背景
我们都知道树形结构,比如菜单,多层的分类等都和树形结构分不开,今天我们要实现的功能是,查询出结构不一定依次关联的,比如:在Oa中我们创建有层级的树形分类,假如有个需求需要根据创建的人来显示相应的层级如图:
正常系统管理员看到是 五个层级拥有所有权限,但是李四登录要求看到的是如图:
张三看到自己的显示如图:
基于这个需求我们分析设计对应方案。
常规设计
假如我们按照常规思路,先按照当前用户id 过滤查询他自己创建的数据,这个时候再去迭代递归组装树形结构,要是他创建的是按照顺序的那可以满足,但是要是出现上面那种情况迭代的时候找不到连续的parentId,没法形成父子节点。
设计方案
由于我们正常设计方案针对断层的树形没法获取parentId,所以在考虑设计的时候加入path 这个字段,他的作用是保存从顶层节点到该节点的路径,比如刚才那个开发语言 他的path 就是职业-互联网-开发语言所对应的id值。这个时候我们可以通过path 一直循环找他上级、上上级……。直到找不到为止。
数据库设计
CREATE TABLE `tb_tree` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`code_num` bigint(20) DEFAULT NULL COMMENT 'code',
`parent_code_num` bigint(20) DEFAULT NULL COMMENT '父节点code',
`code_name` varchar(20) DEFAULT NULL COMMENT 'code 名称',
`path` varchar(1024) DEFAULT NULL COMMENT '树形节点路径',
`create_id` bigint(20) DEFAULT NULL COMMENT '创建者id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='树形分类';
代码具体实现
public static List<TreeEntity> buildTree(List<TreeEntity> nodes) {
List<TreeEntity> tree = Lists.newArrayList();
HashMap<String, TreeEntity> nodeMap = Maps.newHashMap();
String path;
// 将path 存放到临时Map中
for (TreeEntity node : nodes) {
nodeMap.put(node.getPath(), node);
}
for (TreeEntity node : nodes) {
// 顶级节点直接放到list
if (node.getParentCodeNum() == 0L) {
tree.add(node);
} else {
path = node.getPath();
TreeEntity parent = null;
// 一直循环找上级节点,找到结束循环,没有说明path中所有上级都没有,直接放到list
while (path.length() - path.replace("/", "").length() > 1) {
String parentPath = path.substring(0, path.lastIndexOf("/"));
parent = nodeMap.get(parentPath);
if (parent != null) {
break;
}
path = parentPath;
}
if (parent == null) {
tree.add(node);
} else {
//找到后关联到parent 的children 中。
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
parent.getChildren().add(node);
}
}
}
return tree;
}
显示效果
显示张三
[
{
"children":[
{
"children":[
{
"codeName":"Java",
"codeNum":3,
"createId":"1",
"id":3,
"parentCodeNum":4,
"path":"0/1/2/4/3"
}
],
"codeName":"互联网IT",
"codeNum":2,
"createId":"1",
"id":2,
"parentCodeNum":1,
"path":"0/1/2"
}
],
"codeName":"职业",
"codeNum":1,
"createId":"1",
"id":1,
"parentCodeNum":0,
"path":"0/1"
}
]
显示李四
[
{
"children":[
{
"codeName":"spring",
"codeNum":5,
"createId":"2",
"id":5,
"parentCodeNum":4,
"path":"0/1/2/4/3/5"
}
],
"codeName":"开发语言",
"codeNum":4,
"createId":"2",
"id":4,
"parentCodeNum":2,
"path":"0/1/2/4"
}
]