三种方法构建Java树结构

三种方法构建Java树结构

一、准备工作

表结构

CREATE TABLE `asset_classification` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `className` varchar(50) NOT NULL COMMENT '分类名',
  `status` tinyint(2) NOT NULL COMMENT '状态(0:使用中 1:停用)',
  `type` tinyint(2) NOT NULL COMMENT '类别(0:设备 1:物料 2:附件)',
  `writeable` tinyint(2) NOT NULL COMMENT '1:不可编辑 0:可编辑',
  `parentId` int(11) NOT NULL COMMENT '父类id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=157 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT;

部分表数据

在这里插入图片描述

二、三种方式

  • 原始递归
  • 利用Java 8 Stream流进行处理(原理还是递归)
  • Stream流升级构建

controller层

@RestController
public class TestController {

    @Autowired
    private AssetClassificationBiz assetClassificationBiz;

    @GetMapping("/tree")
    public HttpResponseTemp<?> getTree(){

        List<AssetClassification> assetClassificationList = assetClassificationBiz.selectAll();

        List<TreeUtil.TreeSelect> list = new ArrayList<>();

        for (AssetClassification assetClassification : assetClassificationList) {
            TreeUtil.TreeSelect treeSelect = new TreeUtil.TreeSelect();
            treeSelect.setId(Convert.toLong(assetClassification.getId()));
            treeSelect.setLabel(assetClassification.getClassName());
            treeSelect.setParentId(Convert.toLong(assetClassification.getParentId()));
            list.add(treeSelect);
        }

        //原始递归
        List<TreeUtil.TreeSelect> list1 = TreeUtil.buildTree(list);
        //利用Java 8 Stream流进行处理(原理还是递归)
        List<TreeUtil.TreeSelect> list2 = TreeUtil.buildTreeByStream(list);
        //Stream流升级构建
        List<TreeUtil.TreeSelect> list3 = TreeUtil.buildTreeByAllStream(list);

        return ResultStat.OK.wrap(list3);
    }
}

构建树结构工具类(三种方式)

/**
 * @ClassName TreeUtil
 * @Description 构建树结构工具类
 * @Author hl
 * @Date 2022/9/28 15:13
 * @Version 1.0
 */
public class TreeUtil {


    /**
     * Stream流升级构建
     * @param trees
     * @return
     */
    public static List<TreeSelect> buildTreeByAllStream(List<TreeSelect> trees){
        return trees.stream().filter(m -> m.getParentId() == 0).peek(
                (m) -> m.setChildren(getChildrenList(m, trees))
        ).collect(Collectors.toList());

    }

    /**
     * 获取子节点列表
     * @param tree
     * @param list
     * @return
     */
    public static List<TreeSelect> getChildrenList(TreeSelect tree, List<TreeSelect> list){
        return list.stream().filter(item -> Objects.equals(item.getParentId(), tree.getId())).peek(
                (item) -> item.setChildren(getChildrenList(item, list))
        ).collect(Collectors.toList());
    }



    /**
     * 利用Java 8 Stream流进行处理(原理还是递归)
     * @param trees
     * @return
     */
    public static List<TreeSelect> buildTreeByStream(List<TreeSelect> trees){
        //获取parentId = 0的根节点
        List<TreeSelect> list = trees.stream().filter(item -> item.getParentId() == 0L).collect(Collectors.toList());
        //根据parentId进行分组
        Map<Long, List<TreeSelect>> map = trees.stream().collect(Collectors.groupingBy(TreeSelect::getParentId));
        recursionFnTree(list, map);
        return list;
    }

    /**
     * 递归遍历节点
     * @param list
     * @param map
     */
    public static void recursionFnTree(List<TreeSelect> list, Map<Long, List<TreeSelect>> map){
        for (TreeSelect treeSelect : list) {
            List<TreeSelect> childList = map.get(treeSelect.getId());
            treeSelect.setChildren(childList);
            if (null != childList && 0 < childList.size()){
                recursionFnTree(childList,map);
            }
        }
    }


    /**
     * 构建前端所需要树结构
     *
     * @param trees 列表
     * @return 树结构列表
     */
    public static List<TreeSelect> buildTree(List<TreeSelect> trees) {
        List<TreeSelect> returnList = new ArrayList<>();
        List<Long> tempList = new ArrayList<>();
        for (TreeSelect tree : trees) {
            tempList.add(tree.getId());
        }

        for (TreeSelect treeSelect : trees) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(treeSelect.getParentId())) {
                recursionFn(trees, treeSelect);
                returnList.add(treeSelect);
            }
        }

        if (returnList.isEmpty()) {
            returnList = trees;
        }
        return returnList;
    }
    /**
     * 递归列表
     */
    private static void recursionFn(List<TreeSelect> list, TreeSelect t) {
        // 得到子节点列表
        List<TreeSelect> childList = getChildList(list, t);
        t.setChildren(childList);
        for (TreeSelect tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private static List<TreeSelect> getChildList(List<TreeSelect> list, TreeSelect t) {
        List<TreeSelect> tlist = new ArrayList<>();
        for (TreeSelect n : list) {
            if (ObjectUtil.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private static boolean hasChild(List<TreeSelect> list, TreeSelect t) {
        return getChildList(list, t).size() > 0;
    }



    static class TreeSelect implements Serializable {

        /** 节点ID */
        private Long id;

        /** 节点名称 */
        private String label;

        /** 父ID */
        private Long parentId;

        /** 子节点 */
        private List<TreeSelect> children;

        public Long getId() {
            return id;
        }

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

        public String getLabel() {
            return label;
        }

        public void setLabel(String label) {
            this.label = label;
        }

        public List<TreeSelect> getChildren() {
            return children;
        }

        public void setChildren(List<TreeSelect> children) {
            this.children = children;
        }

        public Long getParentId() {
            return parentId;
        }

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

执行结果

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值