非递归快速构建树-注解版

SunHao123 / 2024-09-27 / 原文

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 树注解工具类
 *    父子关系构建树形数据结构
 * @param <T>
 */
public class TreeAnnoUtil<T> {

    private Field[] fields;

    public TreeAnnoUtil(Class<T> clazz) {
        this.fields = clazz.getDeclaredFields();
    }

    /**
     * 构建树
     * @param orginals
     * @return
     */
    public List<T> buildTree(List<T> orginals) {
        List<T> result = null;
        try {
            Map<String, T> dataMap = this.addToMap(orginals);
            result = this.doBuildTree(dataMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 原始数据添加到map集合
     * @param orginals
     * @return
     */
    private Map<String, T> addToMap(List<T> orginals) throws IllegalAccessException {
        // 创建Map,将原数据的 id 作为 key,原数据对象作为 value
        Map<String, T> dataMap = new LinkedHashMap<>();
        for (T t : orginals) {
            for (Field field : fields){
                Tree tree = field.getAnnotation(Tree.class);
                if(tree != null && tree.isId()){
                    field.setAccessible(true);
                    dataMap.put(field.get(t)+"", t);
                    break;
                }
            }
        }
        return dataMap;
    }

    /**
     * 执行构件树操作
     * @param dataMap
     * @return
     * @throws Exception
     */
    private List<T> doBuildTree(Map<String, T> dataMap) throws IllegalAccessException {
        List<T> result = new ArrayList<>();
        for (Map.Entry<String, T> entry : dataMap.entrySet()) {
            T t = entry.getValue();
            String parentId = null;
            for (Field field : fields){
                Tree tree = field.getAnnotation(Tree.class);
                if(tree != null && tree.isParentId()){
                    field.setAccessible(true);
                    Object parentIdObj = field.get(t);
                    if(parentIdObj != null){
                        parentId = field.get(t)+"";
                    }
                    break;
                }
            }
            // 如果是根节点,直接添加到结果集合中
            if (parentId == null || "0".equals(parentId)) {
                result.add(t);
            } else {
                // 如果不是根节点,找到父节点,然后添加到父节点的子节点中
                T parentT = dataMap.get(parentId);
                for (Field field : fields){
                    Tree tree = field.getAnnotation(Tree.class);
                    if(tree != null && tree.isChildren()){
                        field.setAccessible(true);
                        List<T> children = (List<T>) field.get(parentT);
                        children.add(t);
                        break;
                    }
                }
            }
        }
        return result;
    }

    // 行号,初始值为 0
    private static ThreadLocal<Integer> rowNoThreadLocal = ThreadLocal.withInitial(() -> 0);

    /**
     * 打印 树名称,可模拟树结构
     *     使用完 rowNoThreadLocal 记得关闭
     * @param list
     * @param level
     */
    private void printTree(List<OrgVo> list, int level){
        String space = "";
        for (int i = 0; i < level; i++) {
            space = "  " + space;
        }

        //递归一次,层级+1;
        level++;

        for (int i = 0; i < list.size(); i++) {
            OrgVo orgVo = list.get(i);
            String label = orgVo.getLabel();
            List<OrgVo> children = orgVo.getChildren();

            int rowNo = rowNoThreadLocal.get() + 1;// 行号
            rowNoThreadLocal.set(rowNo);
            System.out.println(space + label + "[层级" + (level) + "-行号" + rowNo + "]");

            if(children.size() > 0){
                printTree(children, level);
            }
        }
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        TreeAnnoUtil treeAnnoUtil = new TreeAnnoUtil(OrgVo.class);
        List<OrgVo> orginals = new ArrayList<>();

        OrgVo rootOrgVo = new OrgVo();
        rootOrgVo.setOrgId(-1);
        rootOrgVo.setLabel("name" + 0);
        rootOrgVo.setOrgPid(0);
        rootOrgVo.setOrderNo(0);
        orginals.add(rootOrgVo);

        for (int i = 1; i <= 5; i++) {
            OrgVo orgVo = new OrgVo();
            orgVo.setOrgId(i);
            orgVo.setLabel("name" + i);
            orgVo.setOrgPid(-1);
            orgVo.setOrderNo(i);
            orginals.add(orgVo);
        }
        for (int i = 6; i <= 10; i++) {
            OrgVo orgVo = new OrgVo();
            orgVo.setOrgId(i);
            orgVo.setLabel("name" + i);
            orgVo.setOrgPid(1);
            orgVo.setOrderNo(i);
            orginals.add(orgVo);
        }
        for (int i = 11; i <= 15; i++) {
            OrgVo orgVo = new OrgVo();
            orgVo.setOrgId(i);
            orgVo.setLabel("name" + i);
            orgVo.setOrgPid(6);
            orgVo.setOrderNo(i);
            orginals.add(orgVo);
        }
        for (int i = 16; i <= 20; i++) {
            OrgVo orgVo = new OrgVo();
            orgVo.setOrgId(i);
            orgVo.setLabel("name" + i);
            orgVo.setOrgPid(5);
            orgVo.setOrderNo(i);
            orginals.add(orgVo);
        }
        for (int i = 21; i <= 25; i++) {
            OrgVo orgVo = new OrgVo();
            orgVo.setOrgId(i);
            orgVo.setLabel("name" + i);
            orgVo.setOrgPid(15);
            orgVo.setOrderNo(i);
            orginals.add(orgVo);
        }
        for (int i = 26; i <= 30; i++) {
            OrgVo orgVo = new OrgVo();
            orgVo.setOrgId(i);
            orgVo.setLabel("name" + i);
            orgVo.setOrgPid(23);
            orgVo.setOrderNo(i);
            orginals.add(orgVo);
        }
        System.out.println("数据大小:"+orginals.size());
        List<OrgVo> treeNodes = treeAnnoUtil.buildTree(orginals);
        System.out.println("耗时:"+(System.currentTimeMillis() - start));
        treeAnnoUtil.printTree(treeNodes, 0);

        rowNoThreadLocal.remove();
//        try {
//            ObjectMapper objectMapper = new ObjectMapper();
//            String json = objectMapper.writeValueAsString(treeNodes);
//            System.out.println(json);
//        } catch (JsonProcessingException e) {
//            e.printStackTrace();
//        }
    }

}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Tree {

    // 是否是 id
    boolean isId() default false;

    // 是否是 parentId
    boolean isParentId() default false;

    // 是否是 children
    boolean isChildren() default false;


}
import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class OrgVo {

    @Tree(isId = true)
    private int orgId;

    private String label;

    @Tree(isParentId = true)
    private int orgPid;

    private int orderNo;

    @Tree(isChildren = true)
    private List<OrgVo> children = new ArrayList<>();

}