当前位置:网站首页>利用反射构建一棵菜单生成树
利用反射构建一棵菜单生成树
2022-07-28 13:13:00 【Huzz童年的纸飞机】
利用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;
}
}边栏推荐
- LeetCode 105.从前序与中序遍历序列构造二叉树 && 106.从中序与后序遍历序列构造二叉树
- leetcode(442)数组中重复的数据
- Security assurance is based on software life cycle -istio authorization mechanism
- R语言ggplot2可视化:使用ggpubr包的ggviolin函数可视化小提琴图、设置draw_quantiles参数添加指定分位数横线(例如,50%分位数、中位数)
- ES6 what amazing writing methods have you used
- 基于NoneBot2的qq机器人配置记录
- SLAM论文合集
- Leetcode depth first and breadth first traversal
- 安全保障基于软件全生命周期-Istio的授权机制
- Docker deploys Mysql to realize remote connection [easy to understand]
猜你喜欢

Security assurance is based on software life cycle -istio authentication mechanism

离散对数问题(DLP) && Diffie-Hellman问题(DHP)

算法---不同路径(Kotlin)

LeetCode 105.从前序与中序遍历序列构造二叉树 && 106.从中序与后序遍历序列构造二叉树

83. (cesium home) how the cesium example works

多级缓存方案

Multithreading and high concurrency (III) -- source code analysis AQS principle

在centos中安装mysql5.7.36

MVC模型:日历系统

Read how to deploy highly available k3s with external database
随机推荐
Multi level cache scheme
Rolling update strategy of deployment.
关于栈的理解以及实际应用场景
阿里、京东、抖音:把云推向产业心脏
Socket类关于TCP字符流编程的理解学习
Qt5开发从入门到精通——第一篇概述
线程阻塞的三种情况。
【Utils】ServletUtil
离散对数问题(DLP) && Diffie-Hellman问题(DHP)
R language Visual scatter diagram, geom using ggrep package_ text_ The repl function avoids overlapping labels between data points (add labels to specific areas of the visual image using the parameter
Understanding of "image denoising using an improved generic advantageous network with Wasserstein distance"
软件测试技术之如何编写测试用例
R语言可视化散点图、使用ggrepel包的geom_text_repel函数避免数据点之间的标签互相重叠(使用参数xlim和ylim将标签添加到可视化图像的特定区域、指定标签线段并添加箭头)
leetcode(442)数组中重复的数据
URL related knowledge points
MySQL开发技巧——视图
IP黑白名单
创建线程池的四种方式
Understanding of stack and practical application scenarios
Clickhouse架构与设计