大家好,又见面了,我是你们的朋友全栈君。
此版本太累赘,请转到函数版:https://blog.csdn.net/wenxingchen/article/details/115749782?spm=1001.2014.3001.5501
业务场景:菜单树、组织架构树…..前端要求数据结构为树结构,而后端查出来的是一条一条的数据集,每次都要各种递归遍历很麻烦,特此写了一个工具类来解决.
- 三个注解:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author sunziwen
* @since 2021-4-13 16:19:05
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeId {
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author sunziwen
* @since 2021-4-13 16:19:05
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeParentId {
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author sunziwen
* @since 2021-4-13 16:19:05
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeChildren {
}
一个工具类:
import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 树形工具类
*
* @author sunziwen
* @since 2021-4-13 16:19:05
*/
public class TreeUtil {
/**
* 找出顶层节点
*
* @return data
*/
@SneakyThrows
private <T> List<T> treeOut(List<T> list) {
//数据不能为空
if (list == null || list.size() <= 0) {
return list;
}
//获取泛型T的class
Class<?> aClass = list.get(0).getClass();
Field[] declaredFields = aClass.getDeclaredFields();
//获取主键属性
List<Field> idPropertyField = Arrays.stream(declaredFields).filter(x -> {
TreeId annotation = x.getAnnotation(TreeId.class);
return annotation != null;
}).collect(Collectors.toList());
if (idPropertyField.size() <= 0) {
throw new RuntimeException("缺失@TreeId注解");
}
if (idPropertyField.size() > 1) {
throw new RuntimeException("@TreeId注解只能存在一个");
}
//获取父节点属性
List<Field> parentIdPropertyField = Arrays.stream(declaredFields).filter(x -> {
TreeParentId annotation = x.getAnnotation(TreeParentId.class);
return annotation != null;
}).collect(Collectors.toList());
if (parentIdPropertyField.size() <= 0) {
throw new RuntimeException("缺失@ParentId注解");
}
if (parentIdPropertyField.size() > 1) {
throw new RuntimeException("@ParentId注解只能存在一个");
}
/*主键的属性名*/
String idPropertyName = idPropertyField.get(0).getName();
/*主键的get方法*/
Method getId = aClass.getMethod("get" + StrUtil.upperFirst(idPropertyName));
/*父节点的属性名*/
String parentIdPropertyName = parentIdPropertyField.get(0).getName();
/*父节点的get方法*/
Method getParentId = aClass.getMethod("get" + StrUtil.upperFirst(parentIdPropertyName));
/*所有元素的Id*/
List<Object> ids = list.stream().map(x -> {
try {
return getId.invoke(x);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}).collect(Collectors.toList());
/*查出所有顶级节点*/
List<T> topLevel = list.stream().filter(x -> {
try {
return !ids.contains(getParentId.invoke(x));
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return false;
}).collect(Collectors.toList());
return recursion(topLevel, list);
}
/**
* 递归装载
*
* @param superLevel 上级节点
* @param list 数据集
* @return
*/
@SneakyThrows
private <T> List<T> recursion(List<T> superLevel, List<T> list) {
//获取泛型T的class
Class<?> aClass = list.get(0).getClass();
Field[] declaredFields = aClass.getDeclaredFields();
//获取主键属性
List<Field> idPropertyField = Arrays.stream(declaredFields).filter(x -> {
TreeId annotation = x.getAnnotation(TreeId.class);
return annotation != null;
}).collect(Collectors.toList());
if (idPropertyField.size() <= 0) {
throw new RuntimeException("缺失@TreeId注解");
}
if (idPropertyField.size() > 1) {
throw new RuntimeException("@TreeId注解只能存在一个");
}
//获取父节点属性
List<Field> parentIdPropertyField = Arrays.stream(declaredFields).filter(x -> {
TreeParentId annotation = x.getAnnotation(TreeParentId.class);
return annotation != null;
}).collect(Collectors.toList());
if (parentIdPropertyField.size() <= 0) {
throw new RuntimeException("缺失@ParentId注解");
}
if (parentIdPropertyField.size() > 1) {
throw new RuntimeException("@ParentId注解只能存在一个");
}
//获取父节点属性
List<Field> childrenPropertyField = Arrays.stream(declaredFields).filter(x -> {
TreeChildren annotation = x.getAnnotation(TreeChildren.class);
return annotation != null;
}).collect(Collectors.toList());
if (childrenPropertyField.size() <= 0) {
throw new RuntimeException("缺失@TreeChildren注解");
}
if (childrenPropertyField.size() > 1) {
throw new RuntimeException("@TreeChildren注解只能存在一个");
}
/*主键的属性名*/
String idPropertyName = idPropertyField.get(0).getName();
/*主键的get方法*/
Method getId = aClass.getMethod("get" + StrUtil.upperFirst(idPropertyName));
/*父节点的属性名*/
String parentIdPropertyName = parentIdPropertyField.get(0).getName();
/*父节点的get方法*/
Method getParentId = aClass.getMethod("get" + StrUtil.upperFirst(parentIdPropertyName));
/*子节点的属性名*/
String childrenPropertyName = childrenPropertyField.get(0).getName();
/*字节点的set方法*/
Method setChildren = aClass.getMethod("set" + StrUtil.upperFirst(childrenPropertyName));
for (T t : superLevel) {
List<T> children = list.stream().filter(x -> {
try {
return getParentId.invoke(x).equals(getId.invoke(t));
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return false;
}).collect(Collectors.toList());
if (children.size() <= 0) {
continue;
}
List<T> recursion = recursion(children, list);
setChildren.invoke(t, recursion);
}
return superLevel;
}
}
- 使用示例:
-
import lombok.Data; import java.util.List; @Data public class My { @TreeId//在实体类的主键上打上该注解 private String id; @TreeParentId//在实体类的父节点id上打上该注解 private String parentId; private String name; @TreeChildren //在子集上打上该注解 //@TableField(exist = false)//如果你用的是mybatis-plus则需要让框架忽略该字段 private List<My> children; public My(String id, String parentId, String name) { this.id = id; this.parentId = parentId; this.name = name; } }
public static void main(String[] args) { ArrayList<My> mies = new ArrayList<>(); mies.add(new My("1", "-1", "a")); mies.add(new My("2", "-1", "aa")); mies.add(new My("3", "1", "b")); mies.add(new My("4", "1", "c")); mies.add(new My("5", "3", "d")); mies.add(new My("6", "5", "e")); mies.add(new My("7", "6", "f")); mies.add(new My("8", "2", "g")); mies.add(new My("9", "8", "h")); mies.add(new My("10", "9", "i")); List<My> mies1 = TreeUtil.treeOut(mies); System.out.println(mies1); }
大功告成了,如果有问题请加博主V:sunziwen3366
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160344.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...