根据id 和 parentId生成多根列表的树状结构工具类

如题,在研究 ruoyi 框架时发现 ruoyi 生成树状结构的方法需要硬编码具体的类型

,如下所示 

遂用反射改造了该方法(使用构造者模式,使用者仅需一行代码即可将多条数据记录构造为树状结构)

代码如下,main方法为测试方法

package com.ruoyi.common.utils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 该类负责将通用的包含父子关系的对象列表构造为多主根的树状结构输出
 */
public class BuildTreeUtil<T> {


    /**
     * @param args 测试
     */
    public static void main(String[] args) {
        class DataObject {
            @Override
            public String toString() {
                return "{" +
                        "\"id\":" + id +
                        ", \"parentId\":" + parentId +
                        ", \"label\":" + "\""+label +"\""+
                        ", \"children\":" + children +
                        '}';
            }

            public int getId() {
                return id;
            }

            public void setId(int id) {
                this.id = id;
            }

            public int getParentId() {
                return parentId;
            }

            public void setParentId(int parentId) {
                this.parentId = parentId;
            }

            public List<DataObject> getChildren() {
                return children;
            }

            public void setChildren(List<DataObject> children) {
                this.children = children;
            }

            int id;
            int parentId;

            final String label;
            List<DataObject> children;

            public DataObject(int id, int parentId,String label, List<DataObject> children) {
                this.id = id;
                this.parentId = parentId;
                this.label = label;
                this.children = children;
            }
        }
        List<DataObject> test_data = new ArrayList<>();
        test_data.add(new DataObject(1, 0, "类目"+1,new ArrayList<>()));
        test_data.add(new DataObject(2, 0, "类目"+2,new ArrayList<>()));
        test_data.add(new DataObject(3, 1, "类目"+3,new ArrayList<>()));
        test_data.add(new DataObject(4, 1, "类目"+4,new ArrayList<>()));
        test_data.add(new DataObject(5, 2, "类目"+5,new ArrayList<>()));
        test_data.add(new DataObject(6, 2, "类目"+6,new ArrayList<>()));
        test_data.add(new DataObject(7, 3, "类目"+7,new ArrayList<>()));
        test_data.add(new DataObject(8, 3, "类目"+8,new ArrayList<>()));
        test_data.add(new DataObject(9, 4, "类目"+9,new ArrayList<>()));
        test_data.add(new DataObject(10, 4,"类目"+10, new ArrayList<>()));
        test_data.add(new DataObject(11, 5,"类目"+11, new ArrayList<>()));
        test_data.add(new DataObject(12, 5,"类目"+12, new ArrayList<>()));
        test_data.add(new DataObject(13, 6,"类目"+13, new ArrayList<>()));
        test_data.add(new DataObject(14, 6,"类目"+14, new ArrayList<>()));
        test_data.add(new DataObject(15, 3,"类目"+15, new ArrayList<>()));
        test_data.add(new DataObject(16, 3,"类目"+16, new ArrayList<>()));
        test_data.add(new DataObject(17, 4,"类目"+17, new ArrayList<>()));
        test_data.add(new DataObject(18, 4,"类目"+18, new ArrayList<>()));
        test_data.add(new DataObject(19, 5,"类目"+19, new ArrayList<>()));
        test_data.add(new DataObject(20, 5,"类目"+20, new ArrayList<>()));
        test_data.add(new DataObject(21, 6,"类目"+21, new ArrayList<>()));
        test_data.add(new DataObject(22, 6,"类目"+22, new ArrayList<>()));
        test_data.add(new DataObject(23, 7,"类目"+23, new ArrayList<>()));
        test_data.add(new DataObject(24, 8,"类目"+24, new ArrayList<>()));
        test_data.add(new DataObject(25, 9,"类目"+25, new ArrayList<>()));
        test_data.add(new DataObject(26, 10, "类目"+26,new ArrayList<>()));
        test_data.add(new DataObject(27, 11, "类目"+27,new ArrayList<>()));
        test_data.add(new DataObject(28, 12, "类目"+28,new ArrayList<>()));
        test_data.add(new DataObject(29, 0, "类目"+29,new ArrayList<>()));
        test_data.add(new DataObject(30, 0, "类目"+30,new ArrayList<>()));

        try {
            List<DataObject> build = new BuildTreeUtil<DataObject>()
                    .setId("id")
                    .setParentId("parentId")
                    .setChildrenName("children")
                    .setNodeList(test_data)
                    .build();
            System.out.println("build:"+build);

        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 包含父子关系的节点数据(id,parentId)
     */
    List<T> nodeList;

    /**
     * 对象主键(对象 id)
     */
    private String id = "id";

    /**
     * 对象的父id
     */
    private String parentId = "parentId";


    /**
     * 子类字段名 (List<this> children)
     */
    private String childrenName = "children";


    public BuildTreeUtil<T> setNodeList(List<T> nodeList) {
        this.nodeList = nodeList;
        return this;
    }

    public BuildTreeUtil<T> setId(String id) {
        this.id = id;
        return this;
    }

    public BuildTreeUtil<T> setParentId(String parentId) {
        this.parentId = parentId;
        return this;
    }


    public BuildTreeUtil<T> setChildrenName(String childrenName) {
        this.childrenName = childrenName;
        return this;
    }

    /**
     * 构建前端所需要树结构
     *
     * @return 树结构列表
     */
    public List<T> build() throws NoSuchFieldException, IllegalAccessException {
        List<T> returnList = new ArrayList<T>();
        //所有对象的 id 列表
        List<String> idList = nodeList.stream().map(data -> {
            try {
                Field declaredField = data.getClass().getDeclaredField(id);
                declaredField.setAccessible(true);
                return String.valueOf(declaredField.get(data));
            } catch (IllegalAccessException | NoSuchFieldException e) {
                throw new RuntimeException(e);
            }

        }).collect(Collectors.toList());
        for (T node : nodeList) {
            String parentId;
            Field declaredField = node.getClass().getDeclaredField(this.parentId);
            declaredField.setAccessible(true);
            parentId = String.valueOf(declaredField.get(node));

            // 遍历所有部门,如果该部门的父类 id 不在部门列表中,说明这个部门在部门列表中是父部门
            if (parentId != null && !idList.contains(parentId)) {
                //自顶向下递归设置子部门,会直接改变入参node对象
                recursionFn(nodeList, node);
                //将设置好子部门的部门加入待返回列表
                returnList.add(node);
            }
        }
        //如果都是父部门,没有子部门则直接返回原始列表(平行树)
        if (returnList.isEmpty()) {
            returnList = nodeList;
        }
        //最后返回树状列表
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<T> nodeList, T node) throws NoSuchFieldException, IllegalAccessException {
        // 得到子节点列表
        List<T> childList;
        childList = getChildList(nodeList, node);
        Field declaredField = node.getClass().getDeclaredField(childrenName);
        declaredField.setAccessible(true);
        declaredField.set(node, childList);

        for (T tChild : childList) {
            if (hasChild(nodeList, tChild)) {
                recursionFn(nodeList, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<T> getChildList(List<T> nodeList, T node) throws NoSuchFieldException, IllegalAccessException {
        List<T> childList = new ArrayList<T>();
        for (T n : nodeList) {
            Field nParentIdField = n.getClass().getDeclaredField(this.parentId);
            Field nodeIdField = node.getClass().getDeclaredField(this.id);
            nParentIdField.setAccessible(true);
            nodeIdField.setAccessible(true);
            String nParentId = String.valueOf(nParentIdField.get(n));
            String nodeId = String.valueOf(nodeIdField.get(node));
            if (StringUtils.isNotNull(nParentId) && nParentId.equals(nodeId)) //如果列表中有属于顶级节点的子节点则将该节点加入待返回列表中
            {
                childList.add(n);
            }
        }
        return childList;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<T> nodeList, T node) throws NoSuchFieldException, IllegalAccessException {
        return getChildList(nodeList, node).size() > 0;

    }


}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值