图书管理系统(完结版)

今天我们将对图书管理系统进行收尾工作,今天的开发任务有两个

  1. 实现统一数据返回格式
  2. 实现统一异常的处理

上篇文章【JavaEE进阶】图书管理系统(未完待续)-CSDN博客

统一数据返回格式

在前面文章讲到,通过拦截器实现了登录验证功能,但是对于数据的返回还没有处理

复制代码
public enum ResultStatus {
    SUCCESS(200),
    UNLOGIN(-1),
    FAIL(-2);
    private Integer code;
    ResultStatus(int code) {
        this.code = code;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
}

package com.example.demo.model;

import lombok.Data;

@Data
public class Result<T> {
    private int status;//1.  200成功   2. -1未登录 3. -2  异常
    private String errorMsg;//错误信息
    private T data;
    public static <T> Result success(T data) {
        Result result = new Result();
        result.setStatus(ResultStatus.SUCCESS.getCode());
        result.setErrorMsg("");
        result.setData(data);
        return result;
    }
    public static Result unLogin() {
        Result result = new Result();
        result.setErrorMsg("未登录,请登录后访问");
        result.setStatus(ResultStatus.UNLOGIN.getCode());
        return result;
    }
    public static <T> Result fail(String msg) {
        Result result = new Result();
        result.setErrorMsg(msg);
        result.setStatus(ResultStatus.FAIL.getCode());
        result.setData("");
        return result;
    }
}

回顾之前内容,Result进行了封装

复制代码
 @RequestMapping("/getListByPage")
    public Result<PageResult<BookInfo>> getListByPage(PageRequest pageRequest, HttpSession session) {
        log.info("获取图书列表, pageRequest:{}", pageRequest);
        UserInfo userInfo = (UserInfo) session.getAttribute("session_user_key");
        if (userInfo==null || userInfo.getId()<0 ||
                "".equals(userInfo.getUserName())){
            return Result.unLogin();
        }
        //⽤⼾登录, 返回图书列表
        PageResult<BookInfo> pageResult =
                bookService.getBookListByPage(pageRequest);
        return Result.success(pageResult);
    }

 getBookList();
            function getBookList() {
                $.ajax({
                    type: "get",
                    url: "/book/getListByPage" + location.search,
                    success: function (result) {
                        console.log(result);
                        if (result == null || result.data == null) {
                            location.href = "login.html";
                            return;
                        }
                        var finalHtml = "";
                        var data = result.data;
                        for (var book of data.records) {
                            finalHtml += '<tr>';
                            finalHtml += '<td><input type="checkbox" name="selectBook"  value = "' + book.id + '" id = "selectBook" class="book-select" ></td > ';
                            finalHtml += '<td>' + book.id + '</td>';
                            finalHtml += '<td>' + book.bookName + '</td>';
                            finalHtml += '<td>' + book.author + '</td>';
                            finalHtml += '<td>' + book.count + '</td>';
                            finalHtml += '<td>' + book.price + '</td>';
                            finalHtml += '<td>' + book.publish + '</td>';
                            finalHtml += '<td>' + book.statusCN + '</td>';
                            finalHtml += '<td><div class="op">';
                            finalHtml += '<a href="book_update.html?bookId=' + book.id +
                                '">修改</a>';
                            finalHtml += '<a href="javascript:void(0)" onclick = "deleteBook(' + book.id + ')" > 删除</a > ';
                            finalHtml += '</div></td>';
                            finalHtml += "</tr>";
                        }
                        $("tbody").html(finalHtml);
                        $("#pageContainer").jqPaginator({
                            totalCounts: data.total, //总记录数
                            pageSize: 10, //每⻚的个数
                            visiblePages: 5, //可视⻚数
                            currentPage: data.pageRequest.currentPage, //当前⻚码
                            first: '<li class="page-item"><a class="page-link">⾸⻚</a></li> ', prev: '<li class="page-item"><a class="page-link" href = "javascript:void(0);" > 上⼀⻚<\/a><\/li>',
                            next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下⼀⻚<\/a><\/li>',
                            last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后⼀⻚<\/a><\/li>',
                            page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',
                            //⻚⾯初始化和⻚码点击时都会执⾏
                            onPageChange: function (page, type) {
                                if (type != 'init') {
                                    location.href = "book_list.html?currentPage=" + page;
                                }
                            }
                        });
                    }
                    // 初始调用时无需传参(函数已设置默认值)
                });
            }

同时需要对前端代码进行修改

复制代码
            getBookList();
            function getBookList() {
                $.ajax({
                    type: "get",
                    url: "/book/getListByPage" + location.search,
                    success: function (result) {
                        console.log(result);
                        if (result.data != null || result.data.records != null) {
                            var finalHtml = "";
                            var data = result.data;
                            for (var book of data.records) {
                                finalHtml += '<tr>';
                                finalHtml += '<td><input type="checkbox" name="selectBook"  value = "' + book.id + '" id = "selectBook" class="book-select" ></td > ';
                                finalHtml += '<td>' + book.id + '</td>';
                                finalHtml += '<td>' + book.bookName + '</td>';
                                finalHtml += '<td>' + book.author + '</td>';
                                finalHtml += '<td>' + book.count + '</td>';
                                finalHtml += '<td>' + book.price + '</td>';
                                finalHtml += '<td>' + book.publish + '</td>';
                                finalHtml += '<td>' + book.statusCN + '</td>';
                                finalHtml += '<td><div class="op">';
                                finalHtml += '<a href="book_update.html?bookId=' + book.id +
                                    '">修改</a>';
                                finalHtml += '<a href="javascript:void(0)" onclick = "deleteBook(' + book.id + ')" > 删除</a > ';
                                finalHtml += '</div></td>';
                                finalHtml += "</tr>";
                            }
                            $("tbody").html(finalHtml);
                            $("#pageContainer").jqPaginator({
                                totalCounts: data.total, //总记录数
                                pageSize: 10, //每⻚的个数
                                visiblePages: 5, //可视⻚数
                                currentPage: data.pageRequest.currentPage, //当前⻚码
                                first: '<li class="page-item"><a class="page-link">⾸⻚</a></li> ', prev: '<li class="page-item"><a class="page-link" href = "javascript:void(0);" > 上⼀⻚<\/a><\/li>',
                                next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下⼀⻚<\/a><\/li>',
                                last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后⼀⻚<\/a><\/li>',
                                page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',
                                //⻚⾯初始化和⻚码点击时都会执⾏
                                onPageChange: function (page, type) {
                                    if (type == "change") {
                                        location.href = "book_list.html?currentPage=" + page;
                                    }
                                }
                            });
                        }
                        else{
                            alert("没有图书");
                            location.href = "login.html";
                        }
                    }
                    // 初始调用时无需传参(函数已设置默认值)
                });
            }

但是如果每一个接口都这样写,岂不太麻烦了一点儿。

其实spring boot为我们提供了统一数据格式返回的功能

快速入门

统⼀的数据返回格式使⽤ @ControllerAdvice 和ResponseBodyAdvice 的⽅式实现@ControllerAdvice 表⽰控制器通知类添加类

@ControllerAdvice注解已经包含五大注解,会交给Spring进行管理

ResponseAdvice ,实现 ResponseBodyAdvice 接⼝,并在类上添加@ControllerAdvice 注解

复制代码
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return Result.success(body);
    }
}
  • supports方法:判断是否要执行beforeBodyWrite方法.true为执行,false不执行.通过该⽅法可以选择哪些类或哪些方法的response要进行处理,其他的不进行处理
  • beforeBodyWrite方法:对response方法进行具体操作处理

