尚筹网-3.Admin分页和批量删除

1. 修正

1.1 登录完成跳转到后台主页面改成重定向

@RequestMapping("/admin/do/login")
public String doLogin(@RequestParam("loginAcct") String loginAcct,
                      @RequestParam("userPswd")  String userPswd,
                      Model model,
                      HttpSession session){
    //调用adminService的login方法执行登陆业务逻辑,返回查询到的Admin对象
    Admin admin = adminService.login(loginAcct,userPswd);
    //判断admin是否为null
    if(admin == null){
        model.addAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE, CrowdFundingConstant.MESSAGE_LOGIN_FAILED);
        return "admin-login";
    }
    session.setAttribute(CrowdFundingConstant.ATTR_NAME_LOGIN_ADMIN,admin);
    return "redirect:/admin/to/main/page.html";
}

​ 说明:/admin/to/main/page.html地址是在view-controller中配置的。

2. 后台主页面完整显示

2.1 加入原型页面源代码

原型/main.html→admin-main.jsp

需要调整的内容:

  • 字符集改成UTF-8
  • 加入title和base标签
  • 把“张三”改成${sessionScope['LOGIN-ADMIN'].userName }
  • 把退出的超链接改成实际地址
 退出系统

2.2 公共部分提取

  • head标签部分

    <%@ include file="/WEB-INF/include-head.jsp" %>

  • nav标签部分

    <%@ include file="/WEB-INF/include-nav.jsp" %>

  • sidebar部分

    <%@ include file="/WEB-INF/include-sidebar.jsp" %>

2.3 创建JSP模版

2.3.1 模版内容

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
    
        <%@ include file="/WEB-INF/include-head.jsp" %>
            
                <%@ include file="/WEB-INF/include-nav.jsp" %>
                    
<%@ include file="/WEB-INF/include-sidebar.jsp" %>

2.3.2 创建JSP模版操作

3. Admin维护功能清单

  • 分页显示全部Admin数据√
  • 分页显示Admin数据的关键词查询结果√
  • 批量删除
  • 单条删除
  • 新增Admin
  • 更新Admin

分页显示全部数据和查询结果在后端可以合并为同一个操作。

批量删除和单条删除在后端可以合并为同一个操作。

4. 分页功能

4.1 分析

4.2 执行查询的SQL语句

SELECT
    *
FROM
    t_admin
WHERE
    login_acct LIKE CONCAT("%", "", "%")
OR user_name LIKE CONCAT("%", "", "%")
OR email LIKE CONCAT("%", "", "%");

4.3 MyBatis的PageHelper插件

4.3.1 作用

以完全非侵入的方式在原有查询基础上附加分页效果。从SQL层面来说,在SQL语句后面附加LIMIT子句。从Java代码来说,把原来返回的List类型封装为Page类型。

4.3.2 依赖信息




    com.github.pagehelper
    pagehelper
    4.0.0



    com.github.pagehelper
    pagehelper

4.3.3 配置方式

  • 所在工程:atcrowdfunding-admin-1-webui
  • 配置文件:spring-persist-mybatis.xml
  • 在SqlSessionFactoryBean中配置MyBatis插件


    
        
        
            
            
                
                    
                    mysql
                    
                    
                    true
                
            
        
    

4.4 AdminMapper

4.4.1 Mapper配置文件

  • 所在工程:atcrowdfunding-admin-1-webui
  • 文件:resources/mybatis/mapper/AdminMapper.xml

4.4.2 Mapper接口

  • 所在工程:atcrowdfunding-admin-2-component
  • 全类名:com.rgh.crowd.funding.mapper.AdminMapper
List selectAdminListByKeyword(String keyword);

4.5 AdminService

所在工程:atcrowdfunding-admin-2-component

接口方法:

PageInfo queryForKeywordSearch(Integer pageNum, Integer pageSize, String keyword);

实现类方法:

@Override
public PageInfo queryForKeywordSearch(Integer pageNum, Integer pageSize, String keyword) {
    // 1.调用PageHelper的工具方法,开启分页功能
    PageHelper.startPage(pageNum, pageSize);
    // 2.执行分页查询
    List list = adminMapper.selectAdminListByKeyword(keyword);
    // 3.将list封装到PageInfo对象中
    return new PageInfo<>(list);
}

4.6 AdminHandler

  • 所在工程:atcrowdfunding-admin-2-component
  • 全类名:com.rgh.crowd.funding.handler.AdminHandler
@RequestMapping("/admin/query/for/search")
public String queryForSearch(       
    // 如果页面上没有提供对应的请求参数,那么可以使用defaultValue指定默认值
    @RequestParam(value="pageNum", defaultValue="1") Integer pageNum, 
    @RequestParam(value="pageSize", defaultValue="5") Integer pageSize, 
    @RequestParam(value="keyword", defaultValue="") String keyword,
    Model model) {  
    PageInfo pageInfo = adminService.queryForKeywordSearch(pageNum, pageSize, keyword);
    model.addAttribute(CrowdFundingConstant.ATTR_NAME_PAGE_INFO, pageInfo);
    return "admin-page";
}

