尚筹网-6.Role维护和异步请求的异常映射

1 html和json扩展名问题

1.1 对应*.html扩展名的请求

返回一个完整页面的请求。

1.2 对应*.json扩展名的请求

返回JSON数据的请求。

{"result":"SUCCESS","message":"NO_MESSAGE","data":
{"pageNum":2,"pageSize":5,"size":5,"startRow":6,"endRow":10,"total":100,"pages":20,"list":
[{"id":6,"name":"role5"},{"id":7,"name":"role6"},{"id":8,"name":"role7"},{"id":9,"name":"role8"},
{"id":10,"name":"role9"}],"firstPage":1,"prePage":1,"nextPage":3,"lastPage":8,"isFirstPage":false,
"isLastPage":false,"hasPreviousPage":true,"hasNextPage":true,"navigatePages":8,"navigatepageNums":
[1,2,3,4,5,6,7,8]}}

1.3 匹配错误时的问题

如果请求扩展名是*.html,但是实际返回的响应体是JSON格式,Tomcat会认为实际返回的响应和响应消息头中的内容类型不匹配,会抛异常。

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

此时要解决这个问题,将返回JSON数据的请求扩展名设置为*.json或Tomcat无法识别的扩展名即可。

例如:xxx.json或xxx.rgh都可以。

2. 角色维护-关键词查询功能

2.1 基本思路

在点击“查询”按钮后,获取文本框中填写的keyword值,赋值给全局变量keyword,调用showPage()函数即可。

  • 给“查询”按钮标记id
  • 给“查询”按钮绑定单击响应函数
  • 在单击响应函数中获取文本框中输入的数据
  • 验证输入数据是否有效
    • 如果无效,提示,停止函数执行
    • 如果有效,赋值给window.keyword
  • 调用showPage()

2.2 代码

$("#searchBtn").click(function(){
    // 在单击响应函数中获取文本框中输入的数据
    var keyword = $.trim($("#keywordInput").val());
    // 验证输入数据是否有效
    if(keyword == null || keyword == "") {
        // 如果无效,提示,停止函数执行
        layer.msg("请输入关键词!");
        return ;
    }
    // 如果有效,赋值给window.keyword
    window.keyword = keyword;
    // 调用showPage()重新分页
    showPage();
});

layer.msg('xxx')无法显示的原因

3 角色维护-全选功能

3.1 功能在页面的位置

3.2 具体实现

3.2.1 标记

总checkbox:/atcrowdfunding-admin-1-webui/src/main/webapp/WEB-INF/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>

itembox:/atcrowdfunding-admin-1-webui/src/main/webapp/script/my-role.js

// 使用PageInfo数据在tbody标签内显示分页数据
function generateTableBody(pageInfo) {
    ……
    for(var i = 0; i < list.length; i++) {
        ……
        var checkBoxTd = "<td><input roleid='"+role.id+"' class='itemBox' type='checkbox'></td>";
        ……
    }
}

3.2.2 给#summaryBox绑定单击响应函数

// 全选/全不选功能
$("#summaryBox").click(function(){
    // 1.获取当前checkbox的选中状态
    var currentStatus = this.checked;
    // 2.设置itemBox的选中状态
    $(".itemBox").prop("checked",currentStatus);
});

4. 角色维护-批量删除

4.1 准备工作

4.1.1 准备模态框

<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">
                <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 type="button" class="btn btn-primary">OK</button>
            </div>
        </div>
    </div>
</div>

创建include-modal-role-confirm.jsp文件保存模态框内容。

在role-page.jsp中包含include-modal-role-confirm.jsp文件。

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

4.1.2 getRoleListByRoleIdArray()函数

// 根据roleIdArray查询roleList
function getRoleListByRoleIdArray(roleIdArray) {
    // 1.将roleIdArray转换成JSON字符串
    var requestBody = JSON.stringify(roleIdArray);  
    // 2.发送Ajax请求
    var ajaxResult = $.ajax({
        "url":"role/get/list/by/id/list.json",
        "type":"post",
        "data":requestBody,
        "contentType":"application/json;charset=UTF-8",
        "dataType":"json",
        "async":false
    });
    // 3.获取JSON对象类型的响应体
    var resultEntity = ajaxResult.responseJSON;
    // 4.验证是否成功
    var result = resultEntity.result;
    if(result == "SUCCESS") {   
        // 5.如果成功,则返回roleList
        return resultEntity.data;
    }
    if(result == "FAILED") {
        layer.msg(resultEntity.message);
        return null;
    }
    return null;    
}