添加统⼀数据返回格式之前:

添加统⼀数据返回格式之后:

存在问题

问题现象:

我们继续测试登录的接⼝:

结果显⽰,发⽣内部错误

查看⽇志,⽇志报错

测试⼏种不同的返回结果,发现只有返回结果为String类型时才有这种错误发⽣,这里不在演示

解决方案:

统一格式返回的优点

  1. ⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据
  2. 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就可以了,因为所有接⼝都是这样返回的.
  3. 有利于项⽬统⼀数据的维护和修改.
  4. 有利于后端技术部⻔的统⼀规范的标准制定,不会出现稀奇古怪的返回内容

统一异常处理

当我们程序出现异常的时候,Spring会对我们进行异常相关的处理,当发生异常的时候,它会走到BasicErrorcontroller类中的 error方法。

我们可以自己来处理异常。

统⼀异常处理使⽤的是 @ControllerAdvice+@ExceptionHandler 来实现的

@ControllerAdvice 表⽰控制器通知类

@ExceptionHandler 是异常处理器

两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件

记得加: @ResponseBody

复制代码
@Slf4j
@ResponseBody
@ControllerAdvice
public class ErrorAdvice {
    @ExceptionHandler
    public Result<PageResult<BookInfo>> handler(Exception e){
        log.info("发生异常e",e);
        Result<PageResult<BookInfo>> result=new Result<>();
        result.setErrorMsg(e.getMessage());
        result.setData(null);
        result.setStatus(ResultStatus.FAIL.getCode());
        return result;
    }
}

当然,只能爆Exception这么宽泛的异常就没有意义了

复制代码
@ExceptionHandler
    public Object handler(Exception e) {
        return Result.fail(e.getMessage());
    }
 
    //空指针异常
    @ExceptionHandler
    public Object handler(NullPointerException e) {
        return Result.fail(e.getMessage());
    }
 
    //算数异常
    @ExceptionHandler
    public Object handler(ArithmeticException e) {
        return Result.fail(e.getMessage());
    }

现在我们在测试类中添加两个异常观察一下:

复制代码
package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/t1")
    public String t1() {
        String s = "1";
        char a = s.charAt(2);
        return "t1";
    }

    @RequestMapping("/t2")
    public Integer t2() {
        int s = 10/0;
        return 2;
    }

    @RequestMapping("/t3")
    public Boolean t3() {
        return true;
    }
}

前端代码

。。。。。。。像上面那种把每个返回结果修改为Result后进行少量修改即可

相关推荐
胚芽鞘6811 小时前
关于java项目中maven的理解
java·数据库·maven
nbsaas-boot2 小时前
Java 正则表达式白皮书:语法详解、工程实践与常用表达式库
开发语言·python·mysql
岁忧2 小时前
(LeetCode 面试经典 150 题 ) 11. 盛最多水的容器 (贪心+双指针)
java·c++·算法·leetcode·面试·go
chao_7892 小时前
二分查找篇——搜索旋转排序数组【LeetCode】两次二分查找
开发语言·数据结构·python·算法·leetcode
CJi0NG2 小时前
【自用】JavaSE--算法、正则表达式、异常
java
风无雨2 小时前
GO 启动 简单服务
开发语言·后端·golang
Hellyc2 小时前
用户查询优惠券之缓存击穿
java·redis·缓存
斯普信专业组2 小时前
Go语言包管理完全指南:从基础到最佳实践
开发语言·后端·golang
今天又在摸鱼3 小时前
Maven
java·maven
老马啸西风3 小时前
maven 发布到中央仓库常用脚本-02
java·maven