适用于一切对象做树结构的转换工具

51 阅读3分钟


package com.bgy.bpc.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.*;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 格式化树结构工具类
 *
 */
@Slf4j
public class TreeUtil {

    private static final String PARENT_ID = "parentId";
    private static final String ID = "id";
    private static final String CHILDREN = "children";
    private static final String LEVEL_NAME = "treeLevel";

    /**
     * 获取指定节点的下面所有子孙节点
     * @param list       原始列表数据,非树结构
     * @param currNodeId 当前的节点id
     * @param <T>
     * @return
     */
    public static <T> List<T> getAllChild(List<T> list, Object currNodeId) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        List<T> allChildNode = new ArrayList<>();
        // 获取父id,id,子列表字段
        try {
            Class<?> tClass = list.get(0).getClass();
            Field parentIdField = tClass.getDeclaredField(PARENT_ID);
            Field idField = tClass.getDeclaredField(ID);
            idField.setAccessible(true);
            parentIdField.setAccessible(true);
            // 将所有父节点的id数据放到此节点
            MultiValueMap<String, T> parentMap = new LinkedMultiValueMap<>(list.size());
            list.forEach(item -> {
                Object parentIdValue = ReflectionUtils.getField(parentIdField, item);
                if (Objects.isNull(parentIdValue)) {
                    parentIdValue = "0";
                }
                parentMap.add(String.valueOf(parentIdValue), item);
            });
            list.forEach(item -> {
                Object idValue = ReflectionUtils.getField(idField, item);
                if (Objects.equals(idValue, currNodeId)) {
                    // 找到当前匹配到的节点
                    // 获取当前节点下的所有直接节点
                    List<T> allCurrChild = parentMap.get(currNodeId);
                    getAllChild(parentMap, allChildNode, allCurrChild, idField);
                    allChildNode.add(item);
                }
            });
        } catch (Exception e) {
            log.error("获取子节点异常");
        }
        stopWatch.stop();
        log.info("查询所有子孙节点耗时:{}ms", stopWatch.getTotalTimeMillis());
        return allChildNode;
    }

    private static <T> void getAllChild(MultiValueMap<String, T> parentMap, List<T> allChildNode, List<T> allCurrChild, Field idField) {
        if (CollectionUtils.isEmpty(allCurrChild)) {
            return;
        }
        allChildNode.addAll(allCurrChild);
        allCurrChild.forEach(item -> {
            Object idValue = ReflectionUtils.getField(idField, item);
            List<T> allCurrChild2 = parentMap.get(idValue);
            getAllChild(parentMap, allChildNode, allCurrChild2, idField);
        });
    }

    /**
     * 属性结构构建入口处 (父节点id为空 or 0 表示最顶层)
     * 调用此方法,则需遵循以下规则
     * - 父id的字段名称必须为:parentId
     * - id字段名称必须为:id
     * - 子节点集合字段名称必须为:children
     *
     * @param list 目标集合
     * @return List<T>
     */
    public static <T> List<T> parseTree(List<T> list) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        List<T> ts = parseTree(list, PARENT_ID, ID, CHILDREN, null);
        stopWatch.stop();
        log.info("组建树耗时:{}ms", stopWatch.getTotalTimeMillis());
        return ts;
    }

    /**
     * 属性结构构建入口处 (父节点id为空 or 0 表示最顶层)
     * 调用此方法,则需遵循以下规则
     * - 父id的字段名称必须为:parentId
     * - id字段名称必须为:id
     * - 子节点集合字段名称必须为:children
     *
     * @param levelName 层级字段名称 如:levelName ,若为空,则默认使用字段名称 treeLevel
     * @param list      目标集合
     * @return List<T>
     */
    public static <T> List<T> parseTreeHasLevel(List<T> list, String levelName) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        if (StringUtils.isEmpty(levelName)) {
            levelName = LEVEL_NAME;
        }
        List<T> ts = parseTree(list, PARENT_ID, ID, CHILDREN, levelName);
        stopWatch.stop();
        log.info("组建树耗时:{}ms", stopWatch.getTotalTimeMillis());
        return ts;
    }

    /**
     * 属性结构构建入口处 (父节点id为空 or 0 表示最顶层)
     *
     * @param list         目标集合
     * @param parentIdName 父节点id 字段名称 (eg: parentId)
     * @param idName       实体id字段名称  (eg:id)
     * @param childName    实体子节点字段名称  (eg:children)
     * @return List<T>
     */
    public static <T> List<T> parseTree(List<T> list, String parentIdName, String idName, String childName, String levelName) {
        List<T> result = new ArrayList<>();
        if (Objects.isNull(list) || list.isEmpty()) {
            return result;
        }
        try {
            Class<?> tClass = list.get(0).getClass();
            // 获取父id,id,子列表字段
            Field parentIdField = tClass.getDeclaredField(parentIdName);
            Field idField = tClass.getDeclaredField(idName);
            Field childrenField = tClass.getDeclaredField(childName);
            Field levelNameField = StringUtils.isEmpty(levelName) ? null : tClass.getDeclaredField(levelName);
            parentIdField.setAccessible(true);
            idField.setAccessible(true);
            childrenField.setAccessible(true);
            if (levelNameField != null) {
                levelNameField.setAccessible(true);
            }
            MultiValueMap<String, T> parentMap = new LinkedMultiValueMap<>(list.size());
            list.forEach(t -> {
                Object idValue = ReflectionUtils.getField(idField, t);
                if (Objects.isNull(idValue)) {
                    return;
                }
                Object parentIdValue = ReflectionUtils.getField(parentIdField, t);
                if (Objects.isNull(parentIdValue) || StringUtils.isEmpty(parentIdValue.toString()) || Objects.equals("0", parentIdValue.toString())) {
                    // 最顶层的父节点
                    if (levelNameField != null) {
                        ReflectionUtils.setField(levelNameField, t, 1);
                    }
                    result.add(t);
                } else {
                    // 所有的子节点 (二级节点及以下所有节点)
                    parentMap.add(parentIdValue.toString(), t);
                }
            });
            if (levelNameField != null) {
                result.forEach(r -> setChildren(r, parentMap, idField, childrenField, levelNameField));
            } else {
                result.forEach(r -> setChildren(r, parentMap, idField, childrenField));
            }
        } catch (Exception e) {
            log.error("转换Tree报错", e);
            return result;
        }
        return result;
    }

    /**
     * 递归获取子节点
     *
     * @param parent
     * @param parentMap
     * @param idField
     * @param childrenField
     */
    private static <T> void setChildren(T parent, MultiValueMap<String, T> parentMap, Field idField, Field childrenField, Field levelNameField) {
        String idValue = ReflectionUtils.getField(idField, parent).toString();
        int levelValue = Integer.valueOf(ReflectionUtils.getField(levelNameField, parent).toString());
        List<T> ts = parentMap.get(idValue);
        if (Objects.isNull(ts) || ts.isEmpty()) {
            return;
        }
        ReflectionUtils.setField(childrenField, parent, ts);
        for (T t : ts) {
            ReflectionUtils.setField(levelNameField, t, levelValue + 1);
            setChildren(t, parentMap, idField, childrenField, levelNameField);
        }
    }


    /**
     * 递归获取子节点
     *
     * @param parent
     * @param parentMap
     * @param idField
     * @param childrenField
     */
    private static <T> void setChildren(T parent, MultiValueMap<String, T> parentMap, Field idField, Field childrenField) {
        String idValue = ReflectionUtils.getField(idField, parent).toString();
        List<T> ts = parentMap.get(idValue);
        if (Objects.isNull(ts) || ts.isEmpty()) {
            return;
        }
        ReflectionUtils.setField(childrenField, parent, ts);
        ts.forEach(t -> {
            setChildren(t, parentMap, idField, childrenField);
        });
    }
}