对应的后端代码:

com.rgh.crowd.funding.handler.RoleHandler

// handler方法
@ResponseBody
@RequestMapping("/role/get/list/by/id/list")
public ResultEntity<List<Role>> getRoleListByIdList(@RequestBody List<Integer> roleIdList) {
    List<Role> roleList = roleService.getRoleListByIdList(roleIdList);  
    return ResultEntity.successWithData(roleList);
}

com.rgh.crowd.funding.service.impl.RoleServiceImpl

// service方法
@Override
public List<Role> getRoleListByIdList(List<Integer> roleIdList) {
    // 预期的SQL语句
    // select id,name from t_role where id in (1,2,3,6,12)
    // 创建实体类Role对应的Example对象
    RoleExample roleExample = new RoleExample();
    // 在Example对象中封装查询条件
    roleExample.createCriteria().andIdIn(roleIdList);
    // 执行查询
    return roleMapper.selectByExample(roleExample);
}

4.1.3 showRemoveConfirmModal()函数

// 打开删除确认模态框
function showRemoveConfirmModal() {
    // 1.将模态框显示出来
    $("#confirmModal").modal("show");
    // 2.根据roleIdList获取roleList
    var roleList = getRoleListByRoleIdArray(window.roleIdArray);
    // 3.清空#confirmModalTableBody
    $("#confirmModalTableBody").empty();
    // 4.填充#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>"+id+"</td><td>"+name+"</td></tr>";   
        // 6.执行填充
        $("#confirmModalTableBody").append(trHTML);
    }   
}

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

4.2.1 标记批量删除按钮

<button id="batchRemoveBtn" type="button" class="btn btn-danger"
        style="float: right; margin-left: 10px;">
    <i class=" glyphicon glyphicon-remove"></i> 批量删除
</button>

4.2.2 检查itemBox是否被选中

// 给批量删除按钮绑定单击响应函数
$("#batchRemoveBtn").click(function(){
    // 获取被选中的itemBox数组长度
    var length = $(".itemBox:checked").length;
    // 如果长度为0,说明没有选择itemBox
    if(length == 0) {
        layer.msg("请至少选择一条!");
        return ;
    }
    // 未完待续...
});

4.2.3 在弹出的模态框中显示confirm信息

// 给批量删除按钮绑定单击响应函数
$("#batchRemoveBtn").click(function(){
    // 获取被选中的itemBox数组长度
    var length = $(".itemBox:checked").length;
    // 如果长度为0,说明没有选择itemBox
    if(length == 0) {
        layer.msg("请至少选择一条!");
        return ;
    }
    // 在全局作用域内创建roleIdArray
    window.roleIdArray = new Array();
    // 遍历$(".itemBox:checked")
    $(".itemBox:checked").each(function(){
        // 通过checkbox的roleid属性获取roleId值
        var roleId = $(this).attr("roleid");
        // 存入数组
        window.roleIdArray.push(roleId);
    });
    // 调用函数打开模态框
    showRemoveConfirmModal();
});

4.3 点击模态框的OK按钮执行删除

4.3.1 标记OK按钮

<button id="confirmModalBtn" type="button" class="btn btn-primary">OK</button>

4.3.2 绑定单击响应函数

// 给确认模态框中的OK按钮绑定单击响应函数
$("#confirmModalBtn").click(function(){
    var requestBody = JSON.stringify(window.roleIdArray);   
    $.ajax({
        "url":"role/batch/remove.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("操作成功!");         
                // 如果删除成功,则重新调用分页方法
                showPage();
            }
            if(result == "FAILED") {
                layer.msg(response.message);
            }
            // 不管成功还是失败,都需要关掉模态框
            $("#confirmModal").modal("hide");   
        },
        "error":function(response){
            layer.msg(response.message);
        }
    });
});

4.3.3 后端代码

com.rgh.crowd.funding.handler.RoleHandler

@ResponseBody
@RequestMapping("/role/batch/remove")
public ResultEntity<String> batchRemove(@RequestBody List<Integer> roleIdList) {
    roleService.batchRemove(roleIdList);    
    return ResultEntity.successWithoutData();
}

com.rgh.crowd.funding.service.impl.RoleServiceImpl

