前言:
平时做项目时,在Controller层只会返回一个JSON串来表示信息是否成功~还真的没有考虑到异常是怎么处理的,不过肯定是统一管理异常。
一、全局错误页面:
Spring Boot提供了一个默认的映射:/error(当然该页面并不友好),当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异常内容。
- 创建全局异常处理类:通过使用@ControllerAdvice定义统一的异常处理类,而不是在每个Controller中逐个定义。@ExceptionHandler用来定义函数针对的异常类型,最后将Exception对象和请求URL映射到error.html中。
- 实现error.html页面展示:在templates目录下创建error.html,将请求的URL和Exception对象的message输出。
@ControllerAdvice
class GlobalExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error";
@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", req.getRequestURL());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
}
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>统一异常处理</title>
</head>
<body>
<h1>Error Handler</h1>
<div th:text="${url}"></div>
<div th:text="${exception.message}"></div>
</body>
我们只需要在Controller中抛出Exception,当然我们可能会有多种不同的Exception。然后在@ControllerAdvice类中,根据抛出的具体Exception类型匹配@ExceptionHandler中配置的异常类型来匹配错误映射和处理。
二、返回JSON格式
通过@ControllerAdvice统一定义不同Exception映射到不同错误处理页面。而当我们要实现RESTful API时,返回的错误是JSON格式的数据,而不是HTML页面。
本质上,只需在@ExceptionHandler之后加入@ResponseBody,就能让处理函数return的内容转换为JSON格式。
- 创建统一的JSON返回对象
public class Result<T> {
/** 错误码. */
private Integer code;
/** 提示信息. */
private String msg;
/** 具体的内容. */
private T data;
//getter setter方法
}
- 出现异常信息
public void getAge(Integer id){
Student stu = Stu.finOne(id);
Integer age = stu.getAge();
if(age < 10){
throw new Exception("你在上小学吧");
}else if(age > 10 && age < 16){
throw new Exception("你可能在上初中");
}
}
不符合规范的处理方式
1. 既然要返回Json串那么就要把消息类型与信息给加进去~ 自定义异常
2. 没有一个统一的地方来维护。
public class StuException extends RuntimeException{ //继承这个才会回滚, 否则继承Exception不会回滚
private Integer code;
public StuException(ResultEnum resultEnum) {
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
- 统一异常处理:
ControllerAdvice
public class ExceptionHandle {
private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
if (e instanceof StuException) {
StuException stuException = (StuException) e;
return ResultUtil.error(stuException.getCode(), stuException.getMessage());
}else {
logger.error("【系统异常】{}", e);
return ResultUtil.error(-1, "未知错误");
}
}
}
- 枚举来统一管理:
枚举一般都是用构造方法来创建,提供get方法。
public enum ResultEnum {
UNKONW_ERROR(-1, "未知错误"),
SUCCESS(0, "成功"),
PRIMARY_SCHOOL(100, "我猜你可能还在上小学"),
MIDDLE_SCHOOL(101, "你可能在上初中"),
;
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
- 符合规范的调用方式:
public void getAge(Integer id){
Student stu = Stu.finOne(id);
Integer age = stu.getAge();
if(age < 10){
throw new StuException(ResultEnum.PRIMARY_SCHOOL));
}else if(age > 10 && age < 16){
throw new StuException(ResultEnum.MIDDLE_SCHOOL);
}
}
总结:
这样的优点在于抛出自己定义的异常统一处理,用枚举形式来统一管理,即错误小本本,错误码能对应到错误信息的~