获取树结构JAVA代码设计

前言

在日常的开发工作中,我们经常会遇到需要返回树结构的情况,在此记录下一般的处理方式。

树结构特点分析

树结构存在上下级关系,一般子节点会保存父节点的ID(parentId),很多人会采用递归的方式去处理,但通过map,两次循环遍历的办法,可以不用递归即可实现返回树结构。

代码示例

树节点实体:

/**
 * 树节点
 *
 * @author xy
 * @date 2022/12/4
 */
@Data
@Accessors(chain = true)
@ApiModel(value = "树节点", description = "树节点")
public class TreeNode implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "id")
    private Long id;

    @ApiModelProperty(value = "父ID")
    private Long parentId;

    @ApiModelProperty(value = "编码")
    private String code;

    @ApiModelProperty(value = "名称")
    private String name;

    @ApiModelProperty(value = "排序")
    private Integer sort;

    @ApiModelProperty(value = "子节点")
    private List<TreeNode> children = new ArrayList<>();

    public void addChild(TreeNode node){
        children.add(node);
    }
    
}

获取树结构方法:

    public List<TreeNode> getTree() {
        List<TreeNode> treeList = new ArrayList<>();
        List<TreeNode> topNodeList = new ArrayList<>();
        //获取树节点List
        QueryWrapper<SysOrg> queryWrapper = Wrappers.<SysOrg>query().eq("deleted", 0);
        List<SysOrg> orgList = sysOrgMapper.selectList(queryWrapper);
        if (CollUtil.isNotEmpty(orgList)) {
            Map<Long, TreeNode> map = new HashMap<>();
            //第一次循环:构建树节点List,获取根节点List,构建Map
            for (SysOrg org : orgList) {
                TreeNode node = org2TreeNode(org);
                if (node.getParentId() == null || node.getParentId() == 0L) {
                    topNodeList.add(node);
                }
                treeList.add(node);
                map.put(node.getId(), node);
            }
            if (CollUtil.isNotEmpty(treeList) && CollUtil.isNotEmpty(topNodeList) && CollUtil.isNotEmpty(map)) {
                //第二次循环:父节点添加子节点
                for (TreeNode node : treeList) {
                    if(node.getParentId() != null && node.getParentId() != 0L){
                        TreeNode parent = map.get(node.getParentId());
                        if(ObjectUtil.isNotEmpty(parent)){
                            parent.addChild(node);
                        }else{
                            log.warn("机构树存在脏数据,该数据【{}】获取不到父节点",node);
                        }
                    }
                }
            }
        }
        return topNodeList;
    }

实现效果:
获取树结构
注意:
此例中,判断根节点的条件是该节点的父ID为空或0,反之则为子节点,可根据实际业务情况做不同处理。

/** * 根据等级查询类目树 * * @param level * @return */ @Override public List queryCategoryTree(Integer level) { //查询当前级别下类目 List list = categoryDAO.list(level); //组装好的类目树,返回前端 List categoryTree = new ArrayList(); //所有类目 List allDTOList = new ArrayList(); if (CollectionUtils.isEmpty(list)) { return categoryTree; } for (CategoryDO categoryDO : list) { allDTOList.add(new CategoryTreeDTO().convertDOToDTO(categoryDO)); } //当前等级类目 categoryTree = allDTOList.stream().filter(dto -> level.equals(dto.getLevel())).collect(Collectors.toList()); for (CategoryTreeDTO categoryTreeDTO : categoryTree) { //组装类目为树结构 assembleTree(categoryTreeDTO, allDTOList,Constants.CATEGORY_MAX_LEVEL - level); } return categoryTree; } /** * 组装树 * * @param categoryTreeDTO * @param allList * @param remainRecursionCount 剩余递归次数 * @return */ public CategoryTreeDTO assembleTree(CategoryTreeDTO categoryTreeDTO, List allList, int remainRecursionCount) { remainRecursionCount--; //最大递归次数不超过Constants.CATEGORY_MAX_LEVEL-level次,防止坏数据死循环 if(remainRecursionCount < 0){ return categoryTreeDTO; } String categoryCode = categoryTreeDTO.getCategoryCode(); Integer level = categoryTreeDTO.getLevel(); //到达最后等级树返回 if (Constants.CATEGORY_MAX_LEVEL == level) { return categoryTreeDTO; } //子类目 List child = allList.stream().filter(a -> categoryCode.equals(a.getParentCode())).collect(Collectors.toList()); if (null == child) { return categoryTreeDTO; } categoryTreeDTO.setChildren(child); //组装子类目 for (CategoryTreeDTO dto : child) { assembleTree(dto, allList,remainRecursionCount); } return categoryTreeDTO; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值