一、应用场景
权限菜单
商品分类
需要返回类似数据结构
{ "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
导入依赖
<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": "" }