java构建树形列表(带children属性)- 树形结构工具类
package com.xie.util;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
/**
* @Description java构建树形列表(带children属性)
* 树形表格工具类
* @Date 2022-03-30 15:16
* @Author xie
*/
public class TreeTableUtil {
/**
*
* @param originalList 原始的list数据
* @param idFieldName 唯一标识的字段名称(主键)
* @param pidFieldName 父节点标识的字段名称
* @param childrenFieldName 子节点列表标识的字段名称
* @return java.util.List<T> 树结构列表
*/
public static <T> List<T> list2TreeList(List<T> originalList,
String idFieldName,
String pidFieldName,
String childrenFieldName) {
// 获取根节点,就是找出父节点为空的对象
List<T> rootNodeList = new ArrayList<>();
for (T t : originalList) {
String parentId = null;
try {
parentId = BeanUtils.getProperty(t, parentId);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
if (StringUtils.isBlank(parentId)) {
rootNodeList.add(0, t);
}
}
// 将根节点从原始list移除,减少下次处理数据
originalList.removeAll(rootNodeList);
// 递归封装树
try {
packTree(rootNodeList, originalList, idFieldName, pidFieldName, childrenFieldName);
} catch (Exception e) {
e.printStackTrace();
}
return rootNodeList;
}
/**
* 封装树(向下递归)
*
* @param parentNodeList 要封装为树的父节点对象集合
* @param originalList 原始list数据
* @param idFieldName 作为唯一标示的字段名称
* @param pidFieldName 父节点标识字段名
* @param childrenFieldName 子节点(列表)标识字段名
*/
private static <T> void packTree(List<T> parentNodeList,
List<T> originalList,
String idFieldName,
String pidFieldName,
String childrenFieldName) throws Exception {
for (T parentNode : parentNodeList) {
// 找到当前父节点的子节点列表
List<T> children = packChildren(parentNode, originalList, idFieldName, pidFieldName, childrenFieldName);
if (children.isEmpty()) {
continue;
}
// 将当前父节点的子节点从原始list移除,减少下次处理数据
originalList.removeAll(children);
// 开始下次递归
packTree(children, originalList, idFieldName, pidFieldName, childrenFieldName);
}
}
/**
* 封装子对象
*
* @param parentNode 父节点对象
* @param originalList 原始list数据
* @param keyName 作为唯一标示的字段名称
* @param pidFieldName 父节点标识字段名
* @param childrenFieldName 子节点(列表)标识字段名
*/
private static <T> List<T> packChildren(T parentNode,
List<T> originalList,
String keyName,
String pidFieldName,
String childrenFieldName) throws Exception {
// 找到当前父节点下的子节点列表
List<T> childNodeList = new ArrayList<>();
String parentId = BeanUtils.getProperty(parentNode, keyName);
for (T t : originalList) {
String childNodeParentId = BeanUtils.getProperty(t, pidFieldName);
if (parentId.equals(childNodeParentId)) {
childNodeList.add(t);
}
}
// 将当前父节点下的子节点列表写入到当前父节点下(给子节点列表字段赋值)
if (!childNodeList.isEmpty()) {
FieldUtils.writeDeclaredField(parentNode, childrenFieldName, childNodeList, true);
}
return childNodeList;
}
}
欢迎一起来学习和指导,谢谢关注!
本文来自博客园,作者:xiexie0812,转载请注明原文链接:https://www.cnblogs.com/mask-xiexie/p/16091213.html
分类:
java
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了