尚筹网-4.Admin维护和HTTP

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进一步说明:

常用类型

  1. application/x-www-form-urlencoded

    通常是提交一个表单所产生的

  1. 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());
    }    
}
  1. 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 异步请求

两个或多个操作在各自线程里执行,互不干扰,并行推进。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容