此版本太累赘,请转到函数版: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*/@SneakyThrowsprivate <T> List<T> treeOut(List<T> list) {//数据不能为空if (list == null || list.size() <= 0) {return list;}//获取泛型T的classClass<?> 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*/@SneakyThrowsprivate <T> List<T> recursion(List<T> superLevel, List<T> list) {//获取泛型T的classClass<?> 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

Java集合List转树结构工具类相关推荐

  1. Java集合框架:Collections工具类

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  2. Java集合框架:Arrays工具类

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  3. java 兼容excel_Java解析Excel工具类(兼容xls和xlsx)

    依赖jar org.apache.poi poi-ooxml 4.0.1 ExcelUtils.java package javax.utils; import java.io.File; impor ...

  4. (转)JAVA 十六个常用工具类

    (转)JAVA 十六个常用工具类 一. org.apache.commons.io.IOUtils closeQuietly 关闭一个IO流.socket.或者selector且不抛出异常.通常放在f ...

  5. java inputtools_Java后台开发常用工具类

    本文涉及的工具类部分是自己编写,另一部分是在项目里收集的.工具类涉及数据库连接.格式转换.文件操作.发送邮件等等.提高开发效率,欢迎收藏与转载. 数据库连接工具类 数据库连接工具类--仅仅获得连接对象 ...

  6. java中定义一个CloneUtil 工具类

    其实所有的java对象都可以具备克隆能力,只是因为在基础类Object中被设定成了一个保留方法(protected),要想真正拥有克隆的能力, 就需要实现Cloneable接口,重写clone方法.通 ...

  7. JAVA实现 PDF转换 常用工具类(html转PDF、PDF添加页码、PDF文件下载、PDF添加印章或者水印)

    JAVA实现 PDF转换 常用工具类(html转PDF.PDF添加页码.PDF文件下载.PDF添加印章或者水印)可直接使用 package com.bestvike.util; import com. ...

  8. Java(35):Java Base64编码和解码工具类

    Java Base64编码和解码工具类 Base64Util工具类: package com.ciphergateway.utils; import java.io.UnsupportedEncodi ...

  9. JAVA 文件上传下载工具类

    JAVA 文件上传下载工具类 import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org. ...

最新文章

  1. SpringCloud(二) 生产者、消费者工程搭建与调用(下)
  2. mysql 权限管理无效_mysql 权限控制笔记
  3. tensorflow中optimizer minimize自动训练简介和选择训练variable的方法
  4. Docker一站式配置Nginx【图文教程】
  5. 17. Contoller(2)
  6. spring 之 AOP 理解
  7. Flash竖向大焦点图代码_网页代码站(www.webdm.cn)
  8. Rust : ? 操作符(待续)
  9. 【光剑藏书轩2021】《表象与本质:类比,思考之源和思维之火》
  10. 载波聚合或双连接的方式进行_一文读懂5G基站和4G基站如何协同工作
  11. Typescript配置Jest测试框架
  12. 实习单位评价意见~实习鉴定
  13. jser必看的破解javascript各种加密的反向思维方法 转自脚本之家
  14. windows系统统不支持mysql_Windows系统下MySQL无法启动的万能解决方法
  15. 计算机桌面 文字大小,电脑屏幕字体怎么调大小_电脑系统字体大小设置方法-win7之家...
  16. 最全的肱三头肌训练图解,漂亮手臂必备
  17. 【威联通QNAP】TS-216折腾踩坑记录(更新于22.11.22)
  18. mysql 5.7 winx64_mysql 5.7.17 winx64安装配置方法图文教程
  19. 联合体(union)的使用方法及其本质
  20. 企业微信网络抓包工具devtools_resources

热门文章

  1. 0715Python总结-文件相关操作,扩展模式及相关函数
  2. 为什么计算机的起始时间是1970-1-1?
  3. JVM Run-Time Data Areas 参数相关
  4. 阿里云RDS服务器远程连接失败问题
  5. 命令方块做服务器清理系统,我的世界命令方块 如何在服务器中做签到装置
  6. zabix配置报警机制
  7. 计算机域用户密码过期,PowerShell 检测域用户密码过期时间
  8. 【愚公系列】2022年11月 微信小程序-优购电商项目-意见反馈页面
  9. 【LADRC】线性自抗扰控制
  10. 源码安装的Apache启动时报错:“Could not reliably determine the server‘s fully qualified domain name”