上一小節實現了登錄的實現,本小節實現登錄后根據用戶名查詢當前用戶的角色所關聯的所有權限,然后進行菜單的顯示。登錄成功后,如下圖所示,管理設置是一級菜單,管理員列表,角色管理,權限管理是二級菜單。
先來看一下,AdminUser類,Role類,Permission類
AdminUser類
package com.supin51.domain; import org.apache.ibatis.type.Alias; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; import java.util.List; /** * @Author:ShaoJiang * @description: * @Date: created in 上午10:05 2019/1/21 * @Modified By: */ @Alias("adminUser") public class AdminUser implements Serializable { private Integer id; @NotBlank(message = "用戶名不能為空") @Length(min = 4,max = 12,message = "用戶名格式必須在4-12位字符之間") private String LoginName; @NotBlank(message = "密碼不能為空") @Size(min = 6,max = 12,message = "密碼必須在6-12位任意字符之間") private String password; private Integer state; //用戶角色集合,多對多關系,一個用戶=多個角色,該屬性顯示用戶的角色名稱 private String userRoles; public AdminUser() {super();} public AdminUser(Integer id, String loginName, String password, Integer state) { this.id = id; LoginName = loginName; this.password = password; this.state = state; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLoginName() { return LoginName; } public void setLoginName(String loginName) { LoginName = loginName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getState() { return state; } public void setState(Integer state) { this.state = state; } public String getUserRoles() { return userRoles; } public void setUserRoles(String userRoles) { this.userRoles = userRoles; } }
Role類
package com.supin51.domain; import org.apache.ibatis.type.Alias; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotBlank; import java.io.Serializable; /** * @Author:ShaoJiang * @description: * @Date: created in 下午2:08 2019/1/24 * @Modified By: */ @Alias("role") public class Role implements Serializable { private Integer id; @NotBlank(message = "角色名不能為空") @Length(max = 16,message = "角色名字符數過長") private String roleName; private String roleRemark; public Role() { } public Role(Integer id, String roleName, String roleRemark) { this.id = id; this.roleName = roleName; this.roleRemark = roleRemark; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public String getRoleRemark() { return roleRemark; } public void setRoleRemark(String roleRemark) { this.roleRemark = roleRemark; } }
Permission類:
package com.supin51.domain; import org.apache.ibatis.type.Alias; import java.io.Serializable; import java.util.List; /** * @Author:ShaoJiang * @description: * @Date: created in 上午10:47 2019/1/22 * @Modified By: */ @Alias("permission") public class Permission implements Serializable { private Integer id;//權限編號 private Integer parentId;//父節點編號 private String name;//權限名稱 private String code;//權限代碼 private String url;//權限URL private String icon;//權限圖標樣式 private String category;//權限類別 private String remark;//權限備注 //子權限集合 List<Permission> childPermissions; public Permission() { } public Permission(Integer id, Integer parentId, String name, String code, String url, String icon, String category, String remark) { this.id = id; this.parentId = parentId; this.name = name; this.code = code; this.url = url; this.icon = icon; this.category = category; this.remark = remark; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getParentId() { return parentId; } public void setParentId(Integer parentId) { this.parentId = parentId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public List<Permission> getChildPermissions() { return childPermissions; } public void setChildPermissions(List<Permission> childPermissions) { this.childPermissions = childPermissions; } @Override public String toString() { return "Permission{" + "id=" + id + ", parentId=" + parentId + ", name='" + name + '\'' + ", code='" + code + '\'' + ", url='" + url + '\'' + ", icon='" + icon + '\'' + ", category='" + category + '\'' + ", remark='" + remark + '\'' + ", childPermissions=" + childPermissions + '}'; } }
數據庫t_permission表的結構
t_role表
t_admin表:password儲存的全是加密過的密碼
t_amdin_role表:用戶和角色的關系表(中間表)
t_role_permission表:角色和權限的關系表(中間表)
可以看到,用戶admin有2個角色:管理員和aaa,管理員擁有所有權限,aaa也擁有了所有權限
登錄成功后跳轉到主頁后
AdminController中的代碼
/** * 加載主頁 * @return */ @RequestMapping("/main") public String main(HttpSession session,Model model) { if(session.getAttribute("adminUser")!=null){ logger.info("adminUser:"+session.getAttribute("adminUser").toString()); AdminUser adminUser = (AdminUser)session.getAttribute("adminUser"); //查找登錄用戶角色下的所有權限 List<Permission> allPermissionsList = adminUserService.findAdminUserRolePermissionList(adminUser.getLoginName().toString());
//如果沒有權限,直接返回主頁 if(allPermissionsList.size()<=0) { return "main"; } //遍歷所有節點,先查找出根節點集合 List<Permission> permissionList = new ArrayList<Permission>(); for(Permission p:allPermissionsList){ //parentId為0的代表根節點 if(p.getParentId().toString().equals("0") ||p.getParentId()==0){ permissionList.add(p); } } //外層循環根節點集合 for(Permission p:permissionList){ //聲明一個集合用於裝載子節點 List<Permission> childPermissions = new ArrayList<Permission>(); //內層遍歷所有權限列表 for(Permission p2:allPermissionsList){ //如果節點的parentId等於根節點父節點的ID if(p.getId().equals(p2.getParentId())){ //添加節點到子節點集合 childPermissions.add(p2); } } //設置根節點下的子節點集合 p.setChildPermissions(childPermissions); } logger.info(Arrays.asList(permissionList).toString()); //加載到requestScope內,在頁面進行獲取 model.addAttribute("permissionList",permissionList); } return "main"; }
當用戶擁有兩個角色,角色中擁有相同的權限時,怎么獲取和顯示呢?
這里主要講解一下,獲取用戶所有角色下的所有權限的持久層方法
AdminUserMapper.xml ----對應AdminUserDao接口類
<!--查找登錄用戶下所有角色權限信息--> <select id="findAdminUserRolePermissionList" parameterType="string" resultType="com.supin51.domain.Permission"> SELECT DISTINCT tp.* FROM t_admin ta LEFT JOIN t_admin_role tar ON tar.adminId = ta.id LEFT JOIN t_role tr ON tar.roleId = tr.id LEFT JOIN t_role_permission trp ON trp.roleId = tr.id LEFT JOIN t_permission tp ON tp.id = trp.permissionId WHERE ta.loginName = #{loginName} AND tp.parentId IS NOT NULL </select>
這個是多表連接查詢,其中使用了關鍵字:DISTINCT(去重),因為一個用戶可以有多個角色,一個角色可以有多個權限,當用戶同時擁有2個角色或以上時,而兩個角色中都擁有相同的權限時,必須要使用這個關鍵字DISTINCT(去重),否則相同的權限也會一並查詢出來顯示。
main.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- Created by IntelliJ IDEA. User: shaojiang Date: 2019/1/20 Time: 下午7:07 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name="renderer" content="webkit|ie-comp|ie-stand"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" /> <meta http-equiv="Cache-Control" content="no-siteapp" /> <link rel="Bookmark" href="/favicon.ico" > <link rel="Shortcut Icon" href="/favicon.ico" /> <!--[if lt IE 9]> <script type="text/javascript" src="/statics/lib/html5shiv.js"></script> <script type="text/javascript" src="/statics/lib/respond.min.js"></script> <![endif]--> <link rel="stylesheet" type="text/css" href="/statics/h-ui/css/H-ui.min.css" /> <link rel="stylesheet" type="text/css" href="/statics/h-ui.admin/css/H-ui.admin.css" /> <link rel="stylesheet" type="text/css" href="/statics/lib/Hui-iconfont/1.0.8/iconfont.css" /> <link rel="stylesheet" type="text/css" href="/statics/h-ui.admin/skin/default/skin.css" id="skin" /> <link rel="stylesheet" type="text/css" href="/statics/h-ui.admin/css/style.css" /> <!--[if IE 6]> <script type="text/javascript" src="/statics/lib/DD_belatedPNG_0.0.8a-min.js" ></script> <script>DD_belatedPNG.fix('*');</script> <![endif]--> <title>H-ui.admin v3.1</title> </head> <body> <header class="navbar-wrapper"> <div class="navbar navbar-fixed-top"> <div class="container-fluid cl"> <a class="logo navbar-logo f-l mr-10 hidden-xs" href="/aboutHui.shtml">H-ui.admin</a> <a class="logo navbar-logo-m f-l mr-10 visible-xs" href="/aboutHui.shtml">H-ui</a> <span class="logo navbar-slogan f-l mr-10 hidden-xs">v3.1</span> <a aria-hidden="false" class="nav-toggle Hui-iconfont visible-xs" href="javascript:;"></a> <nav id="Hui-userbar" class="nav navbar-nav navbar-userbar hidden-xs"> <ul class="cl"> <li></li> <li class="dropDown dropDown_hover"> <a href="#" class="dropDown_A">當前用戶:${sessionScope.adminUser.loginName}<i class="Hui-iconfont"></i></a> <ul class="dropDown-menu menu radius box-shadow"> <li><a href="javascript:;" onclick="modifyPwd()" >修改密碼</a></li> <li><a href="javascript:;" onclick="logout()" >退出</a></li> </ul> </li> <li id="Hui-msg"> <a href="#" title="消息"><span class="badge badge-danger">1</span><i class="Hui-iconfont" style="font-size:18px"></i></a> </li> <li id="Hui-skin" class="dropDown right dropDown_hover"> <a href="javascript:;" class="dropDown_A" title="換膚"><i class="Hui-iconfont" style="font-size:18px"></i></a> <ul class="dropDown-menu menu radius box-shadow"> <li><a href="javascript:;" data-val="default" title="默認(黑色)">默認(黑色)</a></li> <li><a href="javascript:;" data-val="blue" title="藍色">藍色</a></li> <li><a href="javascript:;" data-val="green" title="綠色">綠色</a></li> <li><a href="javascript:;" data-val="red" title="紅色">紅色</a></li> <li><a href="javascript:;" data-val="yellow" title="黃色">黃色</a></li> <li><a href="javascript:;" data-val="orange" title="橙色">橙色</a></li> </ul> </li> </ul> </nav> </div> </div> </header> <aside class="Hui-aside"> <div class="menu_dropdown bk_2"> <%--這里控制權限菜單的顯示--%> <c:forEach var="item" items="${permissionList}" begin="0"> <dl> <dt><i class="${item.icon}"></i> ${item.name}<i class="Hui-iconfont menu_dropdown-arrow"></i></dt> <dd> <ul> <c:forEach var="item_subitem" items="${item.childPermissions}"> <li><a data-href="${item_subitem.url}" data-title="${item_subitem.name}" href="javascript:void(0)">${item_subitem.name}</a></li> </c:forEach> </ul> </dd> </dl> </c:forEach> </div> </aside> <div class="dislpayArrow hidden-xs"><a class="pngfix" href="javascript:void(0);" onClick="displaynavbar(this)"></a></div> <section class="Hui-article-box"> <div id="Hui-tabNav" class="Hui-tabNav hidden-xs"> <div class="Hui-tabNav-wp"> <ul id="min_title_list" class="acrossTab cl"> <li class="active"> <span title="我的桌面" data-href="welcome.html">我的桌面</span> <em></em></li> </ul> </div> <div class="Hui-tabNav-more btn-group"><a id="js-tabNav-prev" class="btn radius btn-default size-S" href="javascript:;"><i class="Hui-iconfont"></i></a><a id="js-tabNav-next" class="btn radius btn-default size-S" href="javascript:;"><i class="Hui-iconfont"></i></a></div> </div> <div id="iframe_box" class="Hui-article"> <div class="show_iframe"> <div style="display:none" class="loading"></div> <iframe scrolling="yes" frameborder="0" src="/admin/welcome"></iframe> </div> </div> </section> <div class="contextMenu" id="Huiadminmenu"> <ul> <li id="closethis">關閉當前 </li> <li id="closeall">關閉全部 </li> </ul> </div> <!--_footer 作為公共模版分離出去--> <script type="text/javascript" src="/statics/lib/jquery/1.9.1/jquery.min.js"></script> <script type="text/javascript" src="/statics/lib/layer/2.4/layer.js"></script> <script type="text/javascript" src="/statics/h-ui/js/H-ui.min.js"></script> <script type="text/javascript" src="/statics/h-ui.admin/js/H-ui.admin.js"></script> <!--/_footer 作為公共模版分離出去--> <!--請在下方寫此頁面業務相關的腳本--> <script type="text/javascript" src="/statics/lib/jquery.contextmenu/jquery.contextmenu.r2.js"></script> <script type="text/javascript"> $(function(){ /*$("#min_title_list li").contextMenu('Huiadminmenu', { bindings: { 'closethis': function(t) { console.log(t); if(t.find("i")){ t.find("i").trigger("click"); } }, 'closeall': function(t) { alert('Trigger was '+t.id+'\nAction was Email'); }, } });*/ }); /*修改密碼*/ function modifyPwd(){ parent.layer.open({ title:'修改登錄密碼', maxmin: true, type: 2, shadeClose: false, //點擊遮罩關閉 shade: 0.5,//陰影 content: '/admin/update-login-password.action', area: ['500px', '300px'] }); } /*退出系統*/ function logout() { layer.open({ title: '注銷登錄?', content: '確定要退出該系統?' ,btn: ['確定', '取消'] ,yes: function(index, layero){ //按鈕【按鈕一】的回調 layer.close(index); window.location.href = "/admin/logout"; },btn2: function(index, layero){ //按鈕【按鈕二】的回調 },btn3: function(index, layero){ //按鈕【按鈕三】的回調 } ,cancel: function(){ //右上角關閉回調 } }); } </script> </body> </html>
logout方法
/** * 退出系統 * @return */ @RequestMapping("/logout") public String logout(HttpServletRequest request, SessionStatus sessionState ) { Enumeration<String> em = request.getSession().getAttributeNames(); while (em.hasMoreElements()) { request.getSession().removeAttribute(em.nextElement().toString()); } request.getSession().removeAttribute("adminUser"); //注銷登錄,銷毀session request.getSession().invalidate(); //sessionStatus中的setComplete方法可以將session中的內容全部清空 sessionState.setComplete(); //重定向到到登錄頁面action return "redirect:/admin/login"; }
換一個賬戶:tom登錄,可以看到tom什么權限菜單也沒有,因為tom屬於未分組角色,所以登錄后也看不到任何的菜單,只有默認的修改密碼一個功能可用。
至此,權限菜單的動態顯示完成,本小節結束。下一小節將講解點擊菜單進行權限的攔截驗證放行跳轉,以及控制頁面的權限按鈕(三級菜單)顯示。