ry的侧边路由是后端动态生成的,并不是前端直接写死的,可以对路由进行新增修改,用户登录后会根据其角色权限去渲染路由。
其数据库设计了一张带父子结构的一张表
- 顶级菜单的
parent_id为0 - 每个菜单独有
perms权限字符,登录后通过前面的getInfo接口返回给前端用于资源展示
用户登录后会调用getRouters接口获取菜单路由信息
下面来看看getRouters接口
/**
* 获取路由信息
*
* @return 路由信息
*/
@GetMapping("getRouters")
public AjaxResult getRouters()
{
Long userId = SecurityUtils.getUserId();
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
return AjaxResult.success(menuService.buildMenus(menus));
}
/**
* 根据用户ID查询菜单
*
* @param userId 用户名称
* @return 菜单列表
*/
@Override
public List<SysMenu> selectMenuTreeByUserId(Long userId)
{
List<SysMenu> menus = null;
if (SecurityUtils.isAdmin(userId))
{
menus = menuMapper.selectMenuTreeAll();
}
else
{
menus = menuMapper.selectMenuTreeByUserId(userId);
}
return getChildPerms(menus, 0);
}
selectMenuTreeByUserId方法比较清楚,区分admin和其他用户,根据sys_role_menu关联表查出该用户拥有的所有菜单资源(打平),再调用getChildPerms将其包装成树结构返回。再看一看这个树化方法。
/**
* 根据父节点的ID获取所有子节点
*
* @param list 分类表
* @param parentId 传入的父节点ID
* @return String
*/
public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId)
{
List<SysMenu> returnList = new ArrayList<SysMenu>();
for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();)
{
SysMenu t = (SysMenu) iterator.next();
// 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
if (t.getParentId() == parentId)//处理下一层
{
recursionFn(list, t);
returnList.add(t);
}
}
return returnList;
}
调用recursionFn递归树化子节点
/**
* 递归列表
*
* @param list 分类表
* @param t 子节点
*/
private void recursionFn(List<SysMenu> list, SysMenu t)
{
// 得到子节点列表
List<SysMenu> childList = getChildList(list, t);//通过list.item.parentId == t.id得到
t.setChildren(childList);
for (SysMenu tChild : childList)
{
if (hasChild(list, tChild))//递归出口,调用getChildList.size() > 0得到
{
recursionFn(list, tChild);//递归子节点
}
}
}
总结层级结构思路:
- 获取当前
userId所有目录菜单资源 - 将其中
parent_id= 0的作为各自的根节点 - 查找1中
parent_id= 2中的根节点id,加到2的子节点中去 - 递归3包装子节点,传入的根节id点为当前层id,直到没有子节点为止