@Override
public void batchRemove(List<Integer> roleIdList) {
    RoleExample roleExample = new RoleExample();
    roleExample.createCriteria().andIdIn(roleIdList);   
    roleMapper.deleteByExample(roleExample);
}

5 角色维护-单条删除

// 针对.removeBtn这样动态生成的元素对象使用on()函数方式绑定单击响应函数
// $("动态元素所依附的静态元素").on("事件类型","具体要绑定事件的动态元素的选择器", 事件响应函数);
$("#roleTableBody").on("click",".removeBtn", function(){
    // 获取当前记录的roleId
    var roleId = $(this).attr("roleId");
    // 存入全局变量数组
    window.roleIdArray = new Array();
    window.roleIdArray.push(roleId);
    // 打开模态框(后续所有操作都和批量删除一样)
    showRemoveConfirmModal();
});

6 角色维护-新增

6.1 大体步骤

  • 给“新增”按钮绑定单击响应函数
  • 打开模态框
  • 给“保存”按钮绑定单击响应函数
    • 收集文本框内容
    • 发送请求
  • 请求处理完成关闭模态框、重新分页、清理表单

6.2 给“新增”按钮绑定单击响应函数

6.2.1 标记“新增”按钮

<button id="addBtn" type="button" class="btn btn-primary"
        style="float: right;" >
    <i class="glyphicon glyphicon-plus"></i> 新增
</button>

6.2.2 绑定单击响应函数

$("#addBtn").click(function(){
    alert("aaa...");
});

6.3 打开模态框

6.3.1 准备模态框

先准备模态框的HTML代码

<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">&times;</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" 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>

创建/atcrowdfunding-admin-1-webui/src/main/webapp/WEB-INF/include-modal-role-add.jsp文件

将include-modal-role-add.jsp包含到role-page.jsp

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

6.3.2 打开模态框

$("#addBtn").click(function(){
    $("#addModal").modal("show");
});

6.4 给“保存”按钮绑定单击响应函数

6.4.1 标记“保存”按钮

<button id="addModalBtn" type="button" class="btn btn-success">
    <i class="glyphicon glyphicon-plus"></i>保存
</button>

6.4.2 绑定单击响应函数

$("#addModalBtn").click(function(){
    // 1.收集文本框内容
    var roleName = $.trim($("#roleNameInput").val());
    if(roleName == null || roleName == "") {
        layer.msg("请输入有效角色名称!");
        return ;
    }
    // 2.发送请求
    $.ajax({
        "url":"role/save/role.json",
        "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);
        }
    });
});

6.5 后端代码

com.rgh.crowd.funding.handler.RoleHandler

@ResponseBody
@RequestMapping("/role/save/role")
public ResultEntity<String> saveRole(@RequestParam("roleName") String roleName) {   
    roleService.saveRole(roleName);
    return ResultEntity.successWithoutData();
}

com.rgh.crowd.funding.service.impl.RoleServiceImpl

@Override
public void saveRole(String roleName) {
    roleMapper.insert(new Role(null, roleName));
}

7 角色维护-更新

7.1 大体步骤

  • 给“铅笔”按钮绑定单击响应函数

    因为“铅笔”按钮是动态生成的,所以需要使用on()方式

  • 打开模态框

    • 准备模态框
    • 把roleId保存到全局变量
    • 获取到当前“铅笔”按钮所在行的roleName
    • 使用roleName回显模态框中的表单
  • 给“更新”按钮绑定单击响应函数

    • 收集文本框内容
    • 发送请求
    • 请求处理完成关闭模态框、重新分页

7.2 给“铅笔”按钮绑定单击响应函数

7.2.1 标记“铅笔”按钮

找到/atcrowdfunding-admin-1-webui/src/main/webapp/script/my-role.js文件

function generateTableBody(pageInfo) {
    ……
    for(var i = 0; i < list.length; i++) {
        ……
        var pencilBtn = "<button roleId='"+role.id+"' type='button' class='btn btn-primary btn-xs editBtn'><i class=' glyphicon glyphicon-pencil'></i></button>";       
        ……
    }
}

7.2.2 准备模态框

<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">&times;</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 file="/WEB-INF/include-modal-role-edit.jsp" %>

7.2.3 绑定单击响应函数

$("#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");
});

7.3 给“更新”按钮绑定单击响应函数

7.3.1 前端代码

