首页菜单动态化实现

需求

当不同等级的用户登录系统后,基于用户权限的不同,在首页左侧显示不同的菜单

分析

​ 根据用户的id查询用户的角色,然后基于用户角色查询对应的菜单信息,用户登陆以后,基于用户登陆id查询用户对应的一级菜单,二级菜单然后存储到指定作用域,当进入系统首页后基于thymeleaf呈现用户菜单。

实现

POJO类的定义

​ 基于用户需求将查询到的一级菜单以及一级菜单对应的二级菜单查询出来,并进行封装。

package com.cy.pj.common.pojo;
@Data
public class SysUserMenu implements Serializable {

    private static final long serialVersionUID = 4430852847707200409L;

    private Integer id;
    private String  name;
    private String url;
    private List<SysUserMenu> childs;
}

Dao接口实现

/**
	  *  基于菜单id获取用户菜单信息(这里只查询一级菜单和二级菜单)
	 * @param menuIds
	 * @return
	 */
List<SysUserMenu> findMenusByIds(List<Integer> menuIds);

Mapper元素定义

<resultMap type="com.cy.pj.common.pojo.SysUserMenu" id="sysUserMenu">
    <!-- 一级菜单 -->
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="url" column="url"/>
    <!-- 二级菜单 -->
    <collection property="childs" ofType="com.cy.pj.common.pojo.SysUserMenu">
        <id property="id" column="cid"/>
        <result property="name" column="cname"/>
        <result property="url" column="curl"/>
    </collection>
</resultMap>
<!-- 查询用户拥有访问权限的一级菜单和二级菜单信息 -->
<select id="findMenusByIds" resultMap="sysUserMenu">
    select p.id,p.name,p.url,c.id cid,c.name cname,c.url curl
    from sys_menus p left join sys_menus c
    on c.parentId=p.id
    where p.parentId is null
    and c.id in 
    <foreach collection="menuIds" open="(" close=")" 
             separator="," item="menuId">
        #{menuId}
    </foreach>
</select>

当然也可以采用一次在数据层完成查询(基于用户的id)

<select id="findMenusByIds" resultMap="sysUserMenu">
    select 
    parent.id id,
    parent.name name,
    parent.url url,
    child.id cid,
    child.name cname,
    child.url curl 
    from sys_menus parent
    left join sys_menus child
    on parent.id =child.parentId
    where 
    child.id in (
    (SELECT menu_id from sys_role_menus where role_id in
    (SELECT role_id from sys_user_roles where user_id =#{id})
    )
    ) 
    and parent.parentId is null

</select>

Service接口及实现

在SysMenuService接口中填写以下方法,基于用户的id查询菜单信息

List<SysUserMenu> findUserMenusByUserId(Integer id);

实现类:

@Override
/**
	 * 	基于用户id查询用户的菜单信息
	 */
public List<SysUserMenu> findUserMenusByUserId(Integer id) {
    //参数校验
    if (id==null || id<0) {
        throw new ServiceException("用户不存在");
    }
    //基于用户id查询用户对应的角色的id
    List<Integer> roleIds = sysUserRoleDao.findRoleIdsByUserId(id);

    //基于角色的id获取角色对应的菜单信息,并进行封装
    List<Integer> menuIds = sysRoleMenuDao.findMenuIdsByRoleIds(roleIds);

    //基于菜单id或与用户对应的菜单信息并返回
    return sysMenuDao.findMenusByIds(menuIds);
}

Controller类实现

基于doIndexUI的请求,修改pageController方法

@RequestMapping("doIndexUI")
public String doIndexUI(Model model) {
    SysUser user = ShiroUtils.getUser();
    String username = user.getUsername();		
    List<SysUserMenu>      userMenus=sysMenuService.findUserMenusByUserId(user.getId());
    System.out.println(userMenus);
    model.addAttribute("username", username);
    model.addAttribute("userMenus", userMenus);
    return "starter";
}

Starter页面实现

<ul class="sidebar-menu" data-widget="tree">
    <li class="header">动吧菜单列表</li>
    <li class="treeview"  th:each="m:${userMenus}">

        <a href="#"><i class="fa fa-link"></i> 
            <span>[[${m.name}]]</span>
            <span class="pull-right-container">
                <i class="fa fa-angle-left pull-right"></i>
            </span>
        </a>
        <ul class="treeview-menu">
            <li th:each="c:${m.childs}">
                <a th:onclick="javascript:doLoadRS([[${c.url}]])">[[${c.name}]]</a>
            </li>
        </ul>
    </li>
</ul>

当点击对应的菜单元素时,其事件处理函数如下:

<script type="text/javascript">
    function doLoadRS(url){
    $("#mainContentId").load(url);
}
</script>