day04【后台】角色维护
1、权限控制
1.1、为什么需要权限控制
如果没有权限控制, 系统的功能完全不设防, 全部暴露在所有用户面前。 用户登录以后可以使用系统中的所有功能。 这是实际运行中不能接受的。
所以权限控制系统的目标就是管理用户行为, 保护系统功能。“权限” =“权力” +“限制”
1.2、如何进行权限控制
1.2.1、创建资源
资源就是系统中需要保护起来的功能。 具体形式很多: URL 地址、 handler 方法、 service 方法、 页面元素等等都可以定义为资源使用权限控制系统保护起来。
1.2.2、创建权限
一个功能复杂的项目会包含很多具体资源, 成千上万都有可能。 这么多资源逐个进行操作太麻烦了。 为了简化操作, 可以将相关的几个资源封装到一起, 打包成一个“权限” 同时分配给有需要的人。
1.3、创建角色
对于一个庞大系统来说, 一方面需要保护的资源非常多, 另一方面操作系统的人也非常多。 把资源打包为权限是对操作的简化, 同样把用户划分为不同角色也是对操作的简化。 否则直接针对一个个用户进行管理就会很繁琐。
所以角色就是用户的分组、 分类。 先给角色分配权限, 然后再把角色分配给用户, 用户以这个角色的身份操作系统就享有角色对应的权限了
1.4、管理用户
系统中的用户其实是人操作系统时用来登录系统的账号、 密码。
1.5、关联关系
1.5.1、权限→资源: 单向多对多
Java 类之间单向: 从权限实体类可以获取到资源对象的集合, 但是通过资源获取不到权限
数据库表之间多对多:一个权限可以包含多个资源,一个资源可以被分配给多个不同权限
1.5.2、角色→权限: 单向多对多
Java 类之间单向: 从角色实体类可以获取到权限对象的集合, 但是通过权限获取不到角色
数据库表之间多对多:一个角色可以包含多个权限,一个权限可以被分配给多个不同角色
1.5.3、用户→角色: 双向多对多
Java 类之间双向: 可以通过用户获取它具备的角色, 也可以看一个角色下包含哪些用户
数据库表之间多对多:一个角色可以包含多个用户,一个用户可以身兼数职
1.6、RBAC 权限模型
鉴于权限控制的核心是用户通过角色与权限进行关联, 所以前面描述的权限控制系统可以提炼为一个模型: RBAC(Role-Based Access Control, 基于角色的访问控制)。
在 RBAC 模型中, 一个用户可以对应多个角色, 一个角色拥有多个权限, 权限具体定义用户可以做哪些事情
2、角色分页
2.1、思路
2.2、创建角色表
- 在
project_crowd
数据库中创建t_role
表
CREATE TABLE `project_crowd`.`t_role`( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` CHAR(100)
2.3、逆向工程
2.3.1、修改XML配置文件
- 修改
reverse
工程下的逆向工程配置文件:generatorConfig.xml
,修改数据库表名和实体类名
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- mybatis-generator:generate -->
<context id="atguiguTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是;false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息: 驱动类、 连接地址、 用户名、 密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/project_crowd"
userId="root" password="101713">
</jdbcConnection>
<!-- 默认 false, 把 JDBC DECIMAL 和 NUMERIC 类型解析为 Integer, 为 true 时把 JDBC DECIMAL
和 NUMERIC 类型解析为 java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成 Entity 类的路径 -->
<javaModelGenerator targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.entity">
<!-- enableSubPackages:是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:XxxMapper.xml 映射文件生成的路径 -->
<sqlMapGenerator targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.mapper">
<!-- enableSubPackages:是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage: Mapper 接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.mapper">
<!-- enableSubPackages:是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 数据库表名字和我们的 entity 类对应的映射指定 -->
<table tableName="t_role" domainObjectName="Role" />
</context>
</generatorConfiguration>
2.3.2、执行Maven命令
- 执行
Maven
指令:mybatis-generator:generate
2.3.3、资源归位
- 将实体类归位到
entity
工程下
- 将
Mapper
接口归位到component
工程下
- 将
Mapper
映射文件归位到webui
工程下
2.4、创建相应组件
- 在
component
工程下创建Service
相关组件
- 在
component
工程下创建Handler
相关组件
2.5、Mapper层
2.5.1、编写SQL
- 在
RoleMapper.xml
中添加如下SQL
语句,根据关键词查询Role
<select id="selectRoleByKeyword" resultMap="BaseResultMap">
select id, name from t_role
where name like concat("%",#{keyword},"%")
</select>
2.5.2、修改接口
- 在
RoleMapper.java
接口中添加selectRoleByKeyword
方法的声明
List<Role> selectRoleByKeyword(String keyword);
2.6、Service层
- 在
Service
层中,查询分页数据,并返回Pageinfo
对象
public class RoleServiceImpl implements RoleService {
@Autowired
private RoleMapper roleMapper;
@Override
public PageInfo<Role> getPageInfo(Integer pageNum, Integer pageSize, String keyword) {
// 1.开启分页功能
PageHelper.startPage(pageNum, pageSize);
// 2.执行查询
List<Role> roleList = roleMapper.selectRoleByKeyword(keyword);
// 3.封装为PageInfo对象返回
return new PageInfo<>(roleList);
}
}
2.7、Handler层
2.7.1、业务逻辑
@Controller
public class RoleHandler {
@Autowired
private RoleService roleService;
@ResponseBody
@RequestMapping("/role/get/page/info.json")
public ResultEntity<PageInfo<Role>> getPageInfo(
@RequestParam(value="pageNum", defaultValue="1") Integer pageNum,
@RequestParam(value="pageSize", defaultValue="5") Integer pageSize,
@RequestParam(value="keyword", defaultValue="") String keyword
) {
// 调用Service方法获取分页数据
PageInfo<Role> pageInfo = roleService.getPageInfo(pageNum, pageSize, keyword);
// 封装到ResultEntity对象中返回(如果上面的操作抛出异常,交给异常映射机制处理)
return ResultEntity.successWithData(pageInfo);
}
}
2.8、测试后端json
- 登录之后,直接访问工程路径下的
/role/get/page/info.json
地址,测试后端返回的json
字符串是否正常
2.9、页面准备
2.9.1、配置view-controller
- 在
SpringMVC
配置文件中配置view-controller
<mvc:view-controller path="/role/to/page.html" view-name="role-page"/>
2.9.2、点击跳转
- 修改侧边栏中【角色维护】超链接
- 创建
role-page.jsp
页面,用于显示分页数据
2.10、页面分页
2.10.1、编写JavaScript库
- 在
webapp
目录下创建我们自己的JavaScript
库
// 执行分页,生成页面效果,任何时候调用这个函数都会重新加载页面
function generatePage() {
// 1.获取分页数据
var pageInfo = getPageInfoRemote();
// 2.填充表格
fillTableBody(pageInfo);
}
// 远程访问服务器端程序获取pageInfo数据
function getPageInfoRemote() {
// 调用$.ajax()函数发送请求并接受$.ajax()函数的返回值
var ajaxResult = $.ajax({
"url": "role/get/page/info.json",
"type":"post",
"data": {
"pageNum": window.pageNum,
"pageSize": window.pageSize,
"keyword": window.keyword
},
"async":false,
"dataType":"json"
});
console.log(ajaxResult);
// 判断当前响应状态码是否为200
var statusCode = ajaxResult.status;
// 如果当前响应状态码不是200,说明发生了错误或其他意外情况,显示提示消息,让当前函数停止执行
if(statusCode != 200) {
layer.msg("失败!响应状态码="+statusCode+" 说明信息="+ajaxResult.statusText);
return null;
}
// 如果响应状态码是200,说明请求处理成功,获取pageInfo
var resultEntity = ajaxResult.responseJSON;
// 从resultEntity中获取result属性
var result = resultEntity.result;
// 判断result是否成功
if(result == "FAILED") {
layer.msg(resultEntity.message);
return null;
}
// 确认result为成功后获取pageInfo
var pageInfo = resultEntity.data;
// 返回pageInfo
return pageInfo;
}
// 填充表格
function fillTableBody(pageInfo) {
// 清除tbody中的旧的内容
$("#rolePageBody").empty();
// 全选CheckBox的Checked属性恢复为false
$("#summaryBox").prop("checked", false);
// 这里清空是为了让没有搜索结果时不显示页码导航条
$("#Pagination").empty();
// 判断pageInfo对象是否有效
if(pageInfo == null || pageInfo == undefined || pageInfo.list == null || pageInfo.list.length == 0) {
$("#rolePageBody").append("<tr><td colspan='4' align='center'>抱歉!没有查询到您搜索的数据!</td></tr>");
return ;
}
// 使用pageInfo的list属性填充tbody
for(var i = 0; i < pageInfo.list.length; i++) {
var role = pageInfo.list[i];
var roleId = role.id;
var roleName = role.name;
var numberTd = "<td>"+(i+1)+"</td>";
var checkboxTd = "<td><input id='"+roleId+"' class='itemBox' type='checkbox'></td>";
var roleNameTd = "<td>"+roleName+"</td>";
var checkBtn = "<button type='button' class='btn btn-success btn-xs'><i class=' glyphicon glyphicon-check'></i></button>";
// 通过button标签的id属性(别的属性其实也可以)把roleId值传递到button按钮的单击响应函数中,在单击响应函数中使用this.id
var pencilBtn = "<button id='"+roleId+"' type='button' class='btn btn-primary btn-xs pencilBtn'><i class=' glyphicon glyphicon-pencil'></i></button>";
// 通过button标签的id属性(别的属性其实也可以)把roleId值传递到button按钮的单击响应函数中,在单击响应函数中使用this.id
var removeBtn = "<button id='"+roleId+"' type='button' class='btn btn-danger btn-xs removeBtn'><i class=' glyphicon glyphicon-remove'></i></button>";
var buttonTd = "<td>"+checkBtn+" "+pencilBtn+" "+removeBtn+"</td>";
var tr = "<tr>"+numberTd+checkboxTd+roleNameTd+buttonTd+"</tr>";
$("#rolePageBody").append(tr);
}
// 生成分页导航条
generateNavigator(pageInfo);
}
// 生成分页页码导航条
function generateNavigator(pageInfo) {
// 获取总记录数
var totalRecord = pageInfo.total;
// 声明相关属性
var properties = {
"num_edge_entries": 3,
"num_display_entries": 5,
"callback": paginationCallBack,
"items_per_page": pageInfo.pageSize,
"current_page": pageInfo.pageNum - 1,
"prev_text": "上一页",
"next_text": "下一页"
}
// 调用pagination()函数
$("#Pagination").pagination(totalRecord, properties);
}
// 翻页时的回调函数
function paginationCallBack(pageIndex, jQuery) {
// 修改window对象的pageNum属性
window.pageNum = pageIndex + 1;
// 调用分页函数
generatePage();
// 取消页码超链接的默认行为
return false;
}
- 参考
Admin
的分页代码,理解上述Role
的分页代码
<script type="text/javascript">
$(function(){
// 调用后面声明的函数对页码导航条进行初始化操作
initPagination();
});
// 生成页码导航条的函数
function initPagination() {
// 获取总记录数
var totalRecord = ${requestScope.pageInfo.total};
// 声明一个JSON对象存储Pagination要设置的属性
var properties = {
num_edge_entries: 3, // 边缘页数
num_display_entries: 5, // 主体页数
callback: pageSelectCallback, // 指定用户点击“翻页”的按钮时跳转页面的回调函数
items_per_page: ${requestScope.pageInfo.pageSize}, // 每页要显示的数据的数量
current_page: ${requestScope.pageInfo.pageNum - 1}, // Pagination内部使用pageIndex来管理页码,pageIndex从0开始,pageNum从1开始,所以要减一
prev_text: "上一页", // 上一页按钮上显示的文本
next_text: "下一页" // 下一页按钮上显示的文本
};
// 生成页码导航条
$("#Pagination").pagination(totalRecord, properties);
}
// 回调函数的含义:声明出来以后不是自己调用,而是交给系统或框架调用
// 用户点击“上一页、下一页、1、2、3……”这样的页码时调用这个函数实现页面跳转
// pageIndex是Pagination传给我们的那个“从0开始”的页码
function pageSelectCallback(pageIndex, jQuery) {
// 根据pageIndex计算得到pageNum
var pageNum = pageIndex + 1;
// 跳转页面
window.location.href = "admin/get/page.html?pageNum="+pageNum+"&keyword=${param.keyword}";
// 由于每一个页码按钮都是超链接,所以在这个函数最后取消超链接的默认行为
return false;
}
</script>
2.10.2、编写页面
- 在
role-page.jsp
页面引入pagination.js
库和my-role.js
库,并编写相应业务逻辑
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="zh-CN">
<%@include file="/WEB-INF/include-head.jsp"%>
<link rel="stylesheet" href="css/pagination.css" />
<script type="text/javascript" src="jquery/jquery.pagination.js"></script>
<script type="text/javascript" src="crowd/my-role.js"></script>
<script type="text/javascript">
$(function(){
// 1.为分页操作准备初始化数据
window.pageNum = 1;
window.pageSize = 5;
window.keyword = "";
// 2.调用执行分页的函数,显示分页效果
generatePage();
});
</script>
<body>
<%@ include file="/WEB-INF/include-nav.jsp"%>
<div class="container-fluid">
<div class="row">
<%@ include file="/WEB-INF/include-sidebar.jsp"%>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="glyphicon glyphicon-th"></i> 数据列表
</h3>
</div>
<div class="panel-body">
<form class="form-inline" role="form" style="float: left;">
<div class="form-group has-feedback">
<div class="input-group">
<div class="input-group-addon">查询条件</div>
<input id="keywordInput" class="form-control has-success" type="text"
placeholder="请输入查询条件">
</div>
</div>
<button id="searchBtn" type="button" class="btn btn-warning">
<i class="glyphicon glyphicon-search"></i> 查询
</button>
</form>
<button id="batchRemoveBtn" type="button" class="btn btn-danger"
style="float: right; margin-left: 10px;">
<i class=" glyphicon glyphicon-remove"></i> 删除
</button>
<button
type="button"
id="showAddModalBtn" class="btn btn-primary"
style="float: right;">
<i class="glyphicon glyphicon-plus"></i> 新增
</button>
<br>
<hr style="clear: both;">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th width="30">#</th>
<th width="30"><input id="summaryBox" type="checkbox"></th>
<th>名称</th>
<th width="100">操作</th>
</tr>
</thead>
<tbody id="rolePageBody"></tbody>
<tfoot>
<tr>
<td colspan="6" align="center">
<div id="Pagination" class="pagination"><!-- 这里显示分页 --></div>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
2.10.3、Ajax请求内容
Ajax
请求成功
Ajax
请求失败
2.11、分页测试
- 成功~
3、关键词查询
3.1、思路
3.2、按钮单击事件
- 单击查询按钮,则执行分页操作,后端代码无需更改
<script type="text/javascript">
$(function(){
// 1.为分页操作准备初始化数据
window.pageNum = 1;
window.pageSize = 5;
window.keyword = "";
// 2.调用执行分页的函数,显示分页效果
generatePage();
// 3.给查询按钮绑定单击响应函数
$("#searchBtn").click(function(){
// ①获取关键词数据赋值给对应的全局变量
window.keyword = $("#keywordInput").val();
// ②调用分页函数刷新页面
generatePage();
});
});
</script>
3.3、测试
- 乌拉~
4、新增
4.1、思路
4.2、引入模态框
4.2.1、新建模态框
- 在
WEB-INF
文件夹下新建模态框modal-role-add.jsp
,用于新增Role
弹框
- 代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<div id="addModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">尚筹网系统弹窗</h4>
</div>
<div class="modal-body">
<form class="form-signin" role="form">
<div class="form-group has-success has-feedback">
<input type="text" name="roleName" class="form-control"
placeholder="请输入角色名称" autofocus>
</div>
</form>
</div>
<div class="modal-footer">
<button id="saveRoleBtn" type="button" class="btn btn-primary">保存</button>
</div>
</div>
</div>
</div>
4.2.2、引入模态框
- 在
role-page.jsp
页面中引入模块矿
<%@include file="/WEB-INF/modal-role-add.jsp" %>
4.2.3、模态弹框
- 添加
JavaScript
代码,点击【新增】按钮,弹出模态框
- 新增按钮:为了能够绑定单击事件,加上
id
属性
<button
type="button"
id="showAddModalBtn" class="btn btn-primary"
style="float: right;">
<i class="glyphicon glyphicon-plus"></i> 新增
</button>
- 单击响应函数
// 4.点击新增按钮打开模态框
$("#showAddModalBtn").click(function(){
$("#addModal").modal("show");
});
4.2.4、弹框测试
- 乌拉~
4.3、保存角色
4.3.1、前端代码
- 给模态框中的【保存】按钮绑定单击响应函数
// 5.给新增模态框中的保存按钮绑定单击响应函数
$("#saveRoleBtn").click(function(){
// ①获取用户在文本框中输入的角色名称
// #addModal表示找到整个模态框
// 空格表示在后代元素中继续查找
// [name=roleName]表示匹配name属性等于roleName的元素
var roleName = $.trim($("#addModal [name=roleName]").val());
// ②发送Ajax请求
$.ajax({
"url": "role/save.json",
"type":"post",
"data": {
"name": roleName
},
"dataType": "json",
"success":function(response){
var result = response.result;
if(result == "SUCCESS") {
layer.msg("操作成功!");
// 将页码定位到最后一页
window.pageNum = 99999999;
// 重新加载分页数据
generatePage();
}
if(result == "FAILED") {
layer.msg("操作失败!"+response.message);
}
},
"error":function(response){
layer.msg(response.status+" "+response.statusText);
}
});
// 关闭模态框
$("#addModal").modal("hide");
// 清理模态框
$("#addModal [name=roleName]").val("");
});
4.3.2、后端代码
- 在
RoleHandler.java
中保存新增的角色
@ResponseBody
@RequestMapping("/role/save.json")
public ResultEntity<String> saveRole(Role role) {
roleService.saveRole(role);
return ResultEntity.successWithoutData();
}
- 在
Service
层实现上述方法
@Override
public void saveRole(Role role) {
roleMapper.insert(role);
}
4.4、测试
- 乌拉~
5、更新
5.1、思路
5.2、更新模态框
5.2.1、新建模态框
- 在
WEB-INF
文件夹下创建modal-role-edit.jsp
模态框,更新角色弹框
- 页面代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<div id="editModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">尚筹网系统弹窗</h4>
</div>
<div class="modal-body">
<form class="form-signin" role="form">
<div class="form-group has-success has-feedback">
<input type="text" name="roleName" class="form-control"
placeholder="请输入角色名称" autofocus>
</div>
</form>
</div>
<div class="modal-footer">
<button id="updateRoleBtn" type="button" class="btn btn-success">更新</button>
</div>
</div>
</div>
</div>
5.2.2、引入模态框
- 在
role-page.jsp
页面引入更新角色的模态框
<%@include file="/WEB-INF/modal-role-edit.jsp"%>
5.3、更新角色
5.3.1、前端代码
- 准备工作:给【更新】按钮设置
id
和class
属性,这样我们才能用JavaScript
代码找到它
// 通过button标签的id属性(别的属性其实也可以)把roleId值传递到button按钮的单击响应函数中,在单击响应函数中使用this.id
var pencilBtn = "<button id='"+roleId+"' type='button' class='btn btn-primary btn-xs pencilBtn'><i class=' glyphicon glyphicon-pencil'></i></button>";
- 给【更新】按钮绑定单击响应函数:打开更新模态框,回显角色名称
// 6.给页面上的“铅笔”按钮绑定单击响应函数,目的是打开模态框
// 传统的事件绑定方式只能在第一个页面有效,翻页后失效了
// $(".pencilBtn").click(function(){
// alert("aaaa...");
// });
// 使用jQuery对象的on()函数可以解决上面问题
// ①首先找到所有“动态生成”的元素所附着的“静态”元素
// ②on()函数的第一个参数是事件类型
// ③on()函数的第二个参数是找到真正要绑定事件的元素的选择器
// ③on()函数的第三个参数是事件的响应函数
$("#rolePageBody").on("click",".pencilBtn",function(){
// 打开模态框
$("#editModal").modal("show");
// 获取表格中当前行中的角色名称
var roleName = $(this).parent().prev().text();
// 获取当前角色的id
// 依据是:var pencilBtn = "<button id='"+roleId+"' ……这段代码中我们把roleId设置到id属性了
// 为了让执行更新的按钮能够获取到roleId的值,把它放在全局变量上
window.roleId = this.id;
// 使用roleName的值设置模态框中的文本框
$("#editModal [name=roleName]").val(roleName);
});
- 给模态框中的【更新】按钮绑定单击响应函数:提交修改请求
// 7.给更新模态框中的更新按钮绑定单击响应函数
$("#updateRoleBtn").click(function(){
// ①从文本框中获取新的角色名称
var roleName = $("#editModal [name=roleName]").val();
// ②发送Ajax请求执行更新
$.ajax({
"url":"role/update.json",
"type":"post",
"data":{
"id":window.roleId,
"name":roleName
},
"dataType":"json",
"success":function(response){
var result = response.result;
if(result == "SUCCESS") {
layer.msg("操作成功!");
// 重新加载分页数据
generatePage();
}
if(result == "FAILED") {
layer.msg("操作失败!"+response.message);
}
},
"error":function(response){
layer.msg(response.status+" "+response.statusText);
}
});
// ③关闭模态框
$("#editModal").modal("hide");
});
5.3.2、后端代码
- 在
RoleHandler.java
中更新角色信息
@ResponseBody
@RequestMapping("/role/update.json")
public ResultEntity<String> updateRole(Role role) {
roleService.updateRole(role);
return ResultEntity.successWithoutData();
}
- 在
Service
层实现上述方法
@Override
public void updateRole(Role role) {
roleMapper.updateByPrimaryKey(role);
}
5.4、测试
- 乌拉~
6、删除
6.1、思路
6.2、删除模态框
6.2.1、新建模态框
- 在
WEB-INF
文件夹下创建modal-role-confirm.jsp
模态框,删除角色时将弹出此模态框
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<div id="confirmModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">尚筹网系统弹窗</h4>
</div>
<div class="modal-body">
<h4>请确认是否要删除下列角色:</h4>
<div id="roleNameDiv" style="text-align: center;"></div>
</div>
<div class="modal-footer">
<button id="removeRoleBtn" type="button" class="btn btn-primary">确认删除</button>
</div>
</div>
</div>
</div>
6.2.2、引入模态框
- 在
role-page.jsp
页面引入删除角色的模态框
<%@include file="/WEB-INF/modal-role-confirm.jsp"%>
6.3、删除角色
6.3.1、前端代码
- 在
webapp
下的my-role.js
库中添加如下函数:弹出删除模态框,并回显要删除的角色名称
// 声明专门的函数显示确认模态框
function showConfirmModal(roleArray) {
// 打开模态框
$("#confirmModal").modal("show");
// 清除旧的数据
$("#roleNameDiv").empty();
// 在全局变量范围创建数组用来存放角色id
window.roleIdArray = [];
// 遍历roleArray数组
for(var i = 0; i < roleArray.length; i++) {
var role = roleArray[i];
var roleName = role.roleName;
$("#roleNameDiv").append(roleName+"<br/>");
var roleId = role.roleId;
// 调用数组对象的push()方法存入新元素
window.roleIdArray.push(roleId);
}
}
- 给模态框中的【确认删除】按钮添加单击响应函数
// 临时测试代码
// var roleArray = [{roleId:5,roleName:"aaa"},{roleId:5,roleName:"bbb"}];
// showConfirmModal(roleArray);
// 8.点击确认模态框中的确认删除按钮执行删除
$("#removeRoleBtn").click(function(){
// 从全局变量范围获取roleIdArray,转换为JSON字符串
var requestBody = JSON.stringify(window.roleIdArray);
$.ajax({
"url":"role/remove/by/role/id/array.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("操作成功!");
// 重新加载分页数据
generatePage();
}
if(result == "FAILED") {
layer.msg("操作失败!"+response.message);
}
},
"error":function(response){
layer.msg(response.status+" "+response.statusText);
}
});
// 关闭模态框
$("#confirmModal").modal("hide");
});
- 给单条删除按钮绑定单击响应函数
// 准备工作:给【单条删除】按钮设置`id`和`class`属性,这样我们才能用`JavaScript`代码找到它
// 通过button标签的id属性(别的属性其实也可以)把roleId值传递到button按钮的单击响应函数中,在单击响应函数中使用this.id
var removeBtn = "<button id='"+roleId+"' type='button' class='btn btn-danger btn-xs removeBtn'><i class=' glyphicon glyphicon-remove'></i></button>";
// 9.给单条删除按钮绑定单击响应函数
$("#rolePageBody").on("click",".removeBtn",function(){
// 从当前按钮出发获取角色名称
var roleName = $(this).parent().prev().text();
// 创建role对象存入数组
var roleArray = [{
roleId:this.id,
roleName:roleName
}];
// 调用专门的函数打开模态框
showConfirmModal(roleArray);
});
- 给全选的
CheckBox
绑定单击响应函数
// 准备工作:给【复选框】设置`id`和`class`属性,这样我们才能用`JavaScript`代码找到它
var checkboxTd = "<td><input id='"+roleId+"' class='itemBox' type='checkbox'></td>";
// 10.给总的checkbox绑定单击响应函数
$("#summaryBox").click(function(){
// ①获取当前多选框自身的状态
var currentStatus = this.checked;
// ②用当前多选框的状态设置其他多选框
$(".itemBox").prop("checked", currentStatus);
});
- 给单选的
CheckBox
绑定单击响应函数,实现全选、全不选的反向操作
// 11.全选、全不选的反向操作
$("#rolePageBody").on("click",".itemBox",function(){
// 获取当前已经选中的.itemBox的数量
var checkedBoxCount = $(".itemBox:checked").length;
// 获取全部.itemBox的数量
var totalBoxCount = $(".itemBox").length;
// 使用二者的比较结果设置总的checkbox
$("#summaryBox").prop("checked", checkedBoxCount == totalBoxCount);
});
- 给批量删除按钮绑定单击响应函数
// 12.给批量删除的按钮绑定单击响应函数
$("#batchRemoveBtn").click(function(){
// 创建一个数组对象用来存放后面获取到的角色对象
var roleArray = [];
// 遍历当前选中的多选框
$(".itemBox:checked").each(function(){
// 使用this引用当前遍历得到的多选框
var roleId = this.id;
// 通过DOM操作获取角色名称
var roleName = $(this).parent().next().text();
roleArray.push({
"roleId":roleId,
"roleName":roleName
});
});
// 检查roleArray的长度是否为0
if(roleArray.length == 0) {
layer.msg("请至少选择一个执行删除");
return ;
}
// 调用专门的函数打开模态框
showConfirmModal(roleArray);
});
6.3.2、后端代码
- 在
RoleHandler.java
中批量删除角色,由于需要接收浏览器端发送的数组,使用@RequestBody
标记
@ResponseBody
@RequestMapping("/role/remove/by/role/id/array.json")
public ResultEntity<String> removeByRoleIdAarry(@RequestBody List<Integer> roleIdList) {
roleService.removeRole(roleIdList);
return ResultEntity.successWithoutData();
}
- 在
Service
层实现上述方法
@Override
public void removeRole(List<Integer> roleIdList) {
RoleExample example = new RoleExample();
Criteria criteria = example.createCriteria();
//delete from t_role where id in (5,8,12)
criteria.andIdIn(roleIdList);
roleMapper.deleteByExample(example);
}
6.4、测试
- 删除单个角色
- 批量删除角色
- 未选中任何角色就点击删除