递归

在很多开发场景中会用到递归,比如菜单权限,网站导航栏,下面我给大家一种简单的递归方法

这是业务层实现方法,根据数据库中parentid去区分当前数据的节点,默认根节点是0,这是必要条件,当然你也可以改,不过好像没啥人会把父级节点设成其他参数吧,处理完的数据直接交给递归调用方法

  /**
     * 菜单路由
     *
     * @return
     */
    @Override
    public List<SpaceSysMenu> level() {
        LoginUser loginUser = tokenService.getLoginUser();
        // 查询当前登录用户有什么角色
        Example e = new Example(SpaceSysUserRole.class);
        e.createCriteria().andEqualTo("userId", loginUser.getUserid());
        List<SpaceSysUserRole> sysUserRoles = sysUserRoleMapper.selectByExample(e);
        List<Long> menuId = null;
        for (SpaceSysUserRole userRole : sysUserRoles) {
            // 查看当前角色有什么菜单权限
            Example e1 = new Example(SpaceSysRoleMenu.class);
            e1.createCriteria().andEqualTo("roleId", userRole.getRoleId());
            List<SpaceSysRoleMenu> sysRoleMenus = sysRoleMenuMapper.selectByExample(e1);
            menuId = sysRoleMenus.stream().map(a -> a.getMenuId()).collect(Collectors.toList());
        }
        // 查询当前用户拥有什么菜单权限
        List<SpaceSysMenu> sysMenuList = sysMenuMapper.selectMenu(menuId);
        // 调用递归获取父级下的所有子级节点 默认pid为0是父节点
        List menuTree = buildMenuTree(sysMenuList, 0L);
        return menuTree;
    }

这是调用方法,生成tree,递归的精髓就是自身调用,根据我们的规则生长特定的集合返回给我们

 /**
     * 递归构建菜单树结构
     *
     * @param menuList
     * @param pid
     * @return
     */
    private List<SpaceSysMenu> buildMenuTree(List<SpaceSysMenu> menuList, Long pid) {
        List<SpaceSysMenu> treeList = new ArrayList<>();
        menuList.forEach(menu -> {
            if (org.apache.commons.lang.StringUtils.equals(pid.toString(), menu.getParentId().toString())) {
                menu.setSubMenus(buildMenuTree(menuList, menu.getId()));
                treeList.add(menu);
            }
        });
        return treeList;
    }

这是实体,里面会在私有化一个自身类集合,用来存放递归调用过后的数据节点

@Table
@Entity
@ApiModel(value = "菜单管理")
@Data
@EqualsAndHashCode(callSuper = true)
public class SpaceSysMenu extends Base {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "父菜单ID,一级菜单为0")
    @NotNull(message = "parentId不能为空")
    private Long parentId;

    @ApiModelProperty(value = "菜单名称")
    @NotNull(message = "name不能为空")
    private String name;

    @ApiModelProperty(value = "菜单URL")
    @NotNull(message = "菜单URL不能为空")
    private String url;

    @ApiModelProperty(value = "类型(1:菜单, 2:按钮)")
    @NotNull(message = "type不能为空")
    private Integer type;

    @ApiModelProperty(value = "权限标识")
    private String perms;

    @ApiModelProperty(value = "菜单图标")
    private String icon;

    @ApiModelProperty(value = "菜单级别")
    private Integer level;

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

    @ApiModelProperty(value = "顶级目录菜单id")
    @NotNull(message = "topMenuId不能为空")
    private Long topMenuId;

    @ApiModelProperty(value = "状态:0 禁用;1 启用")
    @NotNull(message = "status不能为空")
    private Integer status;

    @ApiModelProperty(value = "创建时间")
    private Date createTime;

    @ApiModelProperty(value = "修改时间")
    private Date updateTime;

    private List<SpaceSysMenu> subMenus;

}

第二种写法(迭代器循环递归)

   /**
     * 递归构建菜单树结构
     *
     * @param menuList
     * @param pid
     * @return
     */
    private List<SpaceSysMenu> buildMenuTree(List<SpaceSysMenu> menuList, Long pid) {
        List<SpaceSysMenu> returnList = new ArrayList<>();
        for (Iterator<SpaceSysMenu> iterator = menuList.iterator(); iterator.hasNext(); ) {
            SpaceSysMenu t = iterator.next();
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getParentId() == pid) {
                recursionFn(menuList, t);
                returnList.add(t);
            }
        }
        return returnList;
    }

    private void recursionFn(List<SpaceSysMenu> list, SpaceSysMenu t) {
        // 得到子节点列表
        List<SpaceSysMenu> childList = getChildList(list, t);
        t.setSubMenus(childList);
        for (SpaceSysMenu tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }
 /**
     * 得到子节点列表
     */
    private List<SpaceSysMenu> getChildList(List<SpaceSysMenu> list, SpaceSysMenu t) {
        List<SpaceSysMenu> tlist = new ArrayList<>();
        Iterator<SpaceSysMenu> it = list.iterator();
        while (it.hasNext()) {
            SpaceSysMenu n = (SpaceSysMenu) it.next();
            if (n.getParentId().longValue() == t.getId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

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

第三种写法(基于jdk1.8函数式编程)

 public List<SpaceParkMenu> spaceSite() {
        LoginUser loginUser = SessionHelper.getloginUser();
        Long companyId = loginUser.getCompanyId();
        Long tenantId = loginUser.getTenantId();
        Example e = new Example(SpaceParkMenu.class);
        e.createCriteria().andEqualTo("tenantId", tenantId).andEqualTo("companyId", companyId).
                andEqualTo("status", SpaceParkTypeEnum.Status.ENABLE.getValue());
        List<SpaceParkMenu> spaceParkMenus = spaceParkMenuMapper.selectByExample(e);
        // ParentId= 0 的根节点
        List<SpaceParkMenu> nodeList = spaceParkMenus.stream().
                filter(r -> r.getParentId() == 0).
                collect(Collectors.toList());
        // 为 ParentId=0 设置子节点。递归。
        return nodeList.stream().peek(r -> {
            // 给每个根结点 设置 SubMenus
            List<SpaceParkMenu> dataList = collectTreeData(r, spaceParkMenus);
            r.setSubMenus(dataList);
        }).collect(Collectors.toList());

    }

    private List<SpaceParkMenu> collectTreeData(SpaceParkMenu permission, List<SpaceParkMenu> list) {
        return list.stream().
                filter(r -> r.getParentId().equals(permission.getId())).peek(r -> {
            r.setSubMenus(collectTreeData(r, list));
        }).collect(Collectors.toList());

    }

日常使用没问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭优秀的笔记

你的支持就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值