前言
关于如何搭建SpringBoot工程以及开启Web功能,
可以查看我的这篇博客:用Spring Initializr快速构建SpringBoot及整合MVC
异常分类
人不是上帝,无法写出不出错的程序;人也不是机器,我们不可能穷尽所有的异常一一分类处理,所以这个时候一个统一异常处理显得尤为重要。我们姑且把SpringBoot的异常按下图进行分类,然后一一进行处理。毕竟统一异常处理,也不是所有的异常都只做一个处理。
其中代码异常顾名思义就是当用户访问我们编写的代码所出现的异常,可分为同步请求和异步请求两类:同步请求一般如表单提交、超链接这类会跳转页面的请求;而异步请求主要为ajax异步请求,一般只会局部刷新页面。系统异常可以理解为不经过开发者自己编写代码所出现的异常。一般最常见的代码异常为404即找不到页面,比如我们开发b站随意在b站的根目录下输入一个网址,如点击进入b站404页面,我们可以发现b站的404页面竟然是可以看漫画的:
异常处理
代码异常
通过之前的解释我们可以知道,代码异常可分为同步请求和异步请求,那么如何区分同步请求和异步请求呢?
我们可以分别写两个同步同步请求和异步请求,然后在浏览器检查元素,打开Network查看一下不同的请求:
同步请求:
异步请求:
那么有什么区别呢?仔细观察可以发现,异步请求似乎多了点东西:
对,就是这个:X-Requested-With: XMLHttpRequest
,而仔细回想一下js创建ajax似乎是这么写:var xhr=new XMLHttpRequest();
代码实现
经过上述分析,也就不难理解下述代码:
package com.guqueyue.exception;
/**
* @author guqueyue
* @Date 2020/5/21
* 代码异常处理
**/
@ControllerAdvice
public class CommonsExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Object exceptionHandler(HttpServletRequest request, Exception e) {
System.out.println("出错啦:" + e.getMessage());
String header = request.getHeader("X-Requested-With");
// 判断是同步请求还是ajax请求
if (header != null && header.equals("XMLHttpRequest")) {
return new ResultData<>().setCode(ResultData.ResultCodeList.ERROR).setMessage("服务器繁忙,请稍后再试!");
} else {
return new ModelAndView("error/sorry");
}
}
}
当然,返回异步请求之前需要先有一个响应类:
/**
* @author guqueyue
* @Date 2020/4/25
* 响应信息实体类
**/
@Data //lombok插件的注解,若是没有用lombok插件,请自行生成getter、setter方法
@AllArgsConstructor //全参构造方法
@NoArgsConstructor //无参构造方法
@Accessors(chain = true) // 开启链式编程
public class ResultData<T> {
/**
* 响应码
*/
private String code;
/**
* 响应信息
*/
private String message;
/**
* 数据部分
*/
private T data;
/**
* 响应的状态码列表
*/
public static interface ResultCodeList {
String OK = "200";
String ERROR = "500";
}
}
实现效果
经过上述请求,当我们的同步请求出现异常时,会自动显示错误页面(当然,上文中位于templates/error目录下的sorry页面需要自己编写):
当我们的ajax异步请求出现异常时,会自动提示错误信息(当然,弹窗提示错误信息需要自己在前端处理):
系统异常
在我们没有做系统异常处理之前,在项目根路径下随机访问一个不存在路径,会这样:
我们会发现当出现系统异常时,程序会自动访问/error
路径,所以也就不难理解下面的代码:
package com.guqueyue.exception;
/**
* @author guqueyue
* @Date 2020/5/21
* 系统异常处理,如404
**/
@Controller
public class SystemExceptionHandler implements ErrorController {
@RequestMapping("/error")
public String systemException(HttpServletResponse response) {
// 获得响应的状态码
int status = response.getStatus();
switch (status) {
case 404:
return "error/404";
}
return "error/sorry";
}
@Override
public String getErrorPath() {
return "/error";
}
}
这样当用户试图访问一个不存在的路径时,系统将会自动访问位于目录templates/error下的404.html文件,如:
当然,这个是我自己写的404页面。