若依——递归菜单解释

文章介绍了ruoyi-vue-plus中如何利用Hutool的TreeUtil简化树形菜单的构建,对比了原版的迭代器实现,展示了如何通过增强for循环和Stream流优化代码,包括buildMenuTreeSelect方法和递归函数的实现,以及如何处理菜单路由的组装。
摘要由CSDN通过智能技术生成

原版若依使用到了迭代器进行递归等,由于迭代器比较早了。我几乎没怎么用过。而且uoyi-vue-plus版本当中使用增强for与stream流简化过代码。因此在这里讲plus版本的递归生成树。原理是一样的。

值得注意的是在ruoyi-vue-plus版本当中使用了Hutool当中的TreeUtil来构建树形菜单,十分的简便。

    public List<Tree<Long>> buildMenuTreeSelect(List<SysMenu> menus) {
        if (CollUtil.isEmpty(menus)) {
            return CollUtil.newArrayList();
        }
        return TreeBuildUtils.build(menus, (menu, tree) ->
            tree.setId(menu.getMenuId())
                .setParentId(menu.getParentId())
                .setName(menu.getMenuName())
                .setWeight(menu.getOrderNum()));
    }

原版使用buildMenuTree方法进行一顿操作。。。

    @Override
    public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus)
    {
        List<SysMenu> menuTrees = buildMenuTree(menus);
        return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

不过在路由接口获取菜单时依旧按照原版若依的思路来(这是因为需要将菜单组装为router,使用Hutool当中的TreeUtil返回的为Tree列表类型,不方便。而原版单纯返回menu列表方便router组装),只是简化了以下代码。

主要有以下几个方法

    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list     分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId) {
        List<SysMenu> returnList = new ArrayList<>();
        for (SysMenu t : list) {
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getParentId() == parentId) {
                recursionFn(list, t);
                returnList.add(t);
            }
        }
        return returnList;
    }

    /**
     * 递归列表
     *
     * @param list
     * @param t
     */
    private void recursionFn(List<SysMenu> list, SysMenu t) {
        // 得到子节点列表
        List<SysMenu> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysMenu tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t) {
        return StreamUtils.filter(list, n -> n.getParentId().equals(t.getMenuId()));
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysMenu> list, SysMenu t) {
        return CollUtil.isNotEmpty(getChildList(list, t));
    }

其中第一个方法getChildPerms(),寻找到最顶层(pid=0)的几个菜单,然后将每一个顶层菜单进行递归,看有没有子菜单,最后将这几个递归完成的顶层菜单(此时已经将子菜单递归出来了)add到returnList里面。
在这里插入图片描述
recursionFn()方法比较简单了获取当前菜单的子菜单,存入父亲菜单。然后看看子菜单里面有没有子菜单的子菜单,如果有的化,递归调用recursionFn()方法就行了。递归出口在最后一个子菜单没有自己的子菜单的化,那么其childList的size=0,那么下面的增加for循环就无法进行。自然无法继续调用recursionFn()方法,就会直接运行结束。
在这里插入图片描述

这里还有一种使用stream流更加简化的方案,原理是一样的


    private List<Menu> builderMenuTree(List<Menu> menus, Long parentId) {
        List<Menu> menuTree = menus.stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .map(menu -> menu.setChildren(getChildren(menu, menus)))
                .collect(Collectors.toList());
        return menuTree;
    }

    /**
     * 获取存入参数的 子Menu集合
     * @param menu
     * @param menus
     * @return
     */
    private List<Menu> getChildren(Menu menu, List<Menu> menus) {
        List<Menu> childrenList = menus.stream()
                .filter(m -> m.getParentId().equals(menu.getId()))
                .map(m->m.setChildren(getChildren(m,menus)))
                .collect(Collectors.toList());
        return childrenList;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值