$("#editModalBtn").click(function(){
    // 1.获取文本框值
    var roleName = $.trim($("#roleNameInputEdit").val());
    if(roleName == null || roleName == "") {
        layer.msg("请输入有效角色名称!");
        return ;
    }
    // 2.发送请求
    $.ajax({
        "url":"role/update/role.json",
        "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");
        }
    });
});

7.3.2 后端代码

@ResponseBody
@RequestMapping("/role/update/role")
public ResultEntity<String> updateRole(Role role) {
    roleService.updateRole(role);   
    return ResultEntity.successWithoutData();
}
@Override
public void updateRole(Role role) {
    roleMapper.updateByPrimaryKey(role);
}

8 @RestController

相当于@Controller注解+@ResponseBody注解,类使用了@RestController之后相当于在每一个方法上都加了@ResponseBody注解。

9 异常映射兼容异步请求

9.1 问题表现

Ajax请求在服务器端处理过程中抛出异常,经过异常处理器:

com.rgh.crowd.funding.exception.CrowFundingExceptionResolever

@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程序无法正常解析,导致页面不能正常显示和工作,也不能给出友好的错误提示。

9.2 问题解决思路

9.3 异步请求特点

9.4 分辨异步请求的工具方法

在atcrowdfunding-admin-3-common工程加入servlet-api依赖

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <scope>provided</scope>
</dependency>

com.rgh.crowd.funding.util.CrowdFundingUtils

/**
 * 用于判断一个请求是否是异步请求
 * @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;
}

9.5 升级后的异常处理器

@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) {
            // 3.创建ResultEntity对象
            ResultEntity<String> resultEntity = ResultEntity.failed(ResultEntity.NO_DATA, exception.getMessage());
            // 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;
    }
}

※需要Gson支持

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

9.6 改进提示消息

  • 所在工程:atcrowdfunding-admin-3-common
  • 全类名:com.rgh.crowd.funding.util.CrowdFundingConstant
public static final Map<String, String> EXCEPTION_MESSAGE_MAP = new HashMap<>();
static {
    EXCEPTION_MESSAGE_MAP.put("java.lang.ArithmeticException", "系统在进行数学运算时发生错误");
    EXCEPTION_MESSAGE_MAP.put("java.lang.RuntimeException", "系统在运行时发生错误");
    EXCEPTION_MESSAGE_MAP.put("com.rgh.crowd.funding.exception.LoginException", "登录过程中运行错误");
}
  • 所在工程:atcrowdfunding-admin-2-component
  • 全类名:com.rgh.crowd.funding.exeption.CrowdFundingExceptionResolever
@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;
    }
}

10 登录拦截器兼容异步请求

问题的产生和解决的思路都和异常映射部分一致

com.rgh.crowd.funding.interceptor.LoginInterceptor

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {
    // 通过request对象获取HttpSession对象
    HttpSession session = request.getSession(); 
    // 从Session域尝试获取已登录用户对象
    Admin admin = (Admin) session.getAttribute(CrowdFundingConstant.ATTR_NAME_LOGIN_ADMIN); 
    // 如果没有获取到Admin对象
    if(admin == null) {     
        // 进一步判断当前请求是否是异步请求
        boolean checkAsyncRequestResult = CrowdFundingUtils.checkAsyncRequest(request);
        if(checkAsyncRequestResult) {           
            // 为异步请求的响应创建ResultEntity对象
            ResultEntity<String> resultEntity = ResultEntity.failed(ResultEntity.NO_DATA, CrowdFundingConstant.MESSAGE_ACCESS_DENIED);          
            // 创建Gson对象
            Gson gson = new Gson();         
            // 将ResultEntity对象转换为JSON字符串
            String json = gson.toJson(resultEntity);            
            // 设置响应的内容类型
            response.setContentType("application/json;charset=UTF-8");
            // 将JSON字符串作为响应数据返回
            response.getWriter().write(json);
            // 表示不能放行,后续操作不执行
            return false;   
        }
        // 将提示消息存入request域
        request.setAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE, CrowdFundingConstant.MESSAGE_ACCESS_DENIED);
        // 转发到登录页面
        request.getRequestDispatcher("/WEB-INF/admin-login.jsp").forward(request, response);    
        return false;
    }   
    // 如果admin对象有效,则放行继续执行后续操作
    return true;
}

11 分页的showPage()函数修正

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

推荐阅读更多精彩内容