java树形工具类

        这里是我写的一个树形转化工具类,可以满足绝大部分树形转化的要求,因为是递归便利,所以不论树的深度是多少,都是可以转化的。


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;
    }
}

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值