Spring Boot-全局异常处理及自定义异常

在日常开发过程中,我们使用Spring Boot,如果程序中抛出了一个异常,那我们在网页中看到的内容可能如下:
image
返回的是一个默认的错误页面,那如果我们是用的postMan等工具去请求接口呢, 看到的信息会是一个json字符串,如下:
image

那他是怎么实现不同的环境返回不同的内容呢? 下面来看一下Spring Boot的异常处理的默认实现

Spring Boot的默认异常处理

Spring Boot的默认异常处理在 BasicErrorController 这个类里面,下面看一下这个类的源码:
image
关键的代码就是这两个方法,这里有两个接口, 上面的接口中标注了 producestext/html,就是说如果是网页请求的话(网页请求头中有text/html),就走这个接口,最后返回的是一个ModelAndView,就是一个错误页面

image

对于返回错误页面, 其中还调用了一个非常重要的方法: this.resolveErrorView(...) 方法, 源码我就不带大家看了, 他的作用就是根据 HTTP 状态码来去找错误页面, 如 500 错误会去找 /error/500.html, 403 错误回去找 /error/403.html, 如果找不到则再找 /error/4xx.html 或 /error/5xx.html 页面. 还找不到的话, 则会去找 /error.html 页面, 如果都没有配置, 则会使用 Spring Boot 默认的页面

然后在下面的接口中,加了注解@ResponseBody,表示返回的是一个json,所以我们在postMan中的请求返回是一个json

自定义异常

看完了Spring Boot的默认异常处理后,再来思考这样一个问题,比如我们需要抛出一个用户不存在的异常,然后把用户id返回给前端,这就需要我们自己来定义一个异常,代码如下:

1
2
3
4
5
6
7
8
9
10
11
@Data
public class UserNotExistException extends RuntimeException {

private Long id;

public UserNotExistException(Long id) {
super("用户不存在");
this.id = id;
}

}

首先继承RuntimeException,然后写一个构造,调用super传入异常的message,然后还可以赋值一些自定义的属性,比如说这里的id

异常定义好了之后,下一步就是在出现异常的时候把异常给抛出去,Spring Boot默认的异常处理是不可以的,就需要我们自己做全局异常处理

自定义全局异常处理

新建一个全局异常处理器 GlobalExceptionHandler,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(UserNotExistException.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Map<String, Object> handleUserNotExistException(UserNotExistException ex) {
Map<String, Object> result = new HashMap<>(2);
result.put("id", ex.getId());
result.put("message", ex.getMessage());
return result;
}
}

首先类上面的注解是 @ControllerAdvice, 然后下面是自定义异常的一些返回信息,@ResponseBody表示返回是json格式的数据,@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)表示返回的http状态码是500, 方法里面返回了异常信息,以及id.

每次自定义了新的异常之后,都需要加到这个类里面来

测试

上面的内容都搞定之后,进行一个简单的测试,比如有以下这么一个接口:

1
2
3
4
5
6
@GetMapping("{id:\\d+}")
public User getInfo(@PathVariable Long id){
log.info("查询id是[{}]的数据.....", id);
throw new UserNotExistException(id);
// return new User();
}

就是直接抛出了我们自定义的异常,然后下面访问接口看一下效果,如下:
image

可以看到,返回的就是我们的自定义异常信息了