一、序言

在日常一线开发过程中,总有列表转树的需求,几乎是项目的标配,比方说做多级菜单、多级目录、多级分类等,有没有一种通用且跨项目的解决方式呢?帮助广大技术朋友给业务瘦身,提高开发效率。

本文将基于Java8的Lambda 表达式和Stream等知识,使用TreeUtils工具类实现一行代码完成列表转树这一通用型需求。本文有配套视频,传送门直达。

需要说明的是,本TreeUtils工具类已进行三版优化,能够胜任生产场景绝大多数列表转树的。

二、实战编码

1、引入坐标

本坐标地址包含TreeUtils工具类方法,已经发布到Maven中央仓库,建议使用最新的版本号,本文发布时版本是1.5.8.3,若有最新版本,建议使用最新版本。

学习源码的朋友,源码直通车

  1. <dependency>
  2. <groupId>xin.altitude.cms</groupId>
  3. <artifactId>ucode-cms-common</artifactId>
  4. <version>1.5.8.3</version>
  5. </dependency>
2、编写DO

DO是访问数据库实体类,属于前期准备素材。

  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. @TableName(value = "bu_category3")
  5. public class Category {
  6. private static final long serialVersionUID = 1L;
  7. @TableId(type = IdType.AUTO)
  8. private String id;
  9. private String name;
  10. private String parentId;
  11. private String remark;
  12. @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  13. private LocalDateTime createTime;
  14. @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  15. private LocalDateTime updateTime;
  16. public Category(Category category) {
  17. if (Objects.nonNull(category)) {
  18. this.id = category.id;
  19. this.name = category.name;
  20. this.parentId = category.parentId;
  21. this.remark = category.remark;
  22. this.createTime = category.createTime;
  23. this.updateTime = category.updateTime;
  24. }
  25. }
  26. }
3、创建BO

创建BO数据模型用于构造属性结点

  1. @Data
  2. @NoArgsConstructor
  3. public class CategoryBo {
  4. private String id;
  5. private String name;
  6. private String parentId;
  7. private String remark;
  8. /**
  9. * 孩子结点 名字任意取
  10. */
  11. private List<CategoryBo> childList;
  12. /**
  13. * 实现Category 转 CategoryBo
  14. *
  15. * @param category
  16. */
  17. public CategoryBo(Category category) {
  18. if (Objects.nonNull(category)) {
  19. this.id = category.getId();
  20. this.name = category.getName();
  21. this.parentId = category.getParentId();
  22. this.remark = category.getRemark();
  23. }
  24. }
  25. }
3、调用TreeUtils工具类

在服务层调用TreeUtils工具类,一行代码完成转换。

  1. /**
  2. * 获取DO中指定的属性 并构造成树
  3. * @return
  4. */
  5. public List<CategoryBo> selectCategory4() {
  6. List<Category> categoryList = this.list();
  7. List<CategoryBo> categoryBoList = EntityUtils.toList(categoryList, CategoryBo::new);
  8. return TreeUtils.createNodeDetail(categoryBoList, "000000", CategoryBo::getId, CategoryBo::getParentId, CategoryBo::getChildList);
  9. }
4、效果展示

原始列表数据

  1. {
  2. "code": 200,
  3. "msg": "操作成功",
  4. "data": [
  5. {
  6. "id": "310000",
  7. "name": "电子商务",
  8. "parentId": "000000",
  9. "remark": "EEEEE",
  10. "createTime": null,
  11. "updateTime": "2021-11-21 11:22:40"
  12. },
  13. {
  14. "id": "310100",
  15. "name": "大宗商品",
  16. "parentId": "310000",
  17. "remark": "JJJJJ",
  18. "createTime": null,
  19. "updateTime": "2021-11-21 11:22:52"
  20. },
  21. {
  22. "id": "310101",
  23. "name": "大宗商品综合",
  24. "parentId": "310100",
  25. "remark": "IIIII",
  26. "createTime": null,
  27. "updateTime": "2021-11-21 11:22:58"
  28. },
  29. {
  30. "id": "310102",
  31. "name": "钢铁类电商",
  32. "parentId": "310100",
  33. "remark": "OOOOO",
  34. "createTime": null,
  35. "updateTime": "2021-11-21 11:23:02"
  36. },
  37. {
  38. "id": "310200",
  39. "name": "综合电商",
  40. "parentId": "310000",
  41. "remark": "NNNNN",
  42. "createTime": null,
  43. "updateTime": "2021-11-21 11:23:07"
  44. }
  45. ]
  46. }

