这里是我写的一个树形转化工具类,可以满足绝大部分树形转化的要求,因为是递归便利,所以不论树的深度是多少,都是可以转化的。
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @FileNName: TreeCommonUtil
* @Description: 树形结构处理工具类
* @Author: guoxingliang
* @Create: 2019-08-15 15:59
* @Copyright: (c)2018年 ****公司
*/
public class TreeCommonUtil {
private TreeCommonUtil() {}
/**
* <p>Description: [组装实体树]</p>
* Created on: 11:57 2019/4/25
* @author: guoxingliang
* @param nodes 要组装成树的实体List
* @param className 实体全类名
* @param innerClass 若类为静态子类,className则获取有问题,有则传.class形式,否则传null
* @param idName id字段名 类型为基本类型,自动封装类型(如Long、Integer),String
* @param pidName 父id字段名 类型为基本类型,自动封装类型(如Long、Integer),String
* @param childrenListName 子节点存放List的字段名
* @return: java.util.List<T>
*/
public static <T> List<T> buildTree(List<T> nodes, String className, Class innerClass, String idName, String pidName,
String childrenListName) throws InvocationTargetException, NoSuchMethodException, ClassNotFoundException, IllegalAccessException {
List<T> tree = new ArrayList<>();
for (T node : nodes) {
// 遍历
tree = findChildren(node, tree, className, innerClass, idName, pidName, childrenListName);
boolean isChild = isChild(node, tree, className, innerClass, idName, pidName, childrenListName);
if (!isChild) {
// 树上没有父节点,把node挂到树上
tree.add(node);
}
}
return tree;
}
/**
* 根据ID从实体树上获取节点
* @param tree 实体树
* @param id id值
* @param className 实体全类名
* @param idName id字段名 类型为基本类型,自动封装类型(如Long、Integer),String
* @param pidName 父id字段名 类型为基本类型,自动封装类型(如Long、Integer),String
* @param childrenListName 子节点存放List的字段名
* @return 实体节点
* @throws Exception
*/
public static <T> T getNodeById(List<T> tree, Object id, String className, Class innerClass, String idName, String pidName,
String childrenListName) throws Exception {
if (CollectionUtils.isEmpty(tree)) {
return null;
}
for (T node : tree) {
Class<?> classObject = Class.forName(className);
if (!ObjectUtils.isEmpty(innerClass)) {
classObject = innerClass;
}
Method getId = classObject.getMethod("get" + upFirst(idName));
Object nodeId = getId.invoke(node);
//先不处理类型的问题,直接用简单类型、封装类型、String判断
if (nodeId.toString().equals(id.toString())) {
return node;
} else {
Method getChildrenList = classObject.getMethod("get" + upFirst(childrenListName));
List<?> childrenList = (List<?>) getChildrenList.invoke(node);
T object = (T) getNodeById(childrenList, id, className, innerClass, idName, pidName, childrenListName);
if (object != null) {
return object;
}
}
}
return null;
}
/**
* <p>Description: [node是n的父节点]</p>
* Created on: 10:06 2019/4/25
* @author: guoxingliang
* @param: [object, node, className, idName, pidName, childrenListName]
* @return: boolean
*/
private static <T> boolean isParent(T object, T node, String className, Class innerClass, String idName, String pidName)
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
// node是n的父节点
Class<?> classObject = Class.forName(className);
if (!ObjectUtils.isEmpty(innerClass)) {
classObject = innerClass;
}
Method getId = classObject.getMethod("get" + upFirst(idName));
Method getPid = classObject.getMethod("get" + upFirst(pidName));
Object nodeId = getId.invoke(node);
Object nodePid = getPid.invoke(object);
// 根据值的类型比较是否相同
// 先不处理类型的问题,直接用简单类型、封装类型、String判断
if (nodePid != null && nodePid.toString().equals(nodeId.toString())) {
return true;
}
return false;
}
/**
* <p>Description: [校验是否为子孩子]</p>
* Created on: 10:06 2019/4/25
* @author: guoxingliang
* @param: [node, tree, className, idName, pidName, childrenListName]
* @return: boolean
*/
private static <T> boolean isChild(T node, List<T> tree, String className, Class innerClass, String idName, String pidName, String childrenListName)
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Class<?> classObject = Class.forName(className);
if (!ObjectUtils.isEmpty(innerClass)) {
classObject = innerClass;
}
Method getPid = classObject.getMethod("get" + upFirst(pidName));
Object nodePid = getPid.invoke(node);
if (nodePid == null) {
return false;
}
if (CollectionUtils.isEmpty(tree)) {
// 要遍历的list长度为0
return false;
}
for (T n : tree) {
Method getChildrenList = classObject.getMethod("get" + upFirst(childrenListName));
List<T> childrenList = (List<T>) getChildrenList.invoke(n);
if (isParent(node, n, className, innerClass, idName, pidName)) {
// n是否是node的父亲
if (childrenList == null) {
Method setChildrenList = classObject.getMethod("set" + upFirst(childrenListName), List.class);
setChildrenList.invoke(n, new ArrayList<T>());
}
childrenList = (List<T>) getChildrenList.invoke(n);
childrenList.add(node);
return true;
} else {
// 不是,则遍历n的子节点
if (isChild(node, childrenList, className, innerClass, idName, pidName, childrenListName)) {
return true;
}
}
}
return false;
}
/**
* <p>Description: [tree的部分根节点是node的子节点]</p>
* Created on: 10:05 2019/4/25
* @author: guoxingliang
* @param: [node, tree, className, idName, pidName, childrenListName]
* @return: java.util.List<T>
*/
private static <T> List<T> findChildren(T node, List<T> tree, String className, Class innerClass, String idName, String pidName, String childrenListName)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
List<T> newTree = new ArrayList<>();
for (T n : tree) {
if (isParent(n, node, className, innerClass, idName, pidName)) {
Class<?> classObject = Class.forName(className);
if (!ObjectUtils.isEmpty(innerClass)) {
classObject = innerClass;
}
Method getChildrenList = classObject.getMethod("get" + upFirst(childrenListName));
List<T> childrenList = (List<T>) getChildrenList.invoke(node);
if (childrenList == null) {
Method setChildrenList = classObject.getMethod("set" + upFirst(childrenListName), List.class);
setChildrenList.invoke(node, new ArrayList<T>());
}
childrenList = (List<T>) getChildrenList.invoke(node);
childrenList.add(n);
} else {
// 不是孩子
newTree.add(n);
}
}
return newTree;
}
/**
* <p>Description: [获取首字母]</p>
* Created on: 10:05 2019/4/25
* @author: guoxingliang
* @param: [name]
* @return: java.lang.String
*/
private static String upFirst(String name) {
// 首字母大写
name = name.substring(0, 1).toUpperCase() + name.substring(1);
return name;
}
}