通过Map映射替代递归形成一个层级树形结构数据

最近项目中遇到了层级树形结构,数据库存放着的是节点id,以及节点的父节点,刚开始是通过递归节点id作为下一层父节点id的形式,用很多条sql来进行查询直接得出的,,但是由于随着层数以及数据的增加,而且同一层级之间涉及到菜单优先级排序的问题,递归的sql及时是组装一起进行批量查询也需要将近 2s 的时间,这对于一个查询来说无疑是很慢的。

因此后面更换了一种思路,通过一次性查询出所有的节点,最后在进行拼装。
首先设置几个集合
parentMap : 以当前所有节点不为null的parentid作为key,相同的parentid作为value加入到List集合里。
nodeMap: 当前所有节点的id作为key和其对应的所有属性作为value,方便遍历
temp: 因为项目需求需要有一个vo类型的转换,如果没有可以利用原先数据库查出来的

 		//parent and nodes map
        Map<Long, List<MenuVo>> parentMap = new HashMap<>();
        //id and node map
        Map<Long, MenuVo> nodeMap = new HashMap<>();
        //temp list
        ArrayList<MenuVo> temp = new ArrayList<>();
        //result list
        List<MenuVo> vos = new ArrayList<>();

设置好后,接下来开始遍历:

 menus.forEach( x -> {
            //set parentMap key
            Long parentId = x.getParentId();
            if(parentId != null && !parentMap.containsKey(parentId)){
                parentMap.put(parentId,new ArrayList());
            }
            nodeMap.put(x.getMenuId(),vo);
        });

注意哦,put(parentId,new ArrayList());这里一定要放入一个new List,设置null的话,后面就不能直接添加元素,会报空指针的,
遍历第二次就把所有节点添加到对应的parentMap value下面
遍历第三次的时候,parentMap已经有了父子对应的集合列表,添加到原先的nodeMap childrens下面
遍历第四次的时候,只需要筛选出nodeMap里没有parentId的节点,因为没有父亲节点很明显他们是根节点。

至于第三步的时候是怎么添加到所有节点的childrens下的时候,是因为java的对象是引用传递,由于map的节点数据在赋予他们childrens值的时候,地址指向并未改变,所以当使用 **setChildrens(v)**加入孩子集合的时候,nodeMap 中的对应的节点的childrens内容也会发生改变。

		QueryWrapper<Menu> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted",0);
        wrapper.orderByAsc("menu_seq");

        //查询全部
        List<Menu> menus = baseMapper.selectList(wrapper);
        //parent and nodes map
        Map<Long, List<MenuVo>> parentMap = new HashMap<>();
        //id and node map
        Map<Long, MenuVo> nodeMap = new HashMap<>();
        //temp list
        ArrayList<MenuVo> temp = new ArrayList<>();
        //result list
        List<MenuVo> vos = new ArrayList<>();

        //遍历一次,提取所有不为空的parent映射到map,映射nodeMap作为所有节点的map,转换vo
        menus.forEach( x -> {
            MenuVo vo = new MenuVo();
            BeanUtils.copyProperties(x,vo);
            //set parentMap key
            Long parentId = x.getParentId();
            if(parentId != null && !parentMap.containsKey(parentId)){
                parentMap.put(parentId,new ArrayList());
            }
            nodeMap.put(x.getMenuId(),vo);
            temp.add(vo);
        });
        //遍历二次,把所有节点添加到对应的parentMap value下面
        temp.forEach( x -> {
            //add children node
            Long parentId = x.getParentId();
            if(parentId != null && parentMap.containsKey(parentId)){
                List<MenuVo> val = parentMap.get(parentId);
                val.add(x);
                parentMap.put(parentId,val);
            }
        });
        //遍历三次,此时,parentMap已经有了父子对应的集合列表,添加到原先的nodeMap childrens下面
        parentMap.forEach((k,v)->{
            //k --> parentId,添加到对应的父亲节点上的childrens中
            MenuVo vo = nodeMap.get(k);
            vo.setChildrens(v);
        });
        //遍历四次生成结果返回
        nodeMap.forEach((k,v) -> {
            if(v.getParentId() == null){
                vos.add(v);
            }
        });
        return vos;

以上就是利用完整的的循环取代递归生成树结构的方法

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值