共计 18056 个字符,预计需要花费 46 分钟才能阅读完成。
前言
本文是基于单体架构实现的角色的增删改查的性能。前台应用 Bootstrap+Ajax+Jsp , 后端应用 Spring+SpringMvc+MyBatis 进行开发,置信应用过这些技术的小伙伴应该很好的了解以下的内容,也心愿看了这篇文章小伙伴们有所播种。
筹备工作
后端技术
技术 | 阐明 | 官网 |
---|---|---|
Spring | Spring 是一个轻量级管制反转 (IoC) 和面向切面 (AOP) 的容器框架。 | https://spring.io/ |
SpringMvc | MVC 框架 | https://spring.io/projects/sp… |
MyBatis | 长久层框架 | https://mybatis.org/mybatis-3… |
Druid | 数据库连接池 | https://github.com/alibaba/druid |
log4j | 日志框架 | https://logging.apache.org/lo… |
前端技术
Bootstrap | 简洁、直观、强悍的前端开发框架 | https://www.bootcss.com/ |
Ajax | 前后端交互 | https://www.w3school.com.cn/a… |
Jsp | 模板引擎 | https://www.runoob.com/jsp/js… |
layer.js | 音讯提醒 | http://www.h-ui.net/lib/layer… |
Modal 插件 | 模态框(Modal)是笼罩在父窗体上的子窗体 | https://www.runoob.com/bootst… |
jquery.pagination.js | 分页插件 | http://www.jq22.com/yanshi5697/ |
角色保护 - 分页实现
分页前端性能实现
创立内部 JavaScript 源文件,role.js
在页面 role-page.jsp 引入 role.js 文件
<script type="text/javascript" src="script/my-role.js"></script>
初始化全局函数
分页实现初始化全局函数,每页的条数,页码,含糊查问的关键词
// 初始化全局变量 | |
function initGlobalVariable() { | |
window.pageSize = 5; // 每页的条数 | |
window.pageNum = 1; // 页码 | |
window.keyword = ""; // 关键词 | |
} |
申明分页函数
// 给服务器发送申请获取分页数据(pageInfo),并在页面上显示分页成果(主体、页码导航条)function showPage() { | |
// 给服务器发送申请获取分页数据:PageInfo | |
var pageInfo = getPageInfo(); | |
// 在页面上的表格中 tbody 标签内显示分页的主体数据 | |
generateTableBody(pageInfo); | |
// 在页面上的表格中 tfoot 标签内显示分页的页码导航条 | |
initPagination(pageInfo); | |
} |
获取分页数据
function getPageInfo() {// 以同步申请形式调用 $.ajax()函数并获取返回值(返回值蕴含全副响应数据)var ajaxResult = $.ajax({ | |
"url": "role/search/by/keyword.action", | |
"type": "post", | |
"data": {"pageNum": (window.pageNum == undefined) ? 1 : window.pageNum, | |
"pageSize": (window.pageSize == undefined) ? 5 : window.pageSize, | |
"keyword": (window.keyword == undefined) ? "" : window.keyword | |
}, | |
"dataType": "json", | |
"async": false // 为了保障 getPageInfo()函数可能在 Ajax 申请拿到响应后获取 PageInfo,须要设置为同步操作}); | |
// 从全副响应数据中获取 JSON 格局的响应体数据 | |
var resultEntity = ajaxResult.responseJSON; | |
// 从响应体数据中获取 result,判断以后申请是否胜利 | |
var result = resultEntity.result; | |
// 如果胜利获取 PageInfo | |
if (result == "SUCCESS") {return resultEntity.data;} | |
if (result == "FAILED") {layer.msg(resultEntity.message); | |
} | |
return null; | |
} |
应用 PageInfo 数据在 tbody 标签内显示分页数据
function generateTableBody(pageInfo) { | |
// 执行所有操作前先清空 | |
$("#roleTableBody").empty(); // 这个对应页面的 <tbody id="roleTableBody"> </tbody> | |
// 获取数据汇合 | |
var list = pageInfo.list; | |
// 判断 list 是否无效 | |
if (list == null || list.length == 0) {$("#roleTableBody").append("<tr><td colspan='4'style='text-align:center;'> 没有查问到数据!</td></tr>"); | |
return; | |
} | |
for (var i = 0; i < list.length; i++) {var role = list[i]; | |
var checkBtn = "<button type='button'class='btn btn-success btn-xs'><i class=' glyphicon glyphicon-check'></i></button>"; | |
var pencilBtn = "<button type='button'id='roleTableBody'roleid='" + role.id + "'class='btn btn-primary btn-xs editBtn'><i class=' glyphicon glyphicon-pencil'></i></button>"; | |
var removeBtn = "<button type='button'roleid='" + role.id + "'class='btn btn-danger btn-xs removeBtn'><i class=' glyphicon glyphicon-remove'></i></button>"; | |
var numberTd = "<td>" + (i + 1) + "</td>"; | |
var checkBoxTd = "<td><input class='itemBox'roleid='" + role.id + "'type='checkbox'></td>"; | |
var roleNameTd = "<td>" + role.name + "</td>"; | |
var btnTd = "<td>" + checkBtn + "" + pencilBtn +" "+ removeBtn +"</td>"; | |
var tr = "<tr>" + numberTd + checkBoxTd + roleNameTd + btnTd + "</tr>"; | |
// 将后面拼好的 HTML 代码追加到 #roleTableBody 中 | |
$("#roleTableBody").append(tr); | |
} | |
} |
申明函数封装导航条初始化操作
function initPagination(pageInfo) { | |
// 申明变量存储分页导航条显示时的属性设置 | |
var paginationProperties = { | |
num_edge_entries: 3, // 边缘页数 | |
num_display_entries: 5, // 主体页数 | |
callback: pageselectCallback, // 回调函数 | |
items_per_page: window.pageSize, // 每页显示数据数量,就是 pageSize | |
current_page: (window.pageNum - 1),// 当前页页码 | |
prev_text: "上一页", // 上一页文本 | |
next_text: "下一页" // 下一页文本 | |
}; | |
// 显示分页导航条 <div id="Pagination" class="pagination"> <!-- 这里显示分页 --> </div> | |
$("#Pagination").pagination(pageInfo.total, paginationProperties); | |
} |
在每一次点击“上一页”、“下一页”、“页码”时执行这个函数跳转页面
function pageselectCallback(pageIndex, jq) { | |
// 将全局变量中的 pageNum 批改为最新值 | |
// pageIndex 从 0 开始,pageNum 从 1 开始 | |
window.pageNum = pageIndex + 1; | |
// 调用分页函数从新执行分页 | |
showPage(); | |
return false; | |
} |
页面初始化, 就是咱们点击角色保护页面须要加载的内容
$(function(){ | |
// 调用分页参数初始化办法 | |
initGlobalVariable(); | |
// 执行分页 | |
showPage();}); |
关键词查问性能
在点击“查问”按钮后,获取文本框中填写的 keyword 值,赋值给全局变量 keyword,调用 showPage()函数即可。
// 关键字查问实现 | |
$("#searchBtn").click(function () { | |
// 获取关键字查问的值 | |
var keywordInput = $.trim($("#keywordInput").val()); | |
/*if (keywordInput==null || keywordInput==""){layer.msg("请输出关键词"); | |
return; | |
}*/ | |
window.keyword = keywordInput; | |
// 执行查问操作 | |
showPage();}); |
分页后端实现
点击角色保护加载页面数据两种思路:
第一种是咱们申请后盾把查问到的数据放到 Model, 前台遍历把数据展现进去。
第二种是咱们申请后盾把查问到的数据当 PageInfo<Role>,而后动静的拼接把数据展现到页面上。(咱们采纳第二种)
Controller 办法的实现
@ResponseBody | |
@RequestMapping("/role/search/by/keyword") | |
public ResultEntity<PageInfo<Role>> search(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum, | |
@RequestParam(value = "pageSize", defaultValue = "5") Integer pageSize, | |
@RequestParam(value = "keyword", defaultValue = "") String keyword) { | |
// 1. 查问失去 PageInfo 对象 | |
PageInfo<Role> pageInfo = roleService.queryForKeywordWithPage(pageNum, pageSize, keyword); | |
// 2. 封装后果对象返回 | |
return ResultEntity.successWithData(pageInfo); | |
} |
Service 办法的实现
public PageInfo<Role> queryForKeywordWithPage(Integer pageNum, Integer pageSize, String keyword) { | |
// 1. 开启分页性能 | |
PageHelper.startPage(pageNum, pageSize); | |
// 2. 执行查问 | |
List<Role> list = roleMapper.selectForKeywordSearch(keyword); | |
// 3. 封装为 PageInfo 对象 | |
return new PageInfo<Role>(list); | |
} |
Mapper 办法的实现
List<Role> selectForKeywordSearch(String keyword);
Mapper.xml
<select id="selectForKeywordSearch" resultMap="BaseResultMap"> | |
SELECT | |
id, | |
`name` | |
FROM | |
t_role | |
WHERE | |
`name` LIKE CONCAT('%', #{keyword}, '%') | |
</select> |
角色保护 - 全选性能
性能在页面的地位
具体实现
标记
role-page.jsp
<thead> | |
<tr> | |
<th width="30">#</th> | |
<th width="30"><input id="summaryBox" type="checkbox"></th> | |
<th> 名称 </th> | |
<th width="100"> 操作 </th> | |
</tr> | |
</thead> |
my-role.js
for (var i = 0; i < list.length; i++) { | |
// 省略 | |
var checkBoxTd = "<td><input class='itemBox'roleid='" + role.id + "'type='checkbox'></td>"; | |
// 省略 | |
} |
给 summaryBox 绑定单击响应函数
// 全选 / 全不选性能实现 | |
$("#summaryBox").click(function () { | |
// 获取以后的选中状态 | |
var currentStatus = this.checked; | |
$(".itemBox").prop("checked", currentStatus); | |
}); |
角色保护 - 批量删除
筹备模态框
先筹备模态框的 HTML 标签,include-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"> | |
<p> 您确定要删除上面的显示的内容吗?</p> | |
<table class="table table-bordered"> | |
<thead> | |
<tr> | |
<th width="30">#</th> | |
<th> 名称 </th> | |
</tr> | |
</thead> | |
<tbody id="confirmModalTableBody"></tbody> | |
</table> | |
</div> | |
<div class="modal-footer"> | |
<button id="confirmModalBtn" type="button" class="btn btn-primary">OK</button> | |
</div> | |
</div> | |
</div> | |
</div> |
在 role-page.jsp 中蕴含 include-modal-role-confirm.jsp 文件,<%@ include file=”/WEB-INF/include-modal-role-confirm.jsp” %>
getRoleListByRoleIdArray()函数
//id 查问角色信息 | |
function getRoleListByRoleIdArray(roleIdArray) { | |
//roleIdArray 转换成 JSON 字符串 | |
var roleIds = JSON.stringify(roleIdArray); | |
var ajaxResult = $.ajax({ | |
"url": "role/get/list/by/id/list.action", | |
"type": "post", | |
"data": roleIds, | |
"contentType": "application/json;charset=UTF-8", | |
"dataType": "json", | |
"async": false | |
}); | |
// 3. 获取 JSON 对象类型的响应体 | |
var resultEntity = ajaxResult.responseJSON; | |
var result = resultEntity.result; | |
if (result == "SUCCESS") { | |
// 5. 如果胜利,则返回 roleList | |
return resultEntity.data; | |
} | |
if (result == "FAILED") {layer.msg(resultEntity.message); | |
return null; | |
} | |
return null; | |
} |
对应的后端代码:
@ResponseBody | |
@RequestMapping("role/get/list/by/id/list") | |
public ResultEntity<List<Role>> getRoleListByIdList(@RequestBody List<Integer> roleIds) {List<Role> roleList = roleService.findRoleListByIdList(roleIds); | |
return ResultEntity.successWithData(roleList); | |
} |
public List<Role> findRoleListByIdList(List<Integer> roleIds) {return roleMapper.findRoleListByIdList(roleIds); | |
} |
showRemoveConfirmModal()函数
// 关上删除确认模态框 | |
function showRemoveConfirmModal() { | |
// 1. 将模态框显示进去 | |
$("#confirmModal").modal("show"); | |
// 获取角色数据 | |
var roleList = getRoleListByRoleIdArray(window.roleIdArray); | |
// 清空表格数据 | |
$("#confirmModalTableBody").empty(); | |
// 填充 confirmModalTableBody 的数据 | |
for (var i = 0; i < roleList.length; i++) { | |
// 5. 获取角色相干数据 | |
var role = roleList[i]; | |
var id = role.id; | |
var name = role.name; | |
var trHTML = "<tr><td>" + (i+1) + "</td><td>" + name + "</td></tr>"; | |
// 6. 执行填充 | |
$("#confirmModalTableBody").append(trHTML); | |
} | |
} |
点击批量删除按钮绑定单击响应函数
标记批量删除按钮
<button type="button" class="btn btn-danger" id="batchRemoveBtn" | |
style="float: right; margin-left: 10px;"> | |
<i class="glyphicon glyphicon-remove"></i> 删除 | |
</button> |
查看 itemBox 是否被选中
// 给批量删除按钮绑定单击响应函数 | |
$("#batchRemoveBtn").click(function () { | |
// 获取被选中的 itemBox 数组长度 | |
var length = $(".itemBox:checked").length; | |
if (length == 0) {layer.msg("请抉择要删除的记录!!"); | |
return; | |
} | |
// 未完待续... | |
}); |
在弹出的模态框中显示 confirm 信息
// 给批量删除按钮绑定单击响应函数 | |
$("#batchRemoveBtn").click(function () { | |
// 获取被选中的 itemBox 数组长度 | |
var length = $(".itemBox:checked").length; | |
if (length == 0) {layer.msg("请抉择要删除的记录!!"); | |
return; | |
} | |
window.roleIdArray = new Array(); | |
// 遍历复选框 | |
$(".itemBox:checked").each(function () { | |
// 通过 checkbox 的 roleid 属性获取 roleId 值 | |
var roleId = $(this).attr("roleid"); | |
// 存入数组 | |
window.roleIdArray.push(roleId); | |
}); | |
// 调用函数关上模态框 | |
showRemoveConfirmModal();}); |
点击模态框的 OK 按钮执行删除
标记 OK 按
<button **id="confirmModalBtn"** type="button" class="btn btn-primary">OK</button>
绑定单击响应函数
$("#confirmModalBtn").click(function () { | |
// 数组转成 Json | |
var roleIds = JSON.stringify(window.roleIdArray); | |
var ajaxResult = $.ajax({ | |
"url": "role/batch/remove.action", | |
"type": "post", | |
"data": roleIds, | |
"contentType": "application/json;charset=UTF-8", | |
"dataType": "json", | |
"async": false, | |
"success": function (response) { | |
var result = response.result; | |
if (result == "SUCCESS") {layer.msg("操作胜利!"); | |
// 如果删除胜利,则从新调用分页办法 | |
showPage();} | |
if (result == "FAILED") {layer.msg(response.message); | |
} | |
// 不论胜利还是失败,都须要关掉模态框 | |
$("#confirmModal").modal("hide"); | |
}, | |
"error": function (response) {if (result == "FAILED") {layer.msg(response.message); | |
} | |
} | |
}); | |
}); |
后端代码
@ResponseBody | |
@RequestMapping(value = "role/batch/remove") | |
public ResultEntity<String> batchAdminList(@RequestBody List<Integer> roleIds) { | |
try {roleService.batchRoleList(roleIds); | |
return ResultEntity.successWithoutData();} catch (Exception e) {return ResultEntity.failed(null, e.getMessage()); | |
} | |
} |
public void batchRoleList(List<Integer> roleIds) {roleMapper.batchRoleList(roleIds); | |
} |
<delete id="batchRoleList" parameterType="java.util.List"> | |
delete from t_role where id in | |
<foreach collection="list" item="item" open="(" separator="," close=")" > | |
#{item} | |
</foreach> | |
</delete> |
角色保护 - 新增
大体步骤
- 给“新增”按钮绑定单击响应函数
- 关上模态框
- 给“保留”按钮绑定单击响应函数
- 收集文本框内容
- 发送申请
- 申请解决实现敞开模态框、从新分页、清理表单
给新增按钮绑定单击响应函数
标记新增按钮
<button type="button" class="btn btn-primary" id="addBtn" | |
style="float: right;"> | |
<i class="glyphicon glyphicon-plus"></i> 新增 | |
</button> |
绑定单击响应函数
$("#addBtn").click(function(){alert("aaa..."); });
筹备模态框
先筹备模态框的 HTML 代码,include-modal-role-add.jsp
<%@ 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"> | |
<form role="form"> | |
<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"> | |
<input type="text" id="roleNameInput" class="form-control" placeholder="请输出角色名称" /> | |
</div> | |
<div class="modal-footer"> | |
<button type="button" id="addModalBtn" class="btn btn-default"><i class="glyphicon glyphicon-plus"></i> 保留 </button> | |
<button type="reset" class="btn btn-primary"><i class="glyphicon glyphicon-refresh"></i> 重置 </button> | |
</div> | |
</form> | |
</div> | |
</div> | |
</div> |
将 include-modal-role-add.jsp 蕴含到 role-page.jsp , <%@ include file=”/WEB-INF/include-modal-role-add.jsp” %>
关上模态框
$("#addBtn").click(function(){$("#addModal").modal("show"); });
给“保留”按钮绑定单击响应函数
标记“保留”按钮
<button id="addModalBtn" type="button" class="btn btn-success"> <i class="glyphicon glyphicon-plus"></i> 保留 </button>
绑定单击响应函数
$("#addModalBtn").click(function () { | |
// 1. 收集文本框内容 | |
var roleName = $.trim($("#roleNameInput").val()); | |
if (roleName == null || roleName == "") {layer.msg("请输出无效角色名称!"); | |
return; | |
} | |
// 2. 发送申请 | |
$.ajax({ | |
"url": "role/save/role.action", | |
"type": "post", | |
"data": {"roleName": roleName}, | |
"dataType": "json", | |
"success": function (response) { | |
var result = response.result; | |
if (result == "SUCCESS") {layer.msg("操作胜利!"); | |
// 3. 操作胜利从新分页 | |
// 返回最初一页 | |
window.pageNum = 999999; | |
showPage();} | |
if (result == "FAILED") {layer.msg(response.message); | |
} | |
// 4. 不论胜利还是失败,敞开模态框 | |
$("#addModal").modal("hide"); | |
// 5. 清理本次在文本框填写的数据 | |
$("#roleNameInput").val(""); | |
}, | |
"error": function (response) {layer.msg(response.message); | |
} | |
}); | |
}); |
后端局部代码
@ResponseBody | |
@RequestMapping("role/save/role") | |
public ResultEntity<String> saveRole(@RequestParam("roleName") String roleName) { | |
try {roleService.saveRole(roleName); | |
return ResultEntity.successWithoutData();} catch (Exception e) {return ResultEntity.failed(null, e.getMessage()); | |
} | |
} |
公共返回代码
public class ResultEntity<T> { | |
public static final String SUCCESS = "SUCCESS"; | |
public static final String FAILED = "FAILED"; | |
public static final String NO_MESSAGE = "NO_MESSAGE"; | |
public static final String NO_DATA = "NO_DATA"; | |
// 不便返回胜利后果(不携带查问后果状况)public static ResultEntity<String> successWithoutData() {return new ResultEntity<String>(SUCCESS, NO_MESSAGE, NO_DATA); | |
} | |
// 不便返回胜利后果(携带查问后果状况)public static <E> ResultEntity<E> successWithData(E data) {return new ResultEntity<E>(SUCCESS, NO_MESSAGE, data); | |
} | |
// 不便返回失败后果 | |
public static <E> ResultEntity<E> failed(E data, String message) {return new ResultEntity<E>(FAILED, message, data); | |
} | |
private String result; | |
private String message; | |
private T data; | |
public ResultEntity() {} | |
public ResultEntity(String result, String message, T data) {super(); | |
this.result = result; | |
this.message = message; | |
this.data = data; | |
} | |
@Override | |
public String toString() {return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]"; | |
} | |
public String getResult() {return result;} | |
public void setResult(String result) {this.result = result;} | |
public String getMessage() {return message;} | |
public void setMessage(String message) {this.message = message;} | |
public T getData() {return data;} | |
public void setData(T data) {this.data = data;} | |
} |
角色保护 - 更新
大体步骤
给编辑按钮绑定单击响应函数
关上模态框
- 筹备模态框
- 把 roleId 保留到全局变量
- 获取到以后按钮所在行的 roleName
- 应用 roleName 回显模态框中的表单
- 给“更新”按钮绑定单击响应函数
- 收集文本框内容
- 发送申请
- 申请解决实现敞开模态框、从新分页
给编辑按钮绑定单击响应函数
标记编辑按钮
my-role.js 文件
function generateTableBody(pageInfo) { | |
// 省略 | |
var pencilBtn = "<button type='button'roleid='" + role.id + "'class='btn btn-primary btn-xs editBtn'><i class=' glyphicon glyphicon-pencil'></i></button>"; | |
// 省略 | |
} | |
} |
筹备模态框
<%@ 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"> | |
<form role="form"> | |
<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"> | |
<input type="text" id="roleNameInputEdit" class="form-control" | |
placeholder="请输出角色名称" /> | |
</div> | |
<div class="modal-footer"> | |
<button id="editModalBtn" type="button" class="btn btn-warning"> | |
<i class="glyphicon glyphicon-edit"></i> 更新 | |
</button> | |
<button type="reset" class="btn btn-primary"> | |
<i class="glyphicon glyphicon-refresh"></i> 重置 | |
</button> </div> | |
</form> | |
</div> | |
</div> | |
</div> |
将 include-modal-role-add.jsp 蕴含到 role-page.jsp , <%@ include file=”/WEB-INF/include-modal-role-edit.jsp” %>
绑定单击响应函数
$("#roleTableBody").on("click", ".editBtn", function () { | |
// 1. 获取以后按钮的 roleId | |
window.roleId = $(this).attr("roleId"); | |
// 2. 获取以后按钮所在行的 roleName | |
var roleName = $(this).parents("tr").children("td:eq(2)").text(); | |
// 3. 批改模态框中文本框的 value 值,目标是在显示 roleName | |
$("#roleNameInputEdit").val(roleName); | |
// 4. 关上模态框 | |
$("#editModal").modal("show"); | |
}); |
给“更新”按钮绑定单击响应函数
$("#editModalBtn").click(function () { | |
// 1. 获取文本框值 | |
var roleName = $.trim($("#roleNameInputEdit").val()); | |
if (roleName == null || roleName == "") {layer.msg("请输出无效角色名称!"); | |
return; | |
} | |
// 2. 发送申请 | |
$.ajax({ | |
"url": "role/update.action", | |
"type": "post", | |
"data": { | |
"id": window.roleId, | |
"name": roleName | |
}, | |
"dataType": "json", | |
"success": function (response) { | |
var result = response.result; | |
if (result == "SUCCESS") {layer.msg("操作胜利!"); | |
// 3. 操作胜利从新分页 | |
showPage();} | |
if (result == "FAILED") {layer.msg(response.message); | |
} | |
// 4. 不论胜利还是失败,敞开模态框 | |
$("#editModal").modal("hide"); | |
} | |
}); | |
}); |
后端局部代码
@ResponseBody | |
@RequestMapping("role/update") | |
public ResultEntity<String> updateRole(@RequestParam("id") Integer id, | |
@RequestParam("name") String name) {Role role = new Role(); | |
role.setId(id); | |
role.setName(name); | |
try {roleService.updateRole(role); | |
return ResultEntity.successWithoutData();} catch (Exception e) {return ResultEntity.failed(null, e.getMessage()); | |
} | |
} |
异样映射兼容异步申请
问题体现
Ajax 申请在服务器端处理过程中抛出异样,通过异样处理器:
@ControllerAdvice | |
public class CrowdFundingExceptionResolever {@ExceptionHandler(value=Exception.class) | |
public ModelAndView catchException(Exception exception) {ModelAndView mav = new ModelAndView(); | |
mav.addObject("exception", exception); | |
mav.setViewName("system-error"); | |
return mav; | |
} | |
} |
目前这个异样解决机制,只能返回页面,而不能针对 Ajax 申请返回 JSON 格局的响应数据。所以 Ajax 申请处理过程中,如果抛出异样,返回异样信息页面,Ajax 程序无奈失常解析,导致页面不能失常显示和工作,也不能给出敌对的谬误提醒。
问题解决思路
异步申请特点
分辨异步申请的工具办法
/** | |
* 用于判断一个申请是否是异步申请 | |
* @param request | |
* @return | |
*/ | |
public static boolean checkAsyncRequest(HttpServletRequest request) { | |
// 1. 获取相应申请音讯头 | |
String accept = request.getHeader("Accept"); | |
String xRequested = request.getHeader("X-Requested-With"); | |
// 2. 判断申请音讯头数据中是否蕴含指标特色 | |
if((stringEffective(accept) && accept.contains("application/json")) | |
|| | |
(stringEffective(xRequested) && xRequested.contains("XMLHttpRequest")) ) {return true;} | |
return false; | |
} | |
/** | |
* 判断字符串是否无效 | |
* @param source 待验证字符串 | |
* @return true 示意无效,false 示意有效 | |
*/ | |
public static boolean stringEffective(String source) {return source != null && source.length() > 0; | |
} |
降级后的异样处理器
首先引入:
<dependency> | |
<groupId>com.google.code.gson</groupId> | |
<artifactId>gson</artifactId> | |
<version>2.8.5</version> | |
</dependency> |
@ControllerAdvice | |
public class CrowdFundingExceptionResolever {@ExceptionHandler(value = Exception.class) | |
public ModelAndView catchException( | |
Exception exception, | |
HttpServletRequest request, | |
HttpServletResponse response) throws IOException { | |
// 1. 对以后申请进行查看 | |
boolean checkAsyncRequestResult = CrowdFundingUtils.checkAsyncRequest(request); | |
// 2. 如果是异步申请 | |
if(checkAsyncRequestResult) { | |
// 依据异样类型在常量中的映射,应用比拟敌对的文字显示谬误提醒音讯 | |
String exceptionClassName = exception.getClass().getName(); | |
String message = CrowdFundingConstant.EXCEPTION_MESSAGE_MAP.get(exceptionClassName); | |
if(message == null) {message = "零碎未知谬误";} | |
// 3. 创立 ResultEntity 对象 | |
ResultEntity<String> resultEntity = ResultEntity.failed(ResultEntity.NO_DATA, message); | |
// 4. 将 resultEntity 转换为 JSON 格局 | |
Gson gson = new Gson(); | |
String json = gson.toJson(resultEntity); | |
// 5. 将 json 作为响应数据返回给浏览器 | |
response.setContentType("application/json;charset=UTF-8"); | |
response.getWriter().write(json); | |
return null; | |
} | |
ModelAndView mav = new ModelAndView(); | |
mav.addObject("exception", exception); | |
mav.setViewName("system-error"); | |
return mav; | |
} | |
} |
常量类
public class CrowdFundingConstant {public static final Map<String, String> EXCEPTION_MESSAGE_MAP = new HashMap<String, String>(); | |
static {EXCEPTION_MESSAGE_MAP.put("java.lang.ArithmeticException", "零碎在进行数学运算时产生谬误"); | |
EXCEPTION_MESSAGE_MAP.put("java.lang.RuntimeException", "零碎在运行时产生谬误"); | |
EXCEPTION_MESSAGE_MAP.put("com.atguigu.crowd.funding.exception.LoginException", "登录过程中运行谬误"); | |
} | |
} |
我是阿福,公众号「阿福聊编程」作者,对后端技术放弃学习爱好者,我会常常更新 JAVA 技术文章,在进阶的路上,共勉!