RuoYi-Vue 前后端分离版代码浅析-菜单信息模块

1,565 阅读2分钟

这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

前言

本节介绍RuoYi-Vueruoyi-admin模块中的菜单信息模块SysMenuController 部分的代码, 今天我们讲解一下菜单这里的逻辑,RuoYi-Vue使用的菜单接口比较简单,其中比较有意思的是加载对应角色菜单列表树的接口

对应代码

/**
 * 加载对应角色菜单列表树
 */
@GetMapping(value = "/roleMenuTreeselect/{roleId}")
public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId) {
    List<SysMenu> menus = menuService.selectMenuList(getUserId());
    AjaxResult ajax = AjaxResult.success();
    ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
    ajax.put("menus", menuService.buildMenuTreeSelect(menus));
    return ajax;
}

checkedKeys的获取

这个checkedKeys是用来向前端返回对应角色的所有已经选择的菜单项的Id的数据,为了和前端的树形列表相匹配,可以看到在返回的checkedKeys的数组中并没有对应的parentId的(比如我们返回的Menu是有123的,但是checkedKeys里面并没有对应的父Id)这是因为若依默认选中了父子联动的缘故,如果我们返回了父Id,那么对应的所有的子Id都会被选中,其结果就是会导致本来没有被选中的子菜单也会被选中,这时候如果我们保存,那么对应的权限肯定就有了问题。

image.png

image.png 数据库接口层中我们可以看到这里是有一个参数为menuCheckStrictly,代表菜单树选择项是否关联显示,当然前端传不进来,但是我们可以参考一下。

/**
 * 根据角色ID查询菜单树信息
 * 
 * @param roleId 角色ID
 * @param menuCheckStrictly 菜单树选择项是否关联显示
 * @return 选中菜单列表
 */
public List<Integer> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);

对应的数据库代码为

<select id="selectMenuListByRoleId" resultType="Integer">
   select m.menu_id
   from sys_menu m
           left join sys_role_menu rm on m.menu_id = rm.menu_id
       where rm.role_id = #{roleId}
           <if test="menuCheckStrictly">
             and m.menu_id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.menu_id = rm.menu_id and rm.role_id = #{roleId})
           </if>
   order by m.parent_id, m.order_num
</select>

通过是否传入了menuCheckStrictly参数,我们可以控制是否展示所有的父Id

menus参数的获取

要构建前端所需要下拉树结构,需要我们使用递归来进行父级和子级的整合。

/**
 * 构建前端所需要树结构
 * 
 * @param menus 菜单列表
 * @return 树结构列表
 */
@Override
public List<SysMenu> buildMenuTree(List<SysMenu> menus)
{
    List<SysMenu> returnList = new ArrayList<SysMenu>();
    List<Long> tempList = new ArrayList<Long>();
    for (SysMenu dept : menus)
    {
        tempList.add(dept.getMenuId());
    }
    for (Iterator<SysMenu> iterator = menus.iterator(); iterator.hasNext();)
    {
        SysMenu menu = (SysMenu) iterator.next();
        // 如果是顶级节点, 遍历该父节点的所有子节点
        if (!tempList.contains(menu.getParentId()))
        {
            recursionFn(menus, menu);
            returnList.add(menu);
        }
    }
    if (returnList.isEmpty())
    {
        returnList = menus;
    }
    return returnList;
}

image.png 这里的hasChild判断是否有子节点,总感觉不是很优雅。 在想是否能提个push,哈哈

image.png