Java将List转换为Tree数据

思路

  1. 我们首先要知道数据中,哪两列能够体现父子级
  2. 我们需要找到最顶层父 id 是什么,因为只有知道最顶层的父 id,我们才能进行递归
  3. 我们要在不改变数据的原有结构下,而转换为 Tree 结构,那么就需要创建新的结构

代码

/**
 * Date: 2023/10/28
 * Author: PuKun
 * Description: 树形数据ID
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeId {}
/**
 * Date: 2023/10/28
 * Author: PuKun
 * Description: 树形数据的父类id
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TreeParentId {}
/**
 * Date: 2023/10/28
 * Author: PuKun
 * Description: Tree工具类
 */
public class TreeUtils<T> {
    private Class<T> aClass;

    private Field treeIdField;

    private Field treeParentIdField;

    private final String CHILDREN_KEY = "children";

    public TreeUtils(Class<T> aClass) {
        if (aClass == null) {
            throw new RuntimeException("传入的class为NULL");
        }
        this.aClass = aClass;
        init();
    }

    private void init() {
        Field[] fields = this.aClass.getDeclaredFields();
        for (Field f : fields) {
            if (f.isAnnotationPresent(TreeId.class)) {
                this.treeIdField = f;
            } else if (f.isAnnotationPresent(TreeParentId.class)) {
                this.treeParentIdField = f;
            }
            // 这一步也没什么用,我的想法是如果这两列提前找到,那么就提前结束循环
            if (this.treeIdField != null && this.treeParentIdField != null) {
                break;
            }
        }
        if (this.treeIdField == null || this.treeParentIdField == null) {
            throw new RuntimeException("没有找到相应的注解");
        }
        // 避免因字段为private时,无法访问
        this.treeIdField.setAccessible(true);
        this.treeParentIdField.setAccessible(true);
    }

    public List<HashMap<String, Object>> getTreeData(List<T> data) throws IllegalAccessException {
        Object topParentId = getTopParentId(data);
        return buildTreeData(data, topParentId);
    }

    private Object getTopParentId(List<T> data) throws IllegalAccessException {
        // 获取所有parentId的值
        Map<Object, Integer> parentIdMap = new HashMap<>();
        for (T o : data) {
            Object v = this.treeParentIdField.get(o);
            parentIdMap.put(v, 0);
        }

        // 计算每个parentId的数量
        for (T o : data) {
            Object v = this.treeIdField.get(o);
            if (parentIdMap.containsKey(v)) {
                int keyValue = parentIdMap.get(v);
                parentIdMap.put(v, ++keyValue);
            }
        }

        // 当parentId的数量等于0时,说明当前的parentId没有找到对应的treeId,那么就是最顶层的parentId
        Object topParentId = null;
        Set<Map.Entry<Object, Integer>> entries = parentIdMap.entrySet();
        for (Map.Entry<Object, Integer> e : entries) {
            if (e.getValue() == 0) {
                topParentId = e.getKey();
            }
        }

        return topParentId;
    }

    private List<HashMap<String, Object>> buildTreeData(List<T> data, Object parentId) throws IllegalAccessException {
        List<HashMap<String, Object>> list = new ArrayList<>();
        for (T o : data) {
            Object pid = this.treeParentIdField.get(o);
            Object tid = this.treeIdField.get(o);
            if (pid.equals(parentId)) {
                HashMap<String, Object> map = new HashMap<>();
                Field[] fields = this.aClass.getDeclaredFields();
                for (Field f : fields) {
                    f.setAccessible(true);
                    map.put(f.getName(), f.get(o));
                }
                List<HashMap<String, Object>> children = buildTreeData(data, tid);
                if (children.size() > 0) {
                    map.put(CHILDREN_KEY, children);
                }
                list.add(map);
            }
        }
        return list;
    }
}

/**
 * Date: 2023/11/14
 * Author: PuKun
 * Description: 树形工具类测试
 */
class TreeUtilsTest {

    class Dept {
        @TreeId
        private int id;
        private String deptName;
        @TreeParentId
        private int parentId;

        public Dept(int id, String deptName, int parentId) {
            this.id = id;
            this.deptName = deptName;
            this.parentId = parentId;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getDeptName() {
            return deptName;
        }

        public void setDeptName(String deptName) {
            this.deptName = deptName;
        }

        public int getParentId() {
            return parentId;
        }

        public void setParentId(int parentId) {
            this.parentId = parentId;
        }
    }

    class Dept2 {
        @TreeId
        private String id;
        private String deptName;
        @TreeParentId
        private String parentId;

        public Dept2(String id, String deptName, String parentId) {
            this.id = id;
            this.deptName = deptName;
            this.parentId = parentId;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getDeptName() {
            return deptName;
        }

        public void setDeptName(String deptName) {
            this.deptName = deptName;
        }

        public String getParentId() {
            return parentId;
        }

        public void setParentId(String parentId) {
            this.parentId = parentId;
        }
    }

    @Test
    void getTreeData() {
        // List<Dept> list = new ArrayList<>();
//        list.add(new Dept(1, "闲简居有限公司", 0));
//        list.add(new Dept(2, "开发部", 1));
//        list.add(new Dept(4, "Java组", 2));
//        list.add(new Dept(5, "前端组", 2));
//        list.add(new Dept(3, "测试部", 1));

//        list.add(new Dept(2, "开发部", 1));
//        list.add(new Dept(4, "Java组", 2));
//        list.add(new Dept(5, "前端组", 2));
//        list.add(new Dept(3, "测试部", 1));


//        TreeUtils<Dept> treeUtils = new TreeUtils<>(Dept.class);
//        List<HashMap<String, Object>> mapList = null;
//        try {
//            mapList = treeUtils.getTreeData(list);
//        } catch (IllegalAccessException e) {
//            Assertions.fail(e.getMessage());
//        }

        List<Dept2> list = new ArrayList<>();
        list.add(new Dept2("1", "闲简居有限公司", "0"));
        list.add(new Dept2("2", "开发部", "1"));
        list.add(new Dept2("4", "Java组", "2"));
        list.add(new Dept2("5", "前端组", "2"));
        list.add(new Dept2("3", "测试部", "1"));


        TreeUtils<Dept2> treeUtils = new TreeUtils<>(Dept2.class);
        List<HashMap<String, Object>> mapList = null;
        try {
            mapList = treeUtils.getTreeData(list);
        } catch (IllegalAccessException e) {
            Assertions.fail(e.getMessage());
        }
        Assertions.assertNotEquals(null, mapList);
        System.out.println(mapList);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值