day04【后台】角色维护

day04【后台】角色维护

1、权限控制

1.1、为什么需要权限控制

如果没有权限控制, 系统的功能完全不设防, 全部暴露在所有用户面前。 用户登录以后可以使用系统中的所有功能。 这是实际运行中不能接受的。

所以权限控制系统的目标就是管理用户行为, 保护系统功能。“权限” =“权力” +“限制”

1.2、如何进行权限控制

1.2.1、创建资源

资源就是系统中需要保护起来的功能。 具体形式很多: URL 地址、 handler 方法、 service 方法、 页面元素等等都可以定义为资源使用权限控制系统保护起来。

1.2.2、创建权限

一个功能复杂的项目会包含很多具体资源, 成千上万都有可能。 这么多资源逐个进行操作太麻烦了。 为了简化操作, 可以将相关的几个资源封装到一起, 打包成一个“权限” 同时分配给有需要的人。

image-20200919185753289

image-20200919185756092

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、思路

image-20200919190206852

2.2、创建角色表

  • project_crowd数据库中创建t_role

image-20200612210549071

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,修改数据库表名和实体类名

image-20200612211103927

<?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

image-20200612211317661

2.3.3、资源归位
  • 将实体类归位到entity工程下

image-20200612211630116

  • Mapper接口归位到component工程下

image-20200612211712025

  • Mapper映射文件归位到webui工程下

image-20200612211810100

2.4、创建相应组件

  • component工程下创建Service相关组件

image-20200612212051392

  • component工程下创建Handler相关组件

image-20200612212144765

2.5、Mapper层

2.5.1、编写SQL
  • RoleMapper.xml中添加如下SQL语句,根据关键词查询Role

image-20200612212841292

<select id="selectRoleByKeyword" resultMap="BaseResultMap">
	select id, name from t_role
	where name like concat("%",#{keyword},"%")
</select>
2.5.2、修改接口
  • RoleMapper.java接口中添加selectRoleByKeyword方法的声明

image-20200612212920272

List<Role> selectRoleByKeyword(String keyword);

2.6、Service层

  • Service层中,查询分页数据,并返回Pageinfo对象

image-20200612212051392

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、业务逻辑

image-20200612212144765

@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字符串是否正常

image-20200612215032945

2.9、页面准备

2.9.1、配置view-controller
  • SpringMVC配置文件中配置view-controller

image-20200612215656048

<mvc:view-controller path="/role/to/page.html" view-name="role-page"/>
2.9.2、点击跳转
  • 修改侧边栏中【角色维护】超链接

image-20200612220023417

  • 创建role-page.jsp页面,用于显示分页数据

image-20200612220805400

2.10、页面分页

2.10.1、编写JavaScript库
  • webapp目录下创建我们自己的JavaScript

image-20200612221154514

// 执行分页,生成页面效果,任何时候调用这个函数都会重新加载页面
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请求成功

image-20200612224228013

  • Ajax请求失败

image-20200612224306838

2.11、分页测试

  • 成功~

image-20200612225018367

3、关键词查询

3.1、思路

image-20200919190719553

3.2、按钮单击事件

  • 单击查询按钮,则执行分页操作,后端代码无需更改

image-20200613144735466

<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、测试

  • 乌拉~

image-20200613145036469

4、新增

4.1、思路

image-20200919190740595

4.2、引入模态框

4.2.1、新建模态框
  • WEB-INF文件夹下新建模态框modal-role-add.jsp,用于新增Role弹框

image-20200613150937774

  • 代码如下:

image-20200613151207444

<%@ 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">&times;</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页面中引入模块矿

image-20200613151429766

<%@include file="/WEB-INF/modal-role-add.jsp" %>
4.2.3、模态弹框
  • 添加JavaScript代码,点击【新增】按钮,弹出模态框

image-20200613151704111

  • 新增按钮:为了能够绑定单击事件,加上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、弹框测试
  • 乌拉~

image-20200613152101205

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中保存新增的角色

image-20200612212144765

@ResponseBody
@RequestMapping("/role/save.json")
public ResultEntity<String> saveRole(Role role) {	
    roleService.saveRole(role);	
    return ResultEntity.successWithoutData();
}
  • Service层实现上述方法

image-20200612212051392

@Override
public void saveRole(Role role) {
    roleMapper.insert(role);
}

4.4、测试

  • 乌拉~

image-20200613154221411

5、更新

5.1、思路

image-20200919190759536

5.2、更新模态框

5.2.1、新建模态框
  • WEB-INF文件夹下创建modal-role-edit.jsp模态框,更新角色弹框

image-20200613155720703

  • 页面代码

image-20200613155944952

<%@ 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">&times;</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页面引入更新角色的模态框

image-20200613161049194

<%@include file="/WEB-INF/modal-role-edit.jsp"%>

5.3、更新角色

5.3.1、前端代码
  • 准备工作:给【更新】按钮设置idclass属性,这样我们才能用JavaScript代码找到它

image-20200613162236992

// 通过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>";
  • 给【更新】按钮绑定单击响应函数:打开更新模态框,回显角色名称

image-20200613163506271

// 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);
});
  • 给模态框中的【更新】按钮绑定单击响应函数:提交修改请求

image-20200613183424206

// 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中更新角色信息

image-20200613160128313

@ResponseBody
@RequestMapping("/role/update.json")
public ResultEntity<String> updateRole(Role role) {	
    roleService.updateRole(role);
    return ResultEntity.successWithoutData();
}
  • Service层实现上述方法

image-20200613160204329

@Override
public void updateRole(Role role) {
	roleMapper.updateByPrimaryKey(role);
}

5.4、测试

  • 乌拉~

image-20200613184521220

6、删除

6.1、思路

image-20200919190850304

6.2、删除模态框

6.2.1、新建模态框
  • WEB-INF文件夹下创建modal-role-confirm.jsp模态框,删除角色时将弹出此模态框

image-20200613214052507

<%@ 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">&times;</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页面引入删除角色的模态框

image-20200613214201073

<%@include file="/WEB-INF/modal-role-confirm.jsp"%>

6.3、删除角色

6.3.1、前端代码
  • webapp下的my-role.js库中添加如下函数:弹出删除模态框,并回显要删除的角色名称

image-20200613213726764

// 声明专门的函数显示确认模态框
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标记

image-20200613160128313

@ResponseBody
@RequestMapping("/role/remove/by/role/id/array.json")
public ResultEntity<String> removeByRoleIdAarry(@RequestBody List<Integer> roleIdList) {
    roleService.removeRole(roleIdList);		
    return ResultEntity.successWithoutData();
}
  • Service层实现上述方法

image-20200613160204329

@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、测试

  • 删除单个角色

image-20200613220936846

  • 批量删除角色

image-20200613221018237

  • 未选中任何角色就点击删除

image-20200613220850684

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值