清理与ztcloud中重复的代码,改为 jar 包方式引用 ztcloud
This commit is contained in:
29
zt-framework-dsc/pom.xml
Normal file
29
zt-framework-dsc/pom.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>zt-dsc</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>zt-common-dsc</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>zt-framework-dsc</artifactId>
|
||||
<description>
|
||||
该包是技术组件,每个子包,代表一个组件。每个组件包括两部分:
|
||||
1. core 包:是该组件的核心封装
|
||||
2. config 包:是该组件基于 Spring 的配置
|
||||
|
||||
技术组件,也分成两类:
|
||||
1. 框架组件:和我们熟悉的 MyBatis、Redis 等等的拓展
|
||||
2. 业务组件:和业务相关的组件的封装,例如说数据字典、操作日志等等。
|
||||
如果是业务组件,Maven 名字会包含 biz
|
||||
</description>
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
</project>
|
||||
199
zt-framework-dsc/zt-common-dsc/pom.xml
Normal file
199
zt-framework-dsc/zt-common-dsc/pom.xml
Normal file
@@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-framework-dsc</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>zt-common-dsc</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>定义基础 pojo 类、枚举、工具类等等</description>
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-common</artifactId>
|
||||
</dependency>
|
||||
<!-- Spring 核心 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<!-- 用于生成自定义的 Spring @ConfigurationProperties 配置类的说明文件 -->
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-redis</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,主要是 PageParam 使用到 -->
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign-core</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,主要是 api 包使用到 -->
|
||||
</dependency>
|
||||
|
||||
<!-- 监控相关 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<artifactId>apm-toolkit-trace</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-jdk8</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
<scope>provided</scope> <!-- 设置为 provided,主要是 PageParam 使用到 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fhs-opensource</groupId> <!-- VO 数据翻译 -->
|
||||
<artifactId>easy-trans-anno</artifactId> <!-- 默认引入的原因,方便 xxx-module-api 包使用 -->
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk18on</artifactId>
|
||||
<version>1.78.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||
<artifactId>httpclient5</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||
<artifactId>httpclient5</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.14</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpmime</artifactId>
|
||||
<version>4.5.14</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* 基础的通用类,和框架无关
|
||||
*
|
||||
* 例如说,CommonResult 为通用返回
|
||||
*/
|
||||
package com.zt.plat.framework.common;
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.zt.plat.framework.common.util.asyncTask;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* 异步任务同步处理工具类
|
||||
* 多次提交,一次等待
|
||||
*/
|
||||
public class AsyncLatchUtils {
|
||||
private static final ThreadLocal<List<TaskInfo>> THREADLOCAL = ThreadLocal.withInitial(LinkedList::new);
|
||||
|
||||
/**
|
||||
* 提交一个异步任务
|
||||
* @param executor 指定执行此任务的线程池
|
||||
* @param runnable 需要异步执行的具体业务逻辑
|
||||
*/
|
||||
public static void submitTask(Executor executor, Runnable runnable) {
|
||||
THREADLOCAL.get().add(new TaskInfo(executor, runnable));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前线程已提交的任务列表,并自动清理当前线程的已提交任务列表。
|
||||
* @return
|
||||
*/
|
||||
private static List<TaskInfo> popTask() {
|
||||
List<TaskInfo> taskInfos = THREADLOCAL.get();
|
||||
THREADLOCAL.remove();
|
||||
return taskInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发所有已提交任务的执行,并同步等待它们全部完成。
|
||||
* @param timeout 最长等待时间
|
||||
* @param timeUnit 等待时间单位
|
||||
* @return true: 如果所有任务在指定时间内成功完成。false: 如果等待超时。
|
||||
* 该方法在执行后会自动清理当前线程提交的任务列表,因此可以重复使用。
|
||||
*/
|
||||
public static boolean waitFor(long timeout, TimeUnit timeUnit) {
|
||||
List<TaskInfo> taskInfos = popTask();
|
||||
if (taskInfos.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
CountDownLatch latch = new CountDownLatch(taskInfos.size());
|
||||
for (TaskInfo taskInfo : taskInfos) {
|
||||
Executor executor = taskInfo.executor;
|
||||
Runnable runnable = taskInfo.runnable;
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
runnable.run();
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
boolean await = false;
|
||||
try {
|
||||
await = latch.await(timeout, timeUnit);
|
||||
} catch (Exception ignored) {}
|
||||
return await;
|
||||
}
|
||||
|
||||
private static final class TaskInfo {
|
||||
private final Executor executor;
|
||||
private final Runnable runnable;
|
||||
|
||||
public TaskInfo(Executor executor, Runnable runnable) {
|
||||
this.executor = executor;
|
||||
this.runnable = runnable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用样例
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// 1. 准备一个线程池
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(3);
|
||||
|
||||
System.out.println("主流程开始,准备分发异步任务...");
|
||||
|
||||
System.out.println("主线程id:" + Thread.currentThread().getId());
|
||||
// 2. 提交多个异步任务
|
||||
// 任务一:获取用户信息
|
||||
AsyncLatchUtils.submitTask(executorService, () -> {
|
||||
try {
|
||||
System.out.println("任务一子线程id:" + Thread.currentThread().getId());
|
||||
System.out.println("开始获取用户信息...");
|
||||
Thread.sleep(1000); // 模拟耗时
|
||||
System.out.println("获取用户信息成功!");
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
|
||||
// 任务二:获取订单信息
|
||||
AsyncLatchUtils.submitTask(executorService, () -> {
|
||||
try {
|
||||
System.out.println("任务二子线程id:" + Thread.currentThread().getId());
|
||||
System.out.println("开始获取订单信息...");
|
||||
Thread.sleep(1500); // 模拟耗时
|
||||
System.out.println("获取订单信息成功!");
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
|
||||
// 任务三:获取商品信息
|
||||
AsyncLatchUtils.submitTask(executorService, () -> {
|
||||
try {
|
||||
System.out.println("任务三子线程id:" + Thread.currentThread().getId());
|
||||
System.out.println("开始获取商品信息...");
|
||||
Thread.sleep(500); // 模拟耗时
|
||||
System.out.println("获取商品信息成功!");
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println("所有异步任务已提交,主线程开始等待...");
|
||||
|
||||
// 3. 等待所有任务完成,最长等待5秒
|
||||
boolean allTasksCompleted = AsyncLatchUtils.waitFor(5, TimeUnit.SECONDS);
|
||||
|
||||
// 4. 根据等待结果继续主流程
|
||||
if (allTasksCompleted) {
|
||||
System.out.println("所有异步任务执行成功,主流程继续...");
|
||||
} else {
|
||||
System.err.println("有任务执行超时,主流程中断!");
|
||||
}
|
||||
|
||||
// 5. 关闭线程池
|
||||
executorService.shutdown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 对于工具类的选择,优先查找 Hutool 中有没对应的方法
|
||||
* 如果没有,则自己封装对应的工具类,以 Utils 结尾,用于区分
|
||||
*
|
||||
* ps:如果担心 Hutool 存在坑的问题,可以阅读 Hutool 的实现源码,以确保可靠性。并且,可以补充相关的单元测试。
|
||||
*/
|
||||
package com.zt.plat.framework.common.util;
|
||||
@@ -0,0 +1,216 @@
|
||||
package com.zt.plat.framework.common.util.tree;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.zt.plat.framework.common.util.object.ObjectUtils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 树操作方法工具类
|
||||
*/
|
||||
public class TreeUtil {
|
||||
/**
|
||||
* 将list合成树
|
||||
*@param list 需要合成树的List
|
||||
*@param rootCheck 判断E中为根节点的条件,如:x->x.getPId()==-1L,x->x.getParentId()==null,x->x.getParentMenuId()==0
|
||||
*@param parentCheck 判断E中为父节点条件,如:(x,y)->x.getId().equals(y.getPId())
|
||||
*@param setSubChildren E中设置下级数据方法,如:Menu::setSubMenus
|
||||
*@param<E> 泛型实体对象
|
||||
*@return 合成好的树
|
||||
*/
|
||||
public static <E> List<E> makeTree(List<E> list, Predicate<E> rootCheck, BiFunction<E,E,Boolean> parentCheck, BiConsumer<E,List<E>> setSubChildren){
|
||||
return list.stream().filter(rootCheck).peek(x->setSubChildren.accept(x,makeChildren(x,list,parentCheck,setSubChildren))).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
*将树打平成tree
|
||||
*@paramtree需要打平的树
|
||||
*@paramgetSubChildren设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null)
|
||||
*@paramsetSubChildren将下级数据置空方法,如:x->x.setSubMenus(null)
|
||||
*@return打平后的数据
|
||||
*@param<E>泛型实体对象
|
||||
*/
|
||||
public static <E> List<E> flat(List<E> tree, Function<E,List<E>> getSubChildren, Consumer<E> setSubChildren){
|
||||
List<E> res = new ArrayList<>();
|
||||
forPostOrder(tree,item->{
|
||||
setSubChildren.accept(item);
|
||||
res.add(item);
|
||||
},getSubChildren);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*前序遍历
|
||||
*
|
||||
*@paramtree需要遍历的树
|
||||
*@paramconsumer遍历后对单个元素的处理方法,如:x->System.out.println(x)、System.out::println打印元素
|
||||
*@paramsetSubChildren设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null)
|
||||
*@param<E>泛型实体对象
|
||||
*/
|
||||
public static <E> void forPreOrder(List<E> tree,Consumer<E> consumer,Function<E,List<E>> setSubChildren){
|
||||
for(E l : tree){
|
||||
consumer.accept(l);
|
||||
List<E> es = setSubChildren.apply(l);
|
||||
if(es != null && es.size() > 0){
|
||||
forPreOrder(es,consumer,setSubChildren);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*层序遍历
|
||||
*
|
||||
*@paramtree需要遍历的树
|
||||
*@paramconsumer遍历后对单个元素的处理方法,如:x->System.out.println(x)、System.out::println打印元素
|
||||
*@paramsetSubChildren设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null)
|
||||
*@param<E>泛型实体对象
|
||||
*/
|
||||
public static <E> void forLevelOrder(List<E> tree,Consumer<E> consumer,Function<E,List<E>> setSubChildren){
|
||||
Queue<E> queue=new LinkedList<>(tree);
|
||||
while(!queue.isEmpty()){
|
||||
E item = queue.poll();
|
||||
consumer.accept(item);
|
||||
List<E> childList = setSubChildren.apply(item);
|
||||
if(childList !=null && !childList.isEmpty()){
|
||||
queue.addAll(childList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*后序遍历
|
||||
*
|
||||
*@paramtree需要遍历的树
|
||||
*@paramconsumer遍历后对单个元素的处理方法,如:x->System.out.println(x)、System.out::println打印元素
|
||||
*@paramsetSubChildren设置下级数据方法,如:Menu::getSubMenus,x->x.setSubMenus(null)
|
||||
*@param<E>泛型实体对象
|
||||
*/
|
||||
public static <E> void forPostOrder(List<E> tree,Consumer<E> consumer,Function<E,List<E>> setSubChildren){
|
||||
for(E item : tree) {
|
||||
List<E> childList = setSubChildren.apply(item);
|
||||
if(childList != null && !childList.isEmpty()){
|
||||
forPostOrder(childList,consumer,setSubChildren);
|
||||
}
|
||||
consumer.accept(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*对树所有子节点按comparator排序
|
||||
*
|
||||
*@paramtree需要排序的树
|
||||
*@paramcomparator排序规则Comparator,如:Comparator.comparing(MenuVo::getRank)按Rank正序,(x,y)->y.getRank().compareTo(x.getRank()),按Rank倒序
|
||||
*@paramgetChildren获取下级数据方法,如:MenuVo::getSubMenus
|
||||
*@return排序好的树
|
||||
*@param<E>泛型实体对象
|
||||
*/
|
||||
public static <E> List<E> sort(List<E> tree, Comparator<? super E> comparator, Function<E,List<E>> getChildren){
|
||||
for(E item : tree){
|
||||
List<E> childList = getChildren.apply(item);
|
||||
if(childList != null &&! childList.isEmpty()){
|
||||
sort(childList,comparator,getChildren);
|
||||
}
|
||||
}
|
||||
tree.sort(comparator);
|
||||
return tree;
|
||||
}
|
||||
|
||||
private static <E> List<E> makeChildren(E parent,List<E> allData,BiFunction<E,E,Boolean> parentCheck,BiConsumer<E,List<E>> children){
|
||||
return allData.stream().filter(x->parentCheck.apply(parent,x)).peek(x->children.accept(x,makeChildren(x,allData,parentCheck,children))).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用样例
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
MenuVo menu0 = new MenuVo(0L, -1L, "一级菜单", 0);
|
||||
MenuVo menu1 = new MenuVo(1L, 0L, "二级菜单", 1);
|
||||
MenuVo menu2 = new MenuVo(2L, 0L, "三级菜单", 2);
|
||||
MenuVo menu3 = new MenuVo(3L, 1L, "四级菜单", 3);
|
||||
MenuVo menu4 = new MenuVo(4L, 1L, "五级菜单", 4);
|
||||
MenuVo menu5 = new MenuVo(5L, 2L, "六级菜单", 5);
|
||||
MenuVo menu6 = new MenuVo(6L, 2L, "七级菜单", 6);
|
||||
MenuVo menu7 = new MenuVo(7L, 3L, "八级菜单", 7);
|
||||
MenuVo menu8 = new MenuVo(8L, 3L, "九级菜单", 8);
|
||||
MenuVo menu9 = new MenuVo(9L, 4L, "十级菜单", 9);
|
||||
//基本数据
|
||||
List<MenuVo> menuList = Arrays.asList(menu0,menu1, menu2,menu3,menu4,menu5,menu6,menu7,menu8,menu9);
|
||||
//合成树
|
||||
/**
|
||||
* 第1个参数List list,为我们需要合成树的List,如上面Demo中的menuList
|
||||
* 第2个参数Predicate rootCheck,判断为根节点的条件,如上面Demo中pId==-1就是根节点
|
||||
* 第3个参数parentCheck 判断为父节点条件,如上面Demo中 id==pId
|
||||
* 第4个参数setSubChildren,设置下级数据方法如上面Demo中:Menu::setSubMenus
|
||||
*/
|
||||
List<MenuVo> tree= TreeUtil.makeTree(menuList, x->x.getPId()==-1L,(x, y)->x.getId().equals(y.getPId()), MenuVo::setSubMenus);
|
||||
System.out.println(JSON.toJSONString(tree));
|
||||
|
||||
//先序
|
||||
/**
|
||||
* 遍历数参数解释:
|
||||
* tree 需要遍历的树,就是makeTree()合
|
||||
* 成的对象Consumer consumer 遍历后对单个元素的处理方法,如:x-> System.out.println(x)、 postOrder.append(x.getId().toString())
|
||||
* Function<E, List> getSubChildren,获取下级数据方法,如Menu::getSubMenus
|
||||
*/
|
||||
StringBuffer preStr = new StringBuffer();
|
||||
TreeUtil.forPreOrder(tree,x-> preStr.append(x.getId().toString()),MenuVo::getSubMenus);
|
||||
ObjectUtils.equalsAny("0123456789",preStr.toString());
|
||||
|
||||
//层序
|
||||
StringBuffer levelStr=new StringBuffer();
|
||||
TreeUtil.forLevelOrder(tree,x-> levelStr.append(x.getId().toString()),MenuVo::getSubMenus);
|
||||
ObjectUtils.equalsAny("0123456789",levelStr.toString());
|
||||
|
||||
//后序
|
||||
StringBuffer postOrder=new StringBuffer();
|
||||
TreeUtil.forPostOrder(tree,x-> postOrder.append(x.getId().toString()),MenuVo::getSubMenus);
|
||||
ObjectUtils.equalsAny("7839415620",postOrder.toString());
|
||||
|
||||
// 树平铺
|
||||
/**
|
||||
* flat()参数解释:
|
||||
* tree 需要打平的树,就是makeTree()合成的对象Function<E, List> getSubChildren,
|
||||
* 获取下级数据方法,如Menu::getSubMenusConsumer setSubChildren,
|
||||
* 设置下级数据方法,如:x->x.setSubMenus(null)
|
||||
*/
|
||||
List<MenuVo> flat = TreeUtil.flat(tree, MenuVo::getSubMenus,x->x.setSubMenus(null));
|
||||
ObjectUtils.equalsAny(flat.size(),menuList.size());
|
||||
flat.forEach(x -> {
|
||||
if (x.getSubMenus() != null) {
|
||||
throw new RuntimeException("树平铺失败");
|
||||
}
|
||||
});
|
||||
|
||||
// 按rank正序
|
||||
/**
|
||||
* sort参数解释:
|
||||
* tree 需要排序的树,就是makeTree()合成的对象Comparator<? super E> comparator
|
||||
* 排序规则Comparator,如:Comparator.comparing(MenuVo::getRank) 按Rank正序 ,(x,y)->y.getRank().compareTo(x.getRank()),按Rank倒序Function<E, List> getChildren
|
||||
* 获取下级数据方法,如:MenuVo::getSubMenus
|
||||
*/
|
||||
List<MenuVo> sortTree= TreeUtil.sort(tree, Comparator.comparing(MenuVo::getRank), MenuVo::getSubMenus);
|
||||
// 按rank倒序
|
||||
List<MenuVo> sortTreeReverse = TreeUtil.sort(tree, (x,y)->y.getRank().compareTo(x.getRank()), MenuVo::getSubMenus);
|
||||
}
|
||||
@Data
|
||||
static class MenuVo {
|
||||
private Long id; // 主键id
|
||||
private Long pId; // 父级id
|
||||
private String name; // 菜单名称
|
||||
private Integer rank = 0; // 排序
|
||||
private List<MenuVo> subMenus = new ArrayList<>(); // 子菜单
|
||||
public MenuVo(Long id, Long pId, String name, Integer rank) {
|
||||
this.id = id;
|
||||
this.pId = pId;
|
||||
this.name = name;
|
||||
this.rank = rank;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user