1. 用户维护-单条删除
1.1 给单条删除按钮绑定单击响应函数
使用class属性标记多个元素。admin-page.jsp
<button adminId="${admin.id }" type="button" class="btn btn-danger btn-xs uniqueRemoveBtn">
<i class=" glyphicon glyphicon-remove"></i>
</button>
给class为uniqueRemoveBtn的按钮绑定单击响应函数
// 给单条删除按钮绑定单击响应函数
$(".uniqueRemoveBtn").click(function(){
// 获取当前adminId值
var adminId = $(this).attr("adminId");
// 获取当前记录的loginAcct
var loginAcct = $(this).parents("tr").children("td:eq(2)").text();
var confirmResult = confirm("您真的要删除"+loginAcct+"这条记录吗?");
if(!confirmResult) {
return ;
}
// 为了能够使用批量删除的操作,将adminId存入数组
var adminIdArray = new Array();
adminIdArray.push(adminId);
// 调用专门封装的函数,执行批量删除
doBatchRemove(adminIdArray);
});
1.2 专门封装执行批量删除的函数
这个函数同时根据传入的数组不同,既可以批量删除也可以单条删除
// 封装执行批量删除的函数
function doBatchRemove(adminIdArray) {
// 将JSON数组转换为JSON字符串
// var a = [1,2,3,4,5]; 数组类型
// var b = "[1,2,3,4,5]"; 字符串类型
// var c = {"userName":"tom"}; 对象类型
// var d = "{\"userName\":\"tom\"}"; 字符串类型
// 发送Ajax请求执行批量删除
var requestBody = JSON.stringify(adminIdArray);
// 发送Ajax请求将adminIdArray发送给handler方法
$.ajax({
"url":"admin/batch/remove.json", // 服务器端接收请求的URL地址
"type":"post", // 设置请求方式为POST
"contentType":"application/json;charset=UTF-8", // 设置请求体内容类型,告诉服务器当前请求体发送的是JSON数据
"data":requestBody, // 请求体真正要发送给服务器的数据
"dataType":"json", // 把服务器端返回的数据当作JSON格式解析
"success":function(response) { // 服务器处理请求成功后执行的函数,响应体以参数形式传入当前函数
console.log(response);
var result = response.result;
if(result == "SUCCESS") {
// 跳转页面
window.location.href = "admin/query/for/search.html?pageNum=${requestScope['PAGE-INFO'].pageNum}&keyword=${param.keyword}";
}
if(result == "FAILED") {
alert(response.message);
return ;
}
},
"error":function(response) { // 服务器处理请求失败后执行的函数,响应体以参数形式传入当前函数
alert(response.message);
return ;
}
});
2. 将目前为止所有另外声明的函数提取到外部JS文件中
2.1 创建JavaScript文件
- 所在工程:atcrowdfunding-admin-1-webui
- 文件位置:/atcrowdfunding-admin-1-webui/src/main/webapp/script/my-admin.js
2.2 原本EL表达式处理
EL表达式不能出现在JavaScript文件中,需要额外以参数形式传入。
2.3 将pageNum和keyword放在全局变量范围统一维护
目的:让pageNum和keyword实现一处修改,处处生效。需要使用pageNum和keyword值的操作直接从全局变量范围读取即可。
admin-page.jsp
$(function () {
// 初始化全局变量
window.totalRecord = ${requestScope['PAGE-INFO'].total};
window.pageSize = ${requestScope['PAGE-INFO'].pageSize};
window.pageNum = ${requestScope['PAGE-INFO'].pageNum};
// 每一次页面最初显示的时候都会把keyword设置为最新值
window.keyword = "${param.keyword}";
my-admin.js
//对分页导航条显示进行初始化
function initPagination() {
//声明变量存储总记录数
//var totalRecord = ${requestScope['PAGE-INFO'].total};
//声明遍历存储分页导航条显示时的属性设置
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:"下一页"//下一页文本
}
// 显示分页的导航条
$("#Pagination").pagination(window.totalRecord, paginationProperties);
}
//在每一次点击"上一页","下一页","页码"时执行这个函数跳转页面
function pageselectCallback(pageIndex, jq) {
//pageIndex从0开始,pageNum从1开始
window.pageNum = pageIndex+1;
//跳转页面
window.location.href="admin/query/for/search.html?pageNum="+(pageIndex+1)+"&keyword="+window.keyword;
return false;
}
//封装执行批量删除的函数
function doBatchRemove(adminIdArray) {
//发送ajax请求执行批量删除
var requestBody = JSON.stringify(adminIdArray);
//发送ajax请求将adminIdArray发送给handler方法
$.ajax({
"url":"admin/batch/remove.json",//服务端接收请求的URL地址
"type":"post",//设置请求方式为post
"contentType":"application/json;charset=UTF-8",//设置请求体内容类型,告诉服务器发的是JSON数据
"data":requestBody,//请求体真正要发送的数据
"success":function (response) {//服务器处理请求成功后的函数,响应体以参数形式传入当前函数
console.log(response);
var result = response.result;
//跳转页面
if(result == "SUCCESS"){
window.location.href = "admin/query/for/search.html?pageNum="+window.pageNum+"&keyword="+window.keyword;
}
//
if(result == "FAILED"){
alert(response.message);
return;
}
},
"error":function (response) {
alert(response.message);
}
})
}
2.4 在JSP页面上引入外部JavaScript文件
<script type="text/javascript" src="script/my-admin.js"></script>
注意:使用script标签引入外部JavaScript文件需要注意引入的顺序。
如果a.js文件中用到了b.js文件中的函数,那么引入是顺序应该是:b前,a后
3. 用户维护-新增操作
3.1 给t_admin表的login_acct字段添加唯一约束
ALTER TABLE `t_admin`
ADD UNIQUE INDEX (`login_acct`)
3.2 流程分析
3.3 跳转到新增表单页面
3.3.1 把新增按钮改成超链接
admin-page.jsp
修改前
<button type="button" class="btn btn-primary"style="float: right;" onclick="window.location.href='add.html'">
<i class="glyphicon glyphicon-plus"></i> 新增
</button>
修改后
<a href="admin/to/add/page.html" class="btn btn-primary" style="float: right;"><i class="glyphicon glyphicon-plus"></i> 新增</a>
3.3.2 view-controller配置
spring-web-mvc.xml
<mvc:view-controller path="/admin/to/add/page.html" view-name="admin-add"/>
3.3.3 创建admin-add.jsp
面包屑部分
<ol class="breadcrumb">
<li><a href="admin/to/main/page.html">首页</a></li>
<li><a href="admin/query/for/search.html">数据列表</a></li>
<li class="active">新增</li>
</ol>
表单部分
<form action="admin/save.html" method="post" role="form">
<div class="form-group">
<label for="exampleInputPassword1">登录账号</label>
<input
type="text"
name="loginAcct"
class="form-control"
id="exampleInputPassword1"
placeholder="请输入登陆账号"/>
</div>
<div class="form-group">
<label for="exampleInputPassword1">登录密码</label>
<input
type="text"
name="userPswd"
class="form-control"
id="exampleInputPassword1"
placeholder="请输入用户名称"/>
</div>
<div class="form-group">
<label for="exampleInputPassword1">用户昵称</label>
<input
type="text"
name="userName"
class="form-control"
id="exampleInputPassword1"
placeholder="请输入用户名称"/>
</div>
<div class="form-group">
<label for="exampleInputEmail1">邮箱地址</label>
<input
type="email"
name="email"
class="form-control"
id="exampleInputEmail1"
placeholder="请输入邮箱地址"/>
</div>
<button type="submit" class="btn btn-success">
<i class="glyphicon glyphicon-plus"></i> 新增
</button>
<button type="reset" class="btn btn-danger">
<i class="glyphicon glyphicon-refresh"></i> 重置
</button>
</form>
3.4 执行保存操作
3.4.1 handler方法
- 工程目录:atcrowdfunding-admin-2-component
- 全类名:com.rgh.crowd.funding.handler.AdminHandler
// 使用Admin实体类对象封装表单提交的请求参数,具体每一个请求参数会通过对应的setXxx()方法注入实体类
@RequestMapping("/admin/save")
public String saveAdmin(Admin admin) {
adminService.saveAdmin(admin);
return "redirect:/admin/query/for/search.html";
}
3.4.2 service方法
- 工程目录:atcrowdfunding-admin-2-component
- 全类名:com.rgh.crowd.funding.service.impl.AdminServiceImpl
@Override
public void saveAdmin(Admin admin) {
// 对密码进行加密
String userPswd = admin.getUserPswd();
userPswd = CrowdFundingUtils.md5(userPswd);
admin.setUserPswd(userPswd);
// 执行保存
adminMapper.insert(admin);
}
3.4.3 转换抛出的异常
- 工程目录:atcrowdfunding-admin-2-component
- 全类名:com.rgh.crowd.funding.handler.AdminHandler
// 使用Admin实体类对象封装表单提交的请求参数,具体每一个请求参数会通过对应的setXxx()方法注入实体类
@RequestMapping("/admin/save")
public String saveAdmin(Admin admin) {
try {
adminService.saveAdmin(admin);
} catch (Exception e) {
e.printStackTrace();
if(e instanceof DuplicateKeyException) {
throw new RuntimeException(CrowdFundingConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
}
}
return "redirect:/admin/query/for/search.html";
}
3.5 操作完成后立即看到新增的记录
3.5.1 方案一
跳转到分页页面时前往最后一页
return "redirect:/admin/query/for/search.html?pageNum="+Integer.MAX_VALUE;
3.5.2 方案二
分页页面显示数据时根据id降序排列
<select id="selectAdminListByKeyword" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_admin
WHERE
login_acct LIKE CONCAT("%", #{keyword}, "%")
OR user_name LIKE CONCAT("%", #{keyword}, "%")
OR email LIKE CONCAT("%", #{keyword}, "%")
order by id desc
</select>
4. 用户维护-更新操作
4.1 操作流程
4.2 跳转到更新页面
4.2.1 把铅笔按钮改成超链接
修改前
<button type="button" class="btn btn-primary btn-xs">
<i class=" glyphicon glyphicon-pencil"></i>
</button>
修改后
<a href="admin/to/edit/page.html?adminId=${admin.id }&pageNum=${requestScope['PAGE-INFO'].pageNum}" class="btn btn-primary btn-xs"><i class=" glyphicon glyphicon-pencil"></i></a>
4.2.2 handler方法
- 工程目录:atcrowdfunding-admin-2-component
- 全类名:com.rgh.crowd.funding.handler.AdminHandler
@RequestMapping("/admin/to/edit/page")
public String toEditPage(@RequestParam("adminId") Integer adminId, Model model) {
Admin admin = adminService.getAdminById(adminId);
model.addAttribute("admin", admin);
return "admin-edit";
}
4.2.3 service方法
- 工程目录:atcrowdfunding-admin-2-component
- 全类名:com.rgh.crowd.funding.service.impl.AdminServiceImpl
@Override
public Admin getAdminById(Integer adminId) {
return adminMapper.selectByPrimaryKey(adminId);
}
4.2.4 创建admin-edit.jsp
引入spring的form标签
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<form:form action="admin/update.html" method="post" modelAttribute="admin">
<!-- 模型对象中包含的属性可以使用form:hidden -->
<form:hidden path="id"/>
<!-- 模型对象中没有的属性不能使用form:hidden -->
<input type="hidden" name="pageNum" value="${param.pageNum }" />
<div class="form-group">
<label for="exampleInputPassword1">登录账号</label>
<form:input path="loginAcct" cssClass="form-control"/>
</div>
<div class="form-group">
<label for="exampleInputPassword1">登录密码</label>
<form:input path="userPswd" cssClass="form-control"/>
</div>
<div class="form-group">
<label for="exampleInputPassword1">用户昵称</label>
<form:input path="userName" cssClass="form-control"/>
</div>
<div class="form-group">
<label for="exampleInputEmail1">邮箱地址</label>
<form:input path="email" cssClass="form-control"/>
</div>
<button type="submit" class="btn btn-success">
<i class="glyphicon glyphicon-edit"></i> 更新
</button>
<button type="reset" class="btn btn-danger">
<i class="glyphicon glyphicon-refresh"></i> 重置
</button>
</form:form>
4.3 执行更新
4.3.1 handler方法
- 工程目录:atcrowdfunding-admin-2-component
- 全类名:com.rgh.crowd.funding.handler.AdminHandler
@RequestMapping("/admin/update")
public String updateAdmin(Admin admin) {
try {
adminService.updateAdmin(admin);
} catch (Exception e) {
e.printStackTrace();
if(e instanceof DuplicateKeyException) {
throw new RuntimeException(CrowdFundingConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
}
}
return "redirect:/admin/query/for/search.html?pageNum="+pageNum;
}
4.3.2 service方法
- 工程目录:atcrowdfunding-admin-2-component
- 全类名:com.rgh.crowd.funding.service.impl.AdminServiceImpl
@Override
public void updateAdmin(Admin admin) {
// 对密码进行加密
String userPswd = admin.getUserPswd();
userPswd = CrowdFundingUtils.md5(userPswd);
admin.setUserPswd(userPswd);
// 执行更新
adminMapper.updateByPrimaryKey(admin);
}
5. HTTP协议复习
5.1 请求报文
5.1.1 请求行
Request URL: http://localhost:8080/atcrowdfunding-admin-1-webui/css/pagination.css
Request Method: GET
HTTP协议的版本,通常是1.1
5.1.2 请求消息头
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 132
Content-Type: application/x-www-form-urlencoded
Cookie: JSESSIONID=DBC23B26C8603DE7985C3FEC2685859E
Host: localhost:8080
Origin: http://localhost:8080
Pragma: no-cache
Referer: http://localhost:8080/atcrowdfunding-admin-1-webui/admin/to/edit/page.html?adminId=484&pageNum=5
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Content-Type进一步说明:
常用类型
-
application/x-www-form-urlencoded
通常是提交一个表单所产生的
-
application/json;charset=UTF-8
通常是发送Ajax请求,请求体整个是一个JSON数据
$.ajax({
"url":"admin/batch/remove.json", // 服务器端接收请求的URL地址
"type":"post", // 设置请求方式为POST
"contentType":"application/json;charset=UTF-8", // 设置请求体内容类型,告诉服务器当前请求体发送的是JSON数据
"data":JSON.stringify(adminIdArray), // 请求体真正要发送给服务器的数据
"dataType":"json", // 把服务器端返回的数据当作JSON格式解析
"success":function(response) { // 服务器处理请求成功后执行的函数,响应体以参数形式传入当前函数
console.log(response);
var result = response.result;
if(result == "SUCCESS") {
// 跳转页面
// window.location.href = "admin/query/for/search.html?pageNum="+window.pageNum+"&keyword="+window.keyword;
}
if(result == "FAILED") {
alert(response.message);
return ;
}
},
"error":function(response) { // 服务器处理请求失败后执行的函数,响应体以参数形式传入当前函数
alert(response.message);
return ;
}
});
这样提交的请求,handler方法接收数据需要使用@RequestBody注解
@ResponseBody
@RequestMapping("/admin/batch/remove")
public ResultEntity<String> batchRemove(@RequestBody List<Integer> adminIdList) {
try {
adminService.batchRemove(adminIdList);
return ResultEntity.successWithoutData();
}catch(Exception e) {
return ResultEntity.failed(null, e.getMessage());
}
}
-
multipart/form-data
用于文件上传
<form action="xxx" method="post" enctype="multipart/form-data"
5.1.3 请求体
请求体当前请求要发送给服务器的数据主体,GET方式没有请求体,POST方式有请求体。
传送较大数据量时使用POST方式。
5.2 响应报文
5.2.1 响应状态行
Status Code: 200 OK
- 200表示请求处理成功
- 302表示重定向
- 404表示找不到目标资源
- 50X表示服务器内部错误
5.2.2 响应消息头
Content-Type: application/json;charset=UTF-8
Set-Cookie: JSESSIONID=104DED3F5A868930A70834DEC585983B; Path=/atcrowdfunding-admin-1-webui/; HttpOnly
5.2.3 响应体
-
常见形式1:页面
通常用来响应“同步请求”
-
常见形式2:JSON数据
通常用来响应“异步请求”
6. 同步请求和异步请求
6.1 同步请求
同一个线程内部,后面操作需要等前面操作完成才能开始。
6.2 异步请求
两个或多个操作在各自线程里执行,互不干扰,并行推进。