利用反射构建一棵菜单生成树

利用java的动态调用类和类属性机制, 编写一个工具类来自动为我们创建一个菜单树, 从而使得我们不用每次遇到树结构都要重复的写一些逻辑, 十分不友好. 

/**
 * 构建树型结构
 *
 * @author Huzz
 * @create 2022-07-25 18:36
 */
public class TreeBuilder<T> {
    private static final String SET_METHOD_PREFIX = "set";
    private static final String GET_METHOD_PREFIX = "get";

    private static final String DEFAULT_ID_NAME = "id";
    private static final String DEFAULT_PARENT_ID_NAME = "parentId";
    private static final String DEFAULT_CHILDREN_NAME = "children";

    /**
     * 构建树结构
     * @param rootId 根节点id
     * @param dataList 所有节点数据, 包含id|父级id|孩子 成员属性.
     * @return
     * @throws Exception
     */
    public static List builder(String rootId, List dataList) throws Exception {
        List tree = new ArrayList<>();
        for (Object data : dataList) {
            String parentId = data.getClass().getMethod(generateGetMethodName(DEFAULT_PARENT_ID_NAME)).invoke(data).toString();

            if (rootId.equals(parentId)) {
                // 是根节点的话, 递归查找以该节点id作为parentId的孩子
                List children = builder(data.getClass().getMethod(generateGetMethodName(DEFAULT_ID_NAME)).invoke(data).toString(), dataList);
                // 设置孩子
                data.getClass().getMethod(generateSetMethodName(DEFAULT_CHILDREN_NAME), List.class).invoke(data, children);
                // 保存当前节点
                tree.add(data);
            }
        }

        return tree;
    }

    /**
     * 构建树结构
     * @param rootId 根节点id
     * @param dataList 所有节点数据, 包含id|父级id|孩子 成员属性.
     * @param IDFiledName id字段名
     * @param parentIdFiledName 父级ID字段名
     * @param childrenFiledName 孩子字段名
     * @return
     * @throws Exception
     */
    public static List builder(String rootId, List dataList,String IDFiledName, String parentIdFiledName, String childrenFiledName) throws Exception {
        TreeBuilder treeBuilder = new TreeBuilder<>();
        return treeBuilder.getTree(rootId, dataList, IDFiledName, parentIdFiledName, childrenFiledName);
    }

    /**
     * 获取树
     * @param rootId 根节点id
     * @param dataList 所有节点数据, 包含id|父级id|孩子 成员属性.
     * @return
     * @throws Exception
     */
    public List<T> getTree(String rootId, List<T> dataList) throws Exception {
        return builder(rootId, dataList);
    }

    /**
     * 获取树
     * @param rootId 根节点id
     * @param dataList 所有节点数据, 包含id|父级id|孩子 成员属性.
     * @param IDFiledName id字段名
     * @param parentIdFiledName 父级ID字段名
     * @param childrenFiledName 孩子字段名
     * @return
     * @throws Exception
     */
    public List<T> getTree(String rootId, List<T> dataList, String IDFiledName, String parentIdFiledName, String childrenFiledName) throws Exception {
        List<T> tree = new ArrayList<>();
        for (T data : dataList) {
            String parentId = data.getClass().getMethod(generateGetMethodName(parentIdFiledName)).invoke(data).toString();

            if (rootId.equals(parentId)) {
                // 是根节点的话, 查找以该节点id作为parentId的孩子
                List<T> children = getTree(data.getClass().getMethod(generateGetMethodName(IDFiledName)).invoke(data).toString(), dataList, IDFiledName, parentIdFiledName, childrenFiledName);
                // 设置孩子
                data.getClass().getMethod(generateSetMethodName(childrenFiledName), List.class).invoke(data, children);
                // 保存当前节点
                tree.add(data);
            }
        }

        return tree;
    }

    private static String generateGetMethodName(String filedName){
        return GET_METHOD_PREFIX +filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
    }

    private static String generateSetMethodName(String filedName){
        return SET_METHOD_PREFIX +filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
    }

}

测试: 

class Test{
    public static void main(String[] args) throws Exception {
        // 创建一个实体类
        @Data
        @AllArgsConstructor
        class Node {
            private String id;
            private String data;
            private String parentId;
            private List<Node> children;

            public Node(String id, String data, String parentId) {
                this.id = id;
                this.data = data;
                this.parentId = parentId;
            }
        }
        // 模拟一份数据库Node表
        List<Node> nodeList = new ArrayList<>();
        nodeList.add(new Node("1", "用户管理", "0"));
        nodeList.add(new Node("2", "角色管理", "0"));
        nodeList.add(new Node("3", "菜单管理", "0"));
        nodeList.add(new Node("4", "工单管理", "0"));
        nodeList.add(new Node("5", "登录管理", "0"));
        nodeList.add(new Node("6", "日志管理", "0"));

        nodeList.add(new Node("7", "用户创建", "1"));
        nodeList.add(new Node("8", "用户角色配置", "1"));
        nodeList.add(new Node("9", "用户禁用", "1"));

        nodeList.add(new Node("10", "角色创建", "2"));
        nodeList.add(new Node("11", "角色删除", "2"));
        nodeList.add(new Node("12", "角色禁用", "2"));

        nodeList.add(new Node("13", "菜单删除", "3"));
        nodeList.add(new Node("14", "菜单编辑", "3"));
        nodeList.add(new Node("15", "菜单禁用", "3"));

        nodeList.add(new Node("16", "创建工单", "4"));
        nodeList.add(new Node("17", "修改工单", "4"));

        nodeList.add(new Node("18", "登录配置", "5"));
        nodeList.add(new Node("19", "登录校验", "5"));

        nodeList.add(new Node("20", "系统日志", "6"));
        nodeList.add(new Node("21", "登录日志", "6"));

        nodeList.add(new Node("22", "普通创建", "7"));
        nodeList.add(new Node("23", "特殊创建", "7"));

        nodeList.add(new Node("24", "配置A", "8"));
        nodeList.add(new Node("25", "配置B", "8"));

        nodeList.add(new Node("26", "常规日志", "20"));
        nodeList.add(new Node("27", "异常日志", "20"));

        // ==== 静态方式调用 ====
        List<Node> tree = TreeBuilder.builder("0", nodeList);
        // 声明字段名称, 如果自己的实体类与默认的字段名称不一样, 从参数中声明一下
        List<Node> tree0 = TreeBuilder.builder("0", nodeList, "id", "parentId", "children");

        // ==== 创建对象方式调用 ====
        TreeBuilder<Node> builder = new TreeBuilder<>();
        List<Node> tree1 = builder.getTree("0", nodeList);
        // 声明字段名称, 如果自己的实体类与默认的字段名称不一样, 从参数中声明一下
        List<Node> tree2 = builder.getTree("0", nodeList, "id", "parentId", "children");


        return;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值