目录
2.3.1、创建保存 Admin-Role 关联关系的数据库表
2.3.4、创建 assign-role.jsp.jsp 页面并显示已分配和未分配的角色信息
2.3.9、给保存按钮绑定单击事件,使点击时选中所有要分配列表的option
1、权限控制
ContextConfiguration
2、给管理员分配 Role
2.1、目标
通过页面操作把 Admin 和 Role 之间的关联关系保存到数据库。
2.2、思路
2.3、代码
2.3.1、创建保存 Admin-Role 关联关系的数据库表
CREATE TABLE `project_crowd`.`inner_admin_role` (
`id` INT NOT NULL AUTO_INCREMENT,
`admin_id` INT,
`role_id` INT,
PRIMARY KEY (`id`)
);
2.3.2、修改分配权限的按钮
admin-page.jsp
<a href="assign/to/assign/role/page.html?adminId=${admin.id}&pageNum=${requestScope.pageInfo.pageNum}&keyword=${param.keyword}"
class="btn btn-success btn-xs">
<i class=" glyphicon glyphicon-check"></i>
</a>
2.3.2、创建 AssignHandle
package com.atguigu.crowd.mvc.handle;
import com.atguigu.crowd.entity.Role;
import com.atguigu.crowd.service.api.AdminService;
import com.atguigu.crowd.service.api.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
* @Author zhang
* @Date 2022/5/13 - 22:49
* @Version 1.0
*/
@Controller
public class AssignHandle {
@Autowired
private AdminService adminService;
@Autowired
private RoleService roleService;
/**
* 跳转到分配角色页面
* @param adminId 要分配的管理员的ID
* @param modelMap
* @return
*/
@RequestMapping("/assign/to/assign/role/page.html")
public String toAssignRolePage(
@RequestParam("adminId") Integer adminId,
ModelMap modelMap
){
// 查询已分配的角色
List<Role> assignedRoleList = roleService.getAssignedRole(adminId);
// 查询未分配的角色
List<Role> unAssignedRoleList = roleService.getUnAssignedRole(adminId);
// 存入模型
modelMap.addAttribute("assignedRoleList", assignedRoleList);
modelMap.addAttribute("unAssignedRoleList", unAssignedRoleList);
return "assign-role.jsp";
}
}
2.3.3、完成 service 层方法
RoleService
/**
* 获取已分配的角色
* @param adminId 要获取的管理员的ID
* @return
*/
List<Role> getAssignedRole(Integer adminId);
/**
* 获取未分配的角色
* @param adminId 要获取的管理员的ID
* @return
*/
List<Role> getUnAssignedRole(Integer adminId);
RoleServiceImpl
/**
* 获取已分配的角色
* @param adminId 要获取的管理员的ID
* @return
*/
@Override
public List<Role> getAssignedRole(Integer adminId) {
return roleMapper.getAssignedRole(adminId);
}
/**
* 获取未分配的角色
* @param adminId 要获取的管理员的ID
* @return
*/
@Override
public List<Role> getUnAssignedRole(Integer adminId) {
return roleMapper.getUnAssignedRole(adminId);
}
RoleMapper.java
/**
* 获取已分配的角色
* @param adminId 要获取的管理员的ID
* @return
*/
List<Role> getAssignedRole(Integer adminId);
/**
* 获取未分配的角色
* @param adminId 要获取的管理员的ID
* @return
*/
List<Role> getUnAssignedRole(Integer adminId);
RoleMapper.xml
<select id="getAssignedRole" resultMap="BaseResultMap">
select id, name
from t_role
where id in (
select role_id
from inner_admin_role
where admin_id = #{adminId}
)
</select>
<select id="getUnAssignedRole" resultMap="BaseResultMap">
select id, name
from t_role
where id not in (
select role_id
from inner_admin_role
where admin_id = #{adminId}
)
</select>
2.3.4、创建 assign-role.jsp.jsp 页面并显示已分配和未分配的角色信息
option 标签的 value 属性在提交表单时会一起发送给 handle 方法
<c:forEach items="${requestScope.unAssignedRoleList}" var="role">
<option value="${role.id}">${role.name}</option>
</c:forEach>
<c:forEach items="${requestScope.assignedRoleList}" var="role">
<option value="${role.id}">${role.name}</option>
</c:forEach>
2.3.5、调整表单使其能够提交数据
assign-role.jsp
添加三个隐藏域,设置跳转地址及方法,已分配角色列表的 select 标签设置 name 属性,以便保存到数据库,添加保存按钮
<form action="assign/do/role/assign.html" method="post" role="form" class="form-inline">
<input type="hidden" name="adminId" value="${param.adminId}">
<input type="hidden" name="pageNum" value="${param.pageNum}">
<input type="hidden" name="keyword" value="${param.keyword}">
<div class="form-group">
<label for="exampleInputPassword1">未分配角色列表</label><br>
<select class="form-control" multiple="" size="10" style="width:100px;overflow-y:auto;">
<c:forEach items="${requestScope.unAssignedRoleList}" var="role">
<option value="${role.id}">${role.name}</option>
</c:forEach>
</select>
</div>
<div class="form-group">
<ul>
<li class="btn btn-default glyphicon glyphicon-chevron-right"></li>
<br>
<li class="btn btn-default glyphicon glyphicon-chevron-left" style="margin-top:20px;"></li>
</ul>
</div>
<div class="form-group" style="margin-left:40px;">
<label for="exampleInputPassword1">已分配角色列表</label><br>
<select name="roleIdList"
class="form-control" multiple="multiple" size="10" style="width:100px;overflow-y:auto;">
<c:forEach items="${requestScope.assignedRoleList}" var="role">
<option value="${role.id}">${role.name}</option>
</c:forEach>
</select>
</div>
<button style="width:100px;margin:20px 100px" type="submit" class="btn btn-sm btn-success btn-block"> 保存</button>
</form>
2.3.6、角色列表左右移角色
① 给左移和右移按钮设置 id 属性
<div class="form-group">
<ul>
<li id="toRightBtn" class="btn btn-default glyphicon glyphicon-chevron-right"></li>
<br>
<li id="toLeftBtn" class="btn btn-default glyphicon glyphicon-chevron-left" style="margin-top:20px;"></li>
</ul>
</div>
② 给左移和右移按钮绑定单击事件
// 右移选中的角色
$("#toRightBtn").click(function (){
// 找到未分配列表中选中的角色
// eq(0):第一个select标签
// > :后代元素
// appendTo:将元素追加到指定元素后,原本的位置消失
$("select:eq(0)>option:selected").appendTo("select:eq(1)");
});
// 左移选中的角色
$("#toLeftBtn").click(function (){
// 找到未分配列表中选中的角色
// eq(0):第一个select标签
// > :后代元素
// appendTo:将元素追加到指定元素后,原本的位置消失
$("select:eq(1)>option:selected").appendTo("select:eq(0)");
});
2.3.7、完成保存分配角色信息的 handle 方法
AssignHandle
/**
* 将要分配的角色保存
* @param adminId 要保存的管理员的id
* @param pageNum 保存完后跳转页面的页数
* @param keyword 保存完后跳转页面的关键词
* @param roleIdList 要保存的角色id集合
* @return
*/
@RequestMapping("/assign/do/role/assign.html")
public String saveRelationship(
@RequestParam("adminId") Integer adminId,
@RequestParam("pageNum") Integer pageNum,
@RequestParam("keyword") String keyword,
@RequestParam(value = "roleIdList", required = false) List<Integer> roleIdList
){
adminService.saveRelationship(adminId, roleIdList);
return "redirect:/admin/get/page.html?pageNum=" + pageNum + "&keyword=" + keyword;
}
2.3.8、完成保存角色信息的 service 层方法
AdminService
/**
* 将roleIdList中对应的角色分配给adminId对应的管理员
* @param adminId 要分配的管理员的id
* @param roleIdList 要分配的角色的id集合
*/
void saveRelationship(Integer adminId, List<Integer> roleIdList);
AdminServiceImpl
/**
* 将roleIdList中对应的角色分配给adminId对应的管理员
* @param adminId 要分配的管理员的id
* @param roleIdList 要分配的角色的id集合
*/
@Override
public void saveRelationship(Integer adminId, List<Integer> roleIdList) {
// 删除adminId的旧数据
adminMapper.deleteRelationship(adminId);
// 根据adminId和roleList保存新的关联关系
if(roleIdList != null && roleIdList.size() > 0){
adminMapper.insertNewRelationship(adminId, roleIdList);
}
}
AdminMapper.java
/**
* 删除adminId的角色信息
* @param adminId
*/
void deleteRelationship(Integer adminId);
/**
* 将roleIdList角色信息和adminId关联保存到数据库
* @param adminId
* @param roleIdList
*/
void insertNewRelationship(@Param("adminId") int adminId, @Param("roleIdList") List<Integer> roleIdList);
AdminMapper.xml
<delete id="deleteRelationship">
delete from inner_admin_role where admin_id = #{adminId}
</delete>
<insert id="insertNewRelationship">
insert into inner_admin_role(admin_id, role_id) values
<foreach collection="roleIdList" item="roleId" separator=",">
(#{adminId}, #{roleId})
</foreach>
</insert>
2.3.9、给保存按钮绑定单击事件,使点击时选中所有要分配列表的option
此时,当点击保存时,程序只保存已分配角色列表选中的角色,而不是所有角色
① 给保存按钮设定 id 属性
<button id="submitBtn" style="width:100px;margin:20px 100px" type="submit" class="btn btn-sm btn-success btn-block">
保存
</button>
② 给保存按钮绑定单击事件
// 给保存按钮绑定单击事件
$("#submitBtn").click(function (){
// 使要分配的列表的所有option选中
$("select:eq(1)>option").prop("selected", "selected");
// return false;
});
3、给 Role 分配 Auth
3.1、思路
3.2、代码
3.2.1、创建权限表 t_auth
创建表
CREATE TABLE `t_auth` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200) DEFAULT NULL,
`title` VARCHAR(200) DEFAULT NULL,
`category_id` INT(11) DEFAULT NULL, PRIMARY KEY (`id`)
);
表属性解释:
-
name 字段:给资源分配权限或给角色分配权限时使用的具体值,将来做权限验证也是使用 name 字段的值来进行比对。建议使用英文。name 字段中值的格式中间的“:”没有任何特殊含义。不论是我们自己写的代码还是将来使用的框架都不会解析“:”。如果不用“:”,用“%、@、&、*、-”等等这样的符号也都是可以的。
-
title 字段:在页面上显示,让用户便于查看的值。建议使用中文。
-
category_id 字段:关联到当前权限所属的分类。这个关联不是到其他表关联,而是就在当前表内部进行关联,关联其他记录。所以说,t_auth 表中是依靠 category_id 字段建立了“节点”之间的父子关系。
插入数据
INSERT INTO t_auth(id,`name`,title,category_id) VALUES(1,'','用户模块',NULL);
INSERT INTO t_auth(id,`name`,title,category_id) VALUES(2,'user:delete','删除',1);
INSERT INTO t_auth(id,`name`,title,category_id) VALUES(3,'user:get','查询',1);
INSERT INTO t_auth(id,`name`,title,category_id) VALUES(4,'','角色模块',NULL);
INSERT INTO t_auth(id,`name`,title,category_id) VALUES(5,'role:delete','删除',4);
INSERT INTO t_auth(id,`name`,title,category_id) VALUES(6,'role:get','查询',4);
INSERT INTO t_auth(id,`name`,title,category_id) VALUES(7,'role:add','新增',4);
3.2.2、逆向工程:生成权限相关资源
① 修改逆向工程的配置文件:atcrowdfunding06-common-reverse 模块的 generatorConfig.xml
<table tableName="t_auth" domainObjectName="Auth" />
② 执行 maven 指令
③ 给 Auth 类添加无参构造器、有参构造器
④ 将生成的资源归位
3.2.3、创建获取所有权限的 方法
AuthService
public interface AuthService {
/**
* 获取所有权限
* @return
*/
List<Auth> getAll();
}
AuthServiceImpl
@Service
public class AuthServiceImpl implements AuthService {
@Autowired
private AuthMapper authMapper;
/**
* 获取所有权限
* @return
*/
@Override
public List<Auth> getAll() {
authMapper.selectByExample(new AuthExample());
return null;
}
}
AssignHandle
/**
* 获取所有权限
* @return
*/
@ResponseBody
@RequestMapping("/assign/get/all/auth.json")
public ResultEntity<List<Auth>> getAllAuth(){
List<Auth> authList = authService.getAll();
return ResultEntity.successWithData(authList);
}
3.2.4、打开分配权限的模态框并显示 auth 树形结构
① 准备模态框页面,位置:atcrowdfunding01-admin-parent\atcrowdfunding02-admin-webui\src\main\webapp\WEB-INF\modal-role-assign-auth.jsp
② 在 role-page.jsp 引入模态框页面
<%@include file="/WEB-INF/modal-role-assign-auth.jsp"%>
③ 修改打开模态框的按钮
my-role.js 的 fillTableBody 函数
添加 id 属性和 class 属性
var checkBtn = "<button id='" + roleId + "' type='button' class='btn btn-success btn-xs checkBtn'><i class=' glyphicon glyphicon-check'></i></button>";
④ 引入 zTree,注意放在引入 my-role.js 的前面
role-page.jsp
<%-- 引入zTree环境 --%>
<link rel="stylesheet" href="ztree/zTreeStyle.css">
<script type="text/javascript" src="ztree/jquery.ztree.all-3.5.min.js"></script>
⑤ 定义专门用来生成 auth 树形结构的函数
my-role.js
// 专门用来在分配auth的模态框中显示Auth的树形结构的函数
function fillAuthThree(){
// 发送Ajax请求查询Auth数据
var ajaxReturn = $.ajax({
"url" : "assign/get/all/auth.json",
"type" : "post",
"dataType" : "json",
"async" : false, // 设置同步
});
if(ajaxReturn.status != 200){
layer.msg("请求处理出错!响应状态码:" + ajaxReturn.status + " 说明:" + ajaxReturn.statusText);
return;
}
// 从响应结果获取auth的JSON数据
var authList = ajaxReturn.responseJSON.data;
// 准备对zTree进行设置的JSON对象
var setting = {
"data":{
"simpleData":{
// 开启简单JSON生成树功能
"enable":true,
//
"pIdKey" : "categoryId"
},
"key" : {
// 使用title属性显示节点名称,不用默认的name值作为属性名
"name" : "title"
}
},
"check":{
"enable" : true // 在图标前显示复选框
}
};
// 生成树形结构
$.fn.zTree.init($("#authTreeDemo"), setting, authList);
// 获取zTreeObj对象
var zTreeObj = $.fn.zTree.getZTreeObj("authTreeDemo");
// 调用zTreeObj对象方法,把节点展开
zTreeObj.expandAll(true);
// 查询已分配的auth的id组成的List
ajaxReturn = $.ajax({
"url" : "assign/get/assigned/auth/id/by/role/id.json",
"type" : "post",
"data" : {
"roleId" : window.roleId
},
"dataType":"json",
"async" : false
});
if(ajaxReturn.status != 200){
layer.msg("服务器端成勋调用失败!响应状态码是" + statusCode + "说明信息:" + ajaxResult.statusText);
return null;
}
// 从响应结果获取authIdArray
var authIdArray = ajaxReturn.responseJSON.data;
// console.log(authIdArray);
// 根据authIdArray把树形结构中对应的节点勾选上
for(var i = 0; i < authIdArray.length; i++){
var authId = authIdArray[i];
// 根据id查询树形结构中对应的节点
var treeNode = zTreeObj.getNodeByParam("id", authId);
// 将对应的treeNode设置为被勾选
var checked = true; // 选中状态
var checkTypeFlag = false; // 是否与父节点的勾选状态进行联动(类似全选)
zTreeObj.checkNode(treeNode, checked, checkTypeFlag);
}
}
④ 给打开分配权限模态框的按钮绑定单击事件
role-page.jsp
// 给分配权限按钮绑定单击事件
$("#rolePageBody").on("click", ".checkBtn", function (){
// 把当前角色id存入全局变量
window.roleId = this.id;
// 打开模态框
$("#assignModal").modal("show");
// 在模态框中装载Auth的树形结构
fillAuthThree();
});
3.2.5、创建角色与权限之间关联关系的中间表
CREATE TABLE `project_crowd`.`inner_role_auth`(
`id` INT NOT NULL AUTO_INCREMENT,
`role_id` INT,
`auth_id` INT,
PRIMARY KEY (`id`)
);
3.2.6、根据 role_id 查询 auth_id
① 在 AuthMapper.xml 创建 SQL 语句
<!-- 根据roleId查询已分配的权限 -->
<select id="selectAssignedAuthIdBtRoleId" resultType="int">
select auth_id from inner_role_auth where role_id = #{roleId}
</select>
② AuthMapper
/**
* 根据roleId查询已分配的权限
* @param roleId
* @return
*/
List<Integer> selectAssignedAuthIdBtRoleId(Integer roleId);
③ AuthService
/**
* 根据roleId查询已分配的权限
* @param roleId
* @return
*/
List<Integer> getAssignedAuthIdBtRoleId(Integer roleId);
④ AuthServiceImpl
/**
* 根据roleId查询已分配的权限
* @param roleId
* @return
*/
@Override
public List<Integer> getAssignedAuthIdBtRoleId(Integer roleId) {
return authMapper.selectAssignedAuthIdBtRoleId(roleId);
}
3.2.7、执行分配
① 给分配按钮绑定单击事件
role-page.jsp
// 给分配权限的按钮绑定单击事件,保存修改结果
$("#assignBtn").click(function (){
// 收集树形结构被勾选的节点
var authIdArray = [];
var zTreeObj = $.fn.zTree.getZTreeObj("authTreeDemo"); // 获取zTreeObj对象
var checkedNodes = zTreeObj.getCheckedNodes(true); // 获取被勾选的节点
for(var i = 0; i < checkedNodes.length; i++){
var chenkedNode = checkedNodes[i];
var authId = chenkedNode.id;
authIdArray.push(authId);
}
//alert(authIdArray);
// 发送请求执行分配
var requestBody = {
"authIdArray":authIdArray,
// 为了方便后端handle方法使用List<Integer>方式接收参数,roleId也存入数组
"roleId":[window.roleId]
}
requestBody = JSON.stringify(requestBody);
$.ajax({
"url":"assign/do/role/assign/auth.json",
"type":"post",
"data":requestBody,
"contentType":"application/json;charset=UTF-8",
"dataType":"json",
"success":function (response){
var result = response.result;
if(result == "SUCCESS"){
layer.msg("操作成功!");
}
if(result == "FAILED"){
layer.msg("操作失败!" + " " + response.statusText);
}
},
"error":function (response){
layer.msg(response.status + " " +response.statusText)
}
});
// 关闭模态框
$("#assignModal").modal("hide");
});
② 执行分配的service层代码
AuthHandle
/**
* 修改roleId的权限
* @param map
* @return
*/
@ResponseBody
@RequestMapping("/assign/do/role/assign/auth.json")
public ResultEntity<String> saveRoleAuthRelationship(@RequestBody Map<String, List<Integer>> map){
authService.saveRoleAuthRelationship(map);
return ResultEntity.successWithoutData();
}
AuthService
/**
* 修改角色与权限的关系
* @param map
*/
void saveRoleAuthRelationship(Map<String, List<Integer>> map);
AuthServiceImpl
/**
* 修改角色与权限的关系
* @param map
*/
@Override
public void saveRoleAuthRelationship(Map<String, List<Integer>> map) {
// 获取roleId
List<Integer> roleIdList = map.get("roleId");
Integer roleId = roleIdList.get(0);
// 删除旧关联关系
authMapper.deleteOleRelationship(roleId);
// 获取authIdList
List<Integer> authIdList = map.get("authIdArray");
// 判断authIdList是否有效
if(authIdList != null && authIdList.size() > 0){
authMapper.insertNewRelationship(roleId, authIdList);
}
}
AuthMapper
/**
* 删除roleId的权限关系
* @param roleId
*/
void deleteOleRelationship(Integer roleId);
/**
* 为roleId添加权限关系
* @param roleId
* @param authIdList
*/
void insertNewRelationship(@Param("roleId") Integer roleId, @Param("authIdList") List<Integer> authIdList);
AuthMapper.xml
<!-- 删除roleId的权限关系 -->
<delete id="deleteOleRelationship">
delete from inner_role_auth where role_id = #{roleId}
</delete>
<!-- 为roleId添加权限关系 -->
<insert id="insertNewRelationship">
insert into inner_role_auth(auth_id, role_id) values
<foreach collection="authIdList" item="authId" separator=",">
(#{authId}, #{roleId})
</foreach>
</insert>