树状层次数据

  1. {
  2. "code": 200,
  3. "msg": "操作成功",
  4. "data": [
  5. {
  6. "id": "310000",
  7. "name": "电子商务",
  8. "parentId": "000000",
  9. "remark": "EEEEE",
  10. "childList": [
  11. {
  12. "id": "310100",
  13. "name": "大宗商品",
  14. "parentId": "310000",
  15. "remark": "JJJJJ",
  16. "childList": [
  17. {
  18. "id": "310101",
  19. "name": "大宗商品综合",
  20. "parentId": "310100",
  21. "remark": "IIIII",
  22. "childList": []
  23. },
  24. {
  25. "id": "310102",
  26. "name": "钢铁类电商",
  27. "parentId": "310100",
  28. "remark": "OOOOO",
  29. "childList": []
  30. }
  31. ]
  32. },
  33. {
  34. "id": "310200",
  35. "name": "综合电商",
  36. "parentId": "310000",
  37. "remark": "NNNNN",
  38. "childList": []
  39. }
  40. ]
  41. }
  42. ]
  43. }

三、小结

通过一个小小的高频业务场景,抽离业务共性,屏蔽业务细节,实现了通用型业务逻辑的编码。

希望广大技术朋友在完成日常开发工作的前提下,能够进一步打磨代码,感受编程之美。

