什么是扁平化的业务数据,看下面的一张表的数据
上面那张表有如上的数据,我们查询表中的所有数据到一个集合里面这个list集合,这个list集合数据就是扁平化的业务数据
成树 就是我们多个部门下面有不同的子部门,查询的时候希望展现出来的是清晰的部门结构数据,这样就是树类似于下面
我们举个例子,一个大学下面有多个院,多个院下面有多个专业,多个专业下面有多个年级,多个年级下面有多个班,这时候我们想知道这个这个学生属于哪个学校哪个院的哪个专业的哪个班,如果我们正常想查找的话,是不是得建立多个表,学校表,专业表,年级表,班级表,学生表,学生表里面又要包含前面几张的表的字段,那这样搞的话,如果我们进行添加删除等操作,那么操作的数据将会是多个表中的数据,这样非常冗余且麻烦,如果我们想要查询所有的部门数据,那么将会是一个巨大的麻烦的冗余的难受的 一次查询操作
而我们通过把这些数据维护到一张部门表里面,
给每个部门添加对应的父部门的id,和对应的层级总id集合,
然后把平铺的数据转化成 具有大小部门结构层次的数据,这样的转化 就为成树,
这样搞大大减少的表的维护性等操作
在我们的demo中,如果父部门id为0,那么对应的这个部门就是部门树中最大的层级最高的部门
这个接下来我们看代码
对应的部门表实体
package com.example.tabledemo.pojo.entity; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; /** * 部门表 * @TableName dept */ @TableName(value ="dept") @Data public class DeptEntity { /** * 部门ID */ @TableId private Integer id; /** * 部门名称 */ private String deptName; /** * 父部门ID */ private Integer parentId; /** * 祖先列表 */ private String ancestors; /** * */ private String deptType; /** * 部门类型字典id */ private String deptDictId; }
对应的 部门树
package com.example.tabledemo.pojo.entity; import lombok.Data; import java.util.List; /** * @Author: wyz * @Date: 2025-04-05-11:19 * @Description:部门数据扁平化转树实体 */ @Data public class TreeDeptEntity { private Integer id; /** * 部门名称 */ private String deptName; /** * 父部门ID */ private Integer parentId; /** * 祖先列表 */ private String ancestors; /** * 部门类型 */ private String deptType; /** * 部门类型字典id */ private String deptDictId; /** * 树形孩子实体 */ private List<TreeDeptEntity> children ; }
代码如下
package com.example.tabledemo;
import cn.hutool.core.bean.BeanUtil;
import com.example.tabledemo.generator.service.DeptService;
import com.example.tabledemo.pojo.entity.DeptEntity;
import com.example.tabledemo.pojo.entity.TreeDeptEntity;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.*;
import java.util.stream.Collectors;
@SpringBootTest
class TableDemoApplicationTests {
@Autowired
private DeptService deptService;
@Test
void contextLoads() {
// 获取部门列表(扁平化的数据)
List<DeptEntity> deptEntityList = deptService.list();
// 构建树形结构
List<TreeDeptEntity> treeDeptEntities = buildDeptTree(deptEntityList);
// 打印树形结构
printTree(treeDeptEntities, 0);
}
void printTree(List<TreeDeptEntity> treeDeptEntities, int level) {
for (TreeDeptEntity dept : treeDeptEntities) {
// 根据层级缩进
for (int i = 0; i < level; i++) {
System.out.print(" "); // 每层缩进两个空格
}
// 打印当前节点
System.out.println("├─ " + dept.getDeptName() + " (ID: " + dept.getId() + ")");
// 递归打印子节点
if (dept.getChildren() != null && !dept.getChildren().isEmpty()) {
printTree(dept.getChildren(), level + 1);
}
}
}
/**
* 构建部门树形结构
*/
List<TreeDeptEntity> buildDeptTree(List<DeptEntity> deptEntityList) {
// 转换为 TreeDeptEntity 列表
List<TreeDeptEntity> treeDeptEntities = BeanUtil.copyToList(deptEntityList, TreeDeptEntity.class);
//根据每个部门的父亲节点分组,每个父节点下面的集合是对应所有的子部门
Map<Integer, List<TreeDeptEntity>> parentIdToChildrenMap = treeDeptEntities.stream()
.filter(a -> a.getParentId() != null)
.collect(Collectors.groupingBy(TreeDeptEntity::getParentId));
// 找到根节点并递归构建树
List<TreeDeptEntity> rootNodes = new ArrayList<>();
for (TreeDeptEntity treeEntity : treeDeptEntities) {
if (treeEntity.getParentId() == null || treeEntity.getParentId() == 0) {
recursion(parentIdToChildrenMap, treeEntity);
rootNodes.add(treeEntity);
}
}
return rootNodes;
}
/**
* 递归构建树形结构
* 这里递归的作用就是 把分好的map集合 按照 父子部门依次构建 树形结构
*/
void recursion(Map<Integer, List<TreeDeptEntity>> parentIdToChildrenMap, TreeDeptEntity treeEntity) {
List<TreeDeptEntity> childrenList = parentIdToChildrenMap.getOrDefault(treeEntity.getId(), new ArrayList<>());
treeEntity.setChildren(childrenList);
for (TreeDeptEntity child : childrenList) {
recursion(parentIdToChildrenMap, child); // 递归子节点
}
}
}
我们的打印结果如下