暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

java实现通用树形结构

码农私塾 2021-10-03
2540

微信公众号:码农私塾
关注可获得更多编程知识分享
如果你觉得文章对你有帮助,欢迎赞赏

目录

有啥用怎么做总结

有啥用

作为一个java开发,基本都是开发web项目,对树形结构实在是非常熟悉,菜单 权限树 角色树 部门树等等,实现方式也有两种

  1. 后端提供一个接口 以父节点id 作为参数 每一次查询这个父节点的所有子节点,每点击一次树的节点 就会调用查询接口 获得这个父节点的所有子节点进行渲染 非常适合数据量超大的场景 属于是 延迟懒加载 缺点就是会频繁请求服务器

  2. 后端提供一个接口 直接返回完整的树形结构,每个节点都有子节点属性,前端可以直接根据这个结构进行渲染树形控件 缺点就是不适合数据量超大的场景 优点是 只需要查询一次后端接口 减少了对服务器的请求

怎么做

我这里主要讲 第二种方式 后端直接返回完整的树形结构,首先树形结构肯定会有根节点,也就是没有父节点的节点,一般表现在父节点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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论