TreeUtils工具类一行代码实现列表转树【第三版优化】 三级菜单 三级分类 附视频的更多相关文章

  1. 分页 工具类 前后台代码 Java JavaScript (ajax) 实现 讲解

    [博客园cnblogs笔者m-yb原创, 转载请加本文博客链接,笔者github: https://github.com/mayangbo666,公众号aandb7,QQ群927113708]http ...

  2. [课本]JDBC课程6--使用JDBC的DAO模块化--完成数据库的增删查改_工具类JDBCTools四个(Preparedstatement)功能模块的敲定版

    (课本P273-任务九) /**DAO: Data Access Object * 为什么用: 实现功能的模块化,更有利于代码的维护和升级 * 是什么: 访问数据信息的类,包含对数据的CRUD(cre ...

  3. 使用JCrop进行图片裁剪,裁剪js说明,裁剪预览,裁剪上传,裁剪设计的图片处理的工具类和代码

     1.要想制作图片裁剪功能,可以使用网上的裁剪工具JCrop,网址是:https://github.com/tapmodo/Jcrop/ 案例效果如下: 2.引入JCrop的js代码,具体要引入那 ...

  4. html便民查询各个工具类实例代码分享(支持pc和移动端)

    1.手机号码查询 <iframe id="api_iframe_51240" name="api_iframe_51240" src="&quo ...

  5. android开发时间和日期的代码实现工具类(一)

    android开发时间和日期工具类的代码实现: package com.gzcivil.utils; import android.annotation.SuppressLint; import an ...

  6. xml与java代码相互装换的工具类

    这是一个java操作xml文件的工具类,最大的亮点在于能够通过工具类直接生成xml同样层次结构的java代码,也就是说,只要你定义好了xml的模板,就能一键生成java代码.省下了自己再使用工具类写代 ...

  7. Workbook导出excel封装的工具类

    在实际中导出excel非常常见,于是自己封装了一个导出数据到excel的工具类,先附上代码,最后会写出实例和解释.支持03和07两个版本的 excel. HSSF导出的是xls的excel,XSSF导 ...

  8. java(List或Array数组)求交集、并集、差集, 泛型工具类

    业务需要求不同类型的交集.并集.差集为避免代码冗余编写工具类. 注:list 转数组需传入数组,如果将原数组传入将会改变原数组的值,同时泛型数组又不可以实例化,解决方案:Arrays.copyOf(n ...

  9. JDBC工具类连接数据库,模仿登录

    ## 使用JDBC工具类的原因在使用JDBC连接数据库的时候,加载驱动.获取连接.释放资源等代码是重复的,所有为了提高代码的复用性,我们可以写一个工具类,将数据库驱动加载.获取连接.资源释放的代码封装 ...

  10. java树形结构工具类

    一.树形结构数据一般都是以子父id的形式存在数据库中,查询的时候只是带有子id和parent_id的List集合 并不是树形结构,所以我们现在要将普通的List集合转换为树结构数据(本工具类扩展操作树 ...

随机推荐

  1. PostgreSQL 大对象导出报错问题分析

    1.前言 在处理用户问题过程遇到一个问题.用户通过pg_dump导出 bytea 对象时,当行的大小超过 1G时,会报错: [v8r6c5b41@dbhost01 ~]$ sys_dump -t t1 ...

  2. KingbaseFlySync 评估工具的使用

    关键字: KingbaseFlySync.Linux.x86_64.mips64el.aarch64.Java **** 评估工具的使用**** 1.查询评估工具所在服务器的硬件平台(x86_64.m ...

  3. Dart 2.18 正式发布

    互操作性增强.平台特定的网络组件.优化类型推断,以及空安全语言里程碑的近期更新 文/ Michael Thomsen, Google Flutter & Dart 产品经理 Dart 2.18 ...

  4. Golang 随机淘汰算法缓存实现

    缓存如果写满, 它必须淘汰旧值以容纳新值, 最近最少使用淘汰算法 (LRU) 是一个不错的选择, 因为你如果最近使用过某些值, 这些值更可能被保留. 你如果构造一个比缓存限制还长的循环, 当循环最后的 ...

  5. 后端程序员实现一个IP归属地的小程序

    在日常开发中,后端主要提供数据以及处理业务逻辑,前端主要提供页面布局以及数据展示.后端程序员对于页面布局接触比较少,但是小程序有完善的文档说明.页面布局也相对简单,实现起来相对简单一些.而且小程序相对 ...

  6. Openstack Neutron:二层技术和实现

    目录 - 二层的实现 - 1.本地联通与隔离: - Linux bridge实现方式: - local - Flat - VLAN - VXLAN - Open vswitch实现方式 - local ...

  7. std:move() 作用 和 移动语义后 右值行为,unique_ptr的"移动"操作问题

    unique_ptr 不能进行赋值操作,但是可以有返回unique_ptr的函数,由此产生的问题: 结论1:std:move() 只是将一个实参强行转换为右值引用. 我们知道对象初始化时有 构造函数, ...

  8. 8. 使用Fluentd+MongoDB采集Apache日志

    Fluentd+MongoDB,用以实时收集半结构化数据. 背景知识 日志接入Fluentd后,会以json的格式在Fluentd内部进行路由.这就决定了Fluentd处理日志的方式是非常灵活的,它将 ...

  9. Alertmanager集成Dingtalk/Wechat/Email报警

    grafana对报警的支持真的很弱,而Prometheus提供的报警系统就强大很多 Prometheus将数据采集和报警分成了两个模块.报警规则配置在Prometheus Servers上,然后发送报 ...

  10. C/C++ 关于默认构造函数

    前言: 在C++中,对于一个类,C++的编译器都会为这个类提供四个默认函数,分别是: A() //默认构造函数 ~A() //默认析构函数 A(const A&) //默认拷贝构造函数 A&a ...