微信公众号:码农私塾
关注可获得更多编程知识分享
如果你觉得文章对你有帮助,欢迎赞赏
目录
有啥用怎么做总结
有啥用
作为一个java开发,基本都是开发web项目,对树形结构实在是非常熟悉,菜单 权限树 角色树 部门树等等,实现方式也有两种
后端提供一个接口 以父节点id 作为参数 每一次查询这个父节点的所有子节点,每点击一次树的节点 就会调用查询接口 获得这个父节点的所有子节点进行渲染 非常适合数据量超大的场景 属于是 延迟懒加载 缺点就是会频繁请求服务器
后端提供一个接口 直接返回完整的树形结构,每个节点都有子节点属性,前端可以直接根据这个结构进行渲染树形控件 缺点就是不适合数据量超大的场景 优点是 只需要查询一次后端接口 减少了对服务器的请求
怎么做
我这里主要讲 第二种方式 后端直接返回完整的树形结构,首先树形结构肯定会有根节点,也就是没有父节点的节点,一般表现在父节点id 为-1 或者别的特殊值 并且根节点可能会有多个 我们首先区分出 根节点和非根节点 然后遍历根节点集合 递归查找子节点 网上大部分都是这样的思路 而我觉得这里还有优化的空间 有用空间换时间的方法 就是我们可以将非根节点集合 转换为map 以父节点id 为key 将相同的非根节点都分到一组 这样递归查找子节点时 将之前的遍历查找 变成根据key查找 大大提升查找效率 贴出工具类代码
1/**
2 * @Description: 树形结构处理
3 * @Author: Tan
4 * @CreateDate: 2021/10/3
5 **/
6public class TreeUtil<E> {
7
8
9 /**
10 * 创建树形结构
11 * @Author: Tan
12 * @Date: 2021/10/3
13 * @param sourceObjectList: 源对象集合
14 * @param id: id字段属性名
15 * @param name: name 字段属性名
16 * @param parentId: 父id 字段属性名
17 * @param rootNodeValue: 父id字段值==这个值 那么就是根节点
18 * @return: java.util.List<com.TreeUtil<E>.TreeNode>
19 **/
20 public List<TreeNode> createTree(List<E> sourceObjectList,String id,String name,String parentId,String rootNodeValue)throws Exception{
21 //根节点集合
22 List<TreeNode> rootNodeList=new ArrayList<>();
23 //子节点集合
24 List<TreeNode> childNodeList=new ArrayList<>();
25
26 //先区分出 根节点 和非根节点
27 sourceObjectList.stream().forEach(item->{
28 TreeNode node = createTreeNode(item, id, name,parentId);
29 if (rootNodeValue.equals(node.getParentId())) {
30 rootNodeList.add(node);
31 }else{
32 childNodeList.add(node);
33 }
34 });
35
36 //将父id相同的子节点 分为一组 以空间 换时间
37 Map<String, List<TreeNode>> childNodeMap = childNodeList.stream().collect(Collectors.groupingBy(TreeNode::getParentId));
38
39 //遍历根节点 递归添加子节点
40 rootNodeList.forEach(item->addChildNode(item,childNodeMap));
41
42 return rootNodeList;
43 }
44
45 /**
46 * 添加子节点
47 * @Author: Tan
48 * @Date: 2021/10/3
49 * @param node: 父节点
50 * @param childNodeMap: 子节点集合
51 * @return: void
52 **/
53 public void addChildNode(TreeNode node,Map<String, List<TreeNode>> childNodeMap){
54 String key=node.getId();
55 if (childNodeMap.containsKey(key)) {
56 List<TreeNode> childNodeList = childNodeMap.get(key);
57 node.setChildNodeList(childNodeList);
58 //递归 继续查找子节点
59 childNodeList.forEach(item->addChildNode(item,childNodeMap));
60 }
61 }
62
63
64
65 /**
66 * 创建树形节点
67 * @Author: Tan
68 * @Date: 2021/10/3
69 * @param sourceObjec: 源对象
70 * @param id: id字段属性名
71 * @param name: name 字段属性名
72 * @param parentId: 父id 字段属性名
73 * @return: com.TreeUtil<E>.TreeNode
74 **/
75 public TreeNode createTreeNode(E sourceObjec,String id,String name,String parentId){
76 TreeNode node=new TreeNode();
77 node.setSourceObject(sourceObjec);
78 //反射 获取id 和name 值
79 Class<?> clazz = sourceObjec.getClass();
80 try {
81 Field idField = clazz.getDeclaredField(id);
82 Field nameField = clazz.getDeclaredField(name);
83 Field parentIdField = clazz.getDeclaredField(parentId);
84 idField.setAccessible(true);
85 nameField.setAccessible(true);
86 parentIdField.setAccessible(true);
87 String idValue = idField.get(sourceObjec).toString();
88 String nameValue = nameField.get(sourceObjec).toString();
89 String parentIdValue = parentIdField.get(sourceObjec).toString();
90 node.setId(idValue);
91 node.setName(nameValue);
92 node.setParentId(parentIdValue);
93 } catch (Exception e) {
94 throw new RuntimeException("检查字段名是否正确以及字段是否是包装类");
95 }
96 return node;
97 }
98
99
100
101 /**
102 * @Description: 树形结构 节点
103 * @Author: Tan
104 * @Date: 2021/10/3
105 **/
106 public class TreeNode {
107 private String id;
108
109 private String name;
110
111 private String parentId;
112
113 private E sourceObject;
114
115 private List<TreeNode> childNodeList;
116
117 public String getId() {
118 return id;
119 }
120
121 public void setId(String id) {
122 this.id = id;
123 }
124
125 public String getName() {
126 return name;
127 }
128
129 public void setName(String name) {
130 this.name = name;
131 }
132
133 public E getSourceObject() {
134 return sourceObject;
135 }
136
137 public void setSourceObject(E sourceObject) {
138 this.sourceObject = sourceObject;
139 }
140
141 public List<TreeNode> getChildNodeList() {
142 return childNodeList;
143 }
144
145 public void setChildNodeList(List<TreeNode> childNodeList) {
146 this.childNodeList = childNodeList;
147 }
148
149 public String getParentId() {
150 return parentId;
151 }
152
153 public void setParentId(String parentId) {
154 this.parentId = parentId;
155 }
156 }
157}
总结
树形结构的处理经常会碰到以前总是碰到就写一个 没有好好的抽象 封装一个方法 这一次封装好了 不用重复造轮子了 输入转树形结构的集合 id 字段属性名 name 字段属性名 parentId 父id属性名 以及根节点值(是否根节点就体现在特殊的父id值上) 就可以返回一个根节点集合一层一层嵌套了 这个树的所有节点
文章转载自码农私塾,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。