4.7 插入测试用的假数据

  • 所在工程:atcrowdfunding-admin-1-webui
  • 全类名:com.rgh.crowd.funding.test.CrowdFundingTest
@Test
public void batchSaveAdmin() {
    for(int i = 0; i < 500; i++) {
        adminMapper.insert(new Admin(null, "loginAcct"+i, "1111111", "userName"+i, "email"+i+"@qq.com", null));
    }
}

4.8 页面显示:主体部分


    
        
            抱歉!没有符合您要求的查询结果!
        
    
    
        
            
                ${myStatus.count }
                
                ${admin.loginAcct }
                ${admin.userName }
                ${admin.email }
                
                    
                    
                    
                
            
        
    

4.9 页面显示:导航条部分

使用一个基于jQuery的分页插件:Pagination


4.9.1 环境搭建

  1. 加入样式文件

    将pagination.css复制到/atcrowdfunding-admin-1-webui/src/main/webapp/css目录下
    
  2. 在需要的页面引用pagination.css

    在admin-page.jsp中引入

    
    
  3. 加入Pagination的js文件

    将jquery.pagination.js复制到/atcrowdfunding-admin-1-webui/src/main/webapp/script目录下
    
  4. 在需要的页面引用jquery.pagination.js

    
    

4.9.2 分页导航条需要在HTML标签中加入的部分


    
        
            
        
    

4.9.3 jQuery代码

$(function() {
    
    // 对分页导航条显示进行初始化
    initPagination();
    
});
// 声明函数封装导航条初始化操作
function initPagination() { 
    // 声明变量存储总记录数
    var totalRecord = ${requestScope['PAGE-INFO'].total};
    // 声明变量存储分页导航条显示时的属性设置
    var paginationProperties = {
        num_edge_entries : 3,           //边缘页数
        num_display_entries : 5,        //主体页数
        callback : pageselectCallback,  //回调函数
        items_per_page : ${requestScope['PAGE-INFO'].pageSize}, //每页显示数据数量,就是pageSize
        current_page : ${requestScope['PAGE-INFO'].pageNum - 1},//当前页页码
        prev_text : "上一页",          //上一页文本
        next_text : "下一页"           //下一页文本
    };
    // 显示分页导航条
    $("#Pagination").pagination(totalRecord, paginationProperties);
}
// 在每一次点击“上一页”、“下一页”、“页码”时执行这个函数跳转页面
function pageselectCallback(pageIndex, jq) {
    // pageIndex从0开始,pageNum从1开始
    var pageNum = pageIndex + 1;
    // 跳转页面
    window.location.href = "admin/query/for/search.html?pageNum="+pageNum;
    return false;
}

4.9.4 Pagination修改源码

修改/atcrowdfunding-admin-1-webui/src/main/webapp/script/jquery.pagination.js文件,将158行注释掉
// opts.callback(current_page, this);

对应的问题:Pagination因为在这个地方重新加载页面,会造成死循环

4.10 关键词查询

4.10.1 将表单修改为可以提交的状态

  • 所在工程:atcrowdfunding-admin-1-webui
  • 所在页面:admin-page.jsp
查询条件

4.10.2 跳转页面时携带keyword请求参数

// 在每一次点击“上一页”、“下一页”、“页码”时执行这个函数跳转页面
function pageselectCallback(pageIndex, jq) {
    // pageIndex从0开始,pageNum从1开始
    var pageNum = pageIndex + 1;
    // 跳转页面
    window.location.href = "admin/query/for/search.html?pageNum="+pageNum+"&keyword=${param.keyword}";  
    return false;
}

AdminMapper.xml

  

5. 批量删除

5.1 全选/全不选功能

5.1.1 标记要操作的多选框


    
        #
        
        账号
        名称
        邮箱地址
        操作
    


    
        
            抱歉!没有符合您要求的查询结果!
        
    
    
        
            
                ${myStatus.count }
                
                ${admin.loginAcct }
                ${admin.userName }
                ${admin.email }
                
                    
                    
                    
                
            
        
    

5.1.2 jQuery代码

// 全选/全不选功能
$("#summaryBox").click(function() {
    // 获取当前#summaryBox的勾选状态
    // this代表当前多选框对象(DOM对象)
    // checked属性为true时表示被勾选,为false时表示没有被勾选
    // 使用checkStatus设置.itemBox的状态
    $(".itemBox").prop("checked",this.checked);
});

5.2 批量删除按钮绑定单击响应函数

5.2.1 给批量删除按钮标记id


5.2.2 给itemBox设置adminId属性


说明:adminId属性是HTML标签本身并没有的属性,是我们强行设置的。

5.3 封装统一的Ajax响应结果

所在工程:atcrowdfunding-admin-4-entity

全类名:com.rgh.crowd.funding.entity.ResultEntity

/**
 * 统一整个项目中所有Ajax请求的响应格式,作为项目的一个开发规范
 * @author Lenovo
 *
 */
