Java树状结构数据构建(基于hutool)

简介: Java树状结构数据构建(基于hutool)

一、应用场景

权限菜单

商品分类

需要返回类似数据结构

{
  "data": [
    {
      "id": 1,
      "parentId": 0,
      "name": "根节点",
      "children": [
        {
          "id": 2,
          "parentId": 1,
          "name": "王二"
        },
        {
          "id": 3,
          "parentId": 1,
          "name": "王1二"
        }
      ]
    },
    {
      "id": 4,
      "parentId": 0,
      "name": "一级目"
    },
    {
      "id": 5,
      "parentId": 0,
      "name": "一级目2",
      "children": [
        {
          "id": 6,
          "parentId": 5,
          "name": "一级目2"
        }
      ]
    }
  ]
}

二、推荐工具

使用hutool工具的树结构工具-TreeUtil

电梯:Hutool参考文档

导入依赖

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.22</version>
</dependency>

三、数据准备

层级数据表一般会涉及三个必填字段:数据->id,父级ID->pid,数据排序->sort;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
 
-- ----------------------------
-- Table structure for system_classification
-- ----------------------------
DROP TABLE IF EXISTS `system_classification`;
CREATE TABLE `system_classification`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类id',
  `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '分类名称',
  `parent_id` bigint(20) NULL DEFAULT 0 COMMENT '父分类id',
  `sort` int(11) NOT NULL DEFAULT 0 COMMENT '显示顺序',
  `level` int(11) NULL DEFAULT NULL COMMENT '层级',
  `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '分类状态(0正常 1停用)',
  `deth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '纵深',
  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间',
  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间',
  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户编号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '部门表' ROW_FORMAT = Dynamic;
 
-- ----------------------------
-- Records of system_classification
-- ----------------------------
INSERT INTO `system_classification` VALUES (1, '根节点', 0, 0, 1, 0, '1', 'admin', '2021-01-05 17:03:47', '1', '2022-03-22 10:18:56', b'0', 1);
INSERT INTO `system_classification` VALUES (2, '王二', 1, 1024, 2, 0, '1', '1', '2022-03-18 11:35:43', '1', '2022-03-22 10:19:00', b'0', 1);
INSERT INTO `system_classification` VALUES (3, '王1二', 1, 1024, 2, 0, '1', '1', '2022-03-18 11:38:05', '1', '2022-03-22 10:19:02', b'0', 1);
INSERT INTO `system_classification` VALUES (4, '一级目', 0, 1, 1, 0, NULL, '1', '2022-03-22 10:09:25', '1', '2022-03-22 10:09:25', b'0', 1);
INSERT INTO `system_classification` VALUES (5, '一级目2', 0, 1, 1, 0, NULL, '1', '2022-03-22 10:09:32', '1', '2022-03-22 10:09:32', b'0', 1);
INSERT INTO `system_classification` VALUES (6, '二级目2', 5, 1, 2, 0, '5', '1', '2022-03-22 10:09:40', '1', '2022-03-22 10:14:17', b'0', 1);
INSERT INTO `system_classification` VALUES (7, 'san级目2', 6, 1, 3, 0, '5,6', '1', '2022-03-22 10:19:28', '1', '2022-03-22 10:19:28', b'0', 1);
 
SET FOREIGN_KEY_CHECKS = 1;

数据对应实体类

public class ClassificationDO {
 
    /**
     * 分级ID
     */
    @TableId
    private Long id;
    /**
     * 分级名称
     */
    private String name;
    /**
     * 父分级ID
     *
     * 关联 {@link #id}
     */
    private Long parentId;
    /**
     * 显示顺序
     */
    private Integer sort;
 
    /**
     * 层级
     */
    private Integer level;
    /**
     * 纵深
     *
     */
    private String deth;
 
    /**
     * 分级状态
     *
     * 枚举 {@link CommonStatusEnum}
     */
    private Integer status;
    /**
     * 多租户编号
     */
    private Long tenantId;
 
}
 
 

四、实现细节

根据pid与id的逻辑关系构建tree;

public CommonResult<List<Tree<Integer>>> listClassificationsChildren() {
        //返回的业务数据
        List<ClassificationDO> list = classificationService.getSimpleClassifications();
        log.info(JSON.toJSONString(list));
        //配置
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义属性名 都要默认值的
         //数据ID
        treeNodeConfig.setIdKey("id");
        // 父级id字段
        treeNodeConfig.setParentIdKey("parentId");
        // 排序字段,这个字段不能是null,不然会报错,默认最好是数字
        treeNodeConfig.setWeightKey("sort");       
        // 最大递归深度
        //treeNodeConfig.setDeep(3);
        //转换器
        List<Tree<Integer>> build = TreeUtil.build(list, 0, treeNodeConfig, ((object, treeNode) -> {
            treeNode.setId(object.getId().intValue());//id
            treeNode.setParentId(object.getParentId().intValue());//父id
            treeNode.putExtra("name", object.getName());
            treeNode.putExtra("sort", object.getSort());
            treeNode.putExtra("level", object.getLevel());
            treeNode.putExtra("status", object.getStatus());
        }));
        log.info(JSON.toJSONString(build));
        return success(build);
    }

查询返回的数据

 [{"createTime":1647574543000,"creator":"1","deleted":false,"deth":"1","id":2,"level":2,"name":"王二","parentId":1,"sort":1024,"status":0,"tenantId":1,"updateTime":1647915540000,"updater":"1"},{"createTime":1647917632000,"creator":"1","deleted":false,"id":8,"level":1,"name":"测试1","parentId":0,"sort":5,"status":0,"tenantId":1,"updateTime":1647917638000,"updater":"1"},{"createTime":1647917993000,"creator":"1","deleted":false,"deth":"1,1","id":10,"level":2,"name":"张三","parentId":1,"sort":2,"status":0,"tenantId":1,"updateTime":1647917993000,"updater":"1"},{"createTime":1647918003000,"creator":"1","deleted":false,"deth":"1,1,10","id":11,"level":3,"name":"张小三","parentId":10,"sort":1,"status":0,"tenantId":1,"updateTime":1647918003000,"updater":"1"},{"createTime":1647917776000,"creator":"1","deleted":false,"id":9,"level":1,"name":"小王","parentId":0,"sort":1,"status":0,"tenantId":1,"updateTime":1647917776000,"updater":"1"},{"createTime":1647915568000,"creator":"1","deleted":false,"deth":"5,6","id":7,"level":3,"name":"san级目2","parentId":6,"sort":1,"status":0,"tenantId":1,"updateTime":1647915568000,"updater":"1"},{"createTime":1647914980000,"creator":"1","deleted":false,"deth":"5","id":6,"level":2,"name":"二级目2","parentId":5,"sort":1,"status":0,"tenantId":1,"updateTime":1647915257000,"updater":"1"},{"createTime":1647914972000,"creator":"1","deleted":false,"id":5,"level":1,"name":"一级目2","parentId":0,"sort":1,"status":0,"tenantId":1,"updateTime":1647914972000,"updater":"1"},{"createTime":1647914965000,"creator":"1","deleted":false,"id":4,"level":1,"name":"一级目","parentId":0,"sort":1,"status":0,"tenantId":1,"updateTime":1647914965000,"updater":"1"},{"createTime":1609837427000,"creator":"admin","deleted":false,"deth":"1","id":1,"level":1,"name":"根节点","parentId":0,"sort":0,"status":0,"tenantId":1,"updateTime":1647915536000,"updater":"1"}]

排序后的数据

 [{"id":1,"parentId":0,"name":"根节点","sort":0,"level":1,"status":0,"children":[{"id":10,"parentId":1,"name":"张三","sort":2,"level":2,"status":0,"children":[{"id":11,"parentId":10,"name":"张小三","sort":1,"level":3,"status":0}]},{"id":2,"parentId":1,"name":"王二","sort":1024,"level":2,"status":0}]},{"id":9,"parentId":0,"name":"小王","sort":1,"level":1,"status":0},{"id":5,"parentId":0,"name":"一级目2","sort":1,"level":1,"status":0,"children":[{"id":6,"parentId":5,"name":"二级目2","sort":1,"level":2,"status":0,"children":[{"id":7,"parentId":6,"name":"san级目2","sort":1,"level":3,"status":0}]}]},{"id":4,"parentId":0,"name":"一级目","sort":1,"level":1,"status":0},{"id":8,"parentId":0,"name":"测试1","sort":5,"level":1,"status":0}]

接口返回的数据

{
  "code": 0,
  "data": [
    {
      "id": 1,
      "parentId": 0,
      "name": "根节点",
      "sort": 0,
      "level": 1,
      "status": 0,
      "children": [
        {
          "id": 10,
          "parentId": 1,
          "name": "张三",
          "sort": 2,
          "level": 2,
          "status": 0,
          "children": [
            {
              "id": 11,
              "parentId": 10,
              "name": "张小三",
              "sort": 1,
              "level": 3,
              "status": 0
            }
          ]
        },
        {
          "id": 2,
          "parentId": 1,
          "name": "王二",
          "sort": 1024,
          "level": 2,
          "status": 0
        }
      ]
    },
    {
      "id": 9,
      "parentId": 0,
      "name": "小王",
      "sort": 1,
      "level": 1,
      "status": 0
    },
    {
      "id": 5,
      "parentId": 0,
      "name": "一级目2",
      "sort": 1,
      "level": 1,
      "status": 0,
      "children": [
        {
          "id": 6,
          "parentId": 5,
          "name": "二级目2",
          "sort": 1,
          "level": 2,
          "status": 0,
          "children": [
            {
              "id": 7,
              "parentId": 6,
              "name": "san级目2",
              "sort": 1,
              "level": 3,
              "status": 0
            }
          ]
        }
      ]
    },
    {
      "id": 4,
      "parentId": 0,
      "name": "一级目",
      "sort": 1,
      "level": 1,
      "status": 0
    },
    {
      "id": 8,
      "parentId": 0,
      "name": "测试1",
      "sort": 5,
      "level": 1,
      "status": 0
    }
  ],
  "msg": ""
}
相关文章
|
10天前
|
Java 程序员 容器
Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
在Java中,变量是一个可以随时改变的数据容器,类似于一个可以反复打开的小盒子。定义变量时需指定数据类型和名称。例如:`int age = 25;` 表示定义一个整数类型的变量 `age`,初始值为25。 常量则是不可改变的数据容器,类似于一个锁死的铁盒子,定义时使用 `final` 关键字。例如:`final int MAX_SPEED = 120;` 表示定义一个名为 `MAX_SPEED` 的常量,值为120,且不能修改。 变量和常量的主要区别在于变量的数据可以随时修改,而常量的数据一旦确定就不能改变。常量主要用于防止意外修改、提高代码可读性和便于维护。
|
1月前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
40 6
|
29天前
|
存储 Java API
深入剖析Java Map:不只是存储数据,更是设计艺术的体现!
【10月更文挑战第17天】在Java编程中,Map是一种重要的数据结构,用于存储键值对,并展现了设计艺术的精髓。本文深入剖析了Map的设计原理和使用技巧,包括基本概念、设计艺术(如哈希表与红黑树的空间时间权衡)、以及使用技巧(如选择合适的实现类、避免空指针异常等),帮助读者更好地理解和应用Map。
89 3
|
19天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
11天前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
27 2
|
11天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
21 2
|
15天前
|
存储 分布式计算 Java
存算分离与计算向数据移动:深度解析与Java实现
【11月更文挑战第10天】随着大数据时代的到来,数据量的激增给传统的数据处理架构带来了巨大的挑战。传统的“存算一体”架构,即计算资源与存储资源紧密耦合,在处理海量数据时逐渐显露出其局限性。为了应对这些挑战,存算分离(Disaggregated Storage and Compute Architecture)和计算向数据移动(Compute Moves to Data)两种架构应运而生,成为大数据处理领域的热门技术。
38 2
|
1月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
32 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
20天前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
43 2
|
21天前
|
SQL Java OLAP
java实现“数据平滑升级”
java实现“数据平滑升级”
39 2
下一篇
无影云桌面