public class ResultEntity {
    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 successWithoutData() {
        return new ResultEntity(SUCCESS, NO_MESSAGE, NO_DATA);
    }
    // 方便返回成功结果(携带查询结果情况)
    public static  ResultEntity successWithoutData(E data) {
        return new ResultEntity(SUCCESS, NO_MESSAGE, data);
    }
    // 方便返回失败结果
    public static  ResultEntity failed(E data, String message) {
        return new ResultEntity(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;
    }
}

5.4 jackson和Spring版本兼容性问题

5.4.1 方案一【×】

  • 和jackson-mapper-asl的1.9.2兼容的Spring版本是4.0.0。
  • 但是Spring的4.0.0和我们要使用的SpringSecurity版本不兼容。

5.4.2 方案二【√】

  • Spring使用5.0.2
  • jackson-core使用2.9.8
  • jackson-databind使用2.9.8

父工程pom.xml文件更改依赖




    com.fasterxml.jackson.core
    jackson-core
    2.9.8


    com.fasterxml.jackson.core
    jackson-databind
    2.9.8

子工程atcrowdfunding-admin-2-component的pom.xml文件



    com.fasterxml.jackson.core
    jackson-core


    com.fasterxml.jackson.core
    jackson-databind

5.5 勾选检查

当用户在页面上没有勾选任何多选框,然后点击批量删除按钮时应该给出提示并不执行删除。

5.6 删除前确认

弹出确认框,让用户确认是否删除。

5.7 删除完成善后

  • 如果删除操作执行成功则跳转页面。
  • 如果失败则弹出提示消息。

5.8 最终代码

5.8.1 前端JS部分

// 全选/全不选功能
$("#summaryBox").click(function() {
    // 获取当前#summaryBox的勾选状态
    // this代表当前多选框对象(DOM对象)
    // checked属性为true时表示被勾选,为false时表示没有被勾选
    // 使用checkStatus设置.itemBox的状态
    $(".itemBox").prop("checked",this.checked);
});
// 给批量删除按钮绑定单击响应函数
$("#batchRemoveBtn").click(function(){
    // 创建数组对象:存储adminId
    var adminIdArray = new Array();
    // 创建数组对象:存储loginAcct
    var loginAcctArray = new Array();
    // 通过jQuery选择器定位到所有被选中itemBox,然后遍历
    $(".itemBox:checked").each(function(){
        <%--  --%>
            // this.adminId拿不到值,原因是:this作为DOM对象无法读取HTML标签本身没有的属性
            // 将this转换为jQuery对象调用attr()函数就能够拿到值
            var adminId = $(this).attr("adminId");
        // 调用数组对象的push()方法将数据存入数组
        adminIdArray.push(adminId);
        // loginAcct
        var loginAcct = $(this)             // 当前checkbox对象
        .parent("td")   // 包含checkbox的td
        .next()         // 当前td的下一个兄弟元素,也就是下一个td
        .text();        // 下一个td的标签内部的文本
        loginAcctArray.push(loginAcct);
    });
    // 检查adminIdArray是否包含有效数据
    if(adminIdArray.length == 0) {
        // 给出提示
        alert("请勾选您要删除的记录!");
        // 函数停止执行
        return ;
    }
    // 给出确认提示,让用户确认是否真的删除这两条记录
    var confirmResult = confirm("您真的要删除"+loginAcctArray+"信息吗?操作不可逆,请谨慎决定!");
    // 如果用户点击了取消,那么让函数停止执行
    if(!confirmResult) {
        return ;
    }
    // 将JSON数组转换为JSON字符串
    // var a = [1,2,3,4,5];                 数组类型
    // var b = "[1,2,3,4,5]";               字符串类型
    // var c = {"userName":"tom"};          对象类型
    // var d = "{\"userName\":\"tom\"}";    字符串类型
    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 ;
        }
    });
});

5.8.2 后端部分

5.8.2.1 @RequestBody和@ResponseBody注解
  • 所在工程:atcrowdfunding-admin-2-component
  • 全类名:com.rgh.crowd.funding.handler.AdminHandler
//将当前handler方法的返回值作为响应体返回,不经过试图解析器
@ResponseBody
@RequestMapping("/admin/batch/remove")
public ResultEntity batchRemove(@RequestBody List adminIdList){
    try {
        adminService.batchRemove(adminIdList);
        return ResultEntity.successWithoutData();
    }catch (Exception e){
        return ResultEntity.failed(null,e.getMessage());
    }
}
  • 所在工程:atcrowdfunding-admin-2-component
  • 全类名:com.rgh.crowd.funding.service.impl.AdminServiceImpl
public void batchRemove(List adminIdList) {
    //QBC:Query By Criteria
    //创建AdminExample对象
    AdminExample adminExample = new AdminExample();
    //创建Criteria对象
    //Criteria对象可以帮助我们封装查询条件
    //通过使用Criteria对象,可以把Java代码转换成SQL语句中WHERE字句里面的具体查询条件
    AdminExample.Criteria criteria = adminExample.createCriteria();
    //针对要查询的字段封装具体的查询条件
    criteria.andIdIn(adminIdList);
    //执行具体操作时把封装了查询条件的Example对象传入
    adminMapper.deleteByExample(adminExample);
}

你可能感兴趣的:(尚筹网-3.Admin分页和批量删除)