微信公众号: 一个优秀的废人 如有问题或建议, 请后台留言, 我会尽力解决你的问题.
前言
如题, 今天介绍 SpringBoot 是如何统一处理全局异常的. SpringBoot 中的全局异常处理主要起作用的两个注解是 @ControllerAdvice 和 @ExceptionHandler , 其中 @ControllerAdvice 是组件注解, 添加了这个注解的类能够拦截 Controller 的请求, 而 ExceptionHandler 注解可以设置全局处理控制里的异常类型来拦截要处理的异常. 比如:@ExceptionHandler(value = NullPointException.class) .
准备工作
- SpringBoot 2.1.3
- IDEA
- JDK 8
依赖配置
- <dependencies>
- <!-- JPA 依赖 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- </dependency>
- <!-- web 依赖 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-Web</artifactId>
- </dependency>
- <!-- mysql 连接类 -->
- <dependency>
- <groupId>MySQL</groupId>
- <artifactId>MySQL-connector-java</artifactId>
- <scope>runtime</scope>
- </dependency>
- <!-- lombok 依赖 -->
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <!-- 单元测试依赖 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
配置文件
- spring:
- # 数据库相关
- datasource:
- driver-class-name: com.MySQL.jdbc.Driver
- url: jdbc:MySQL://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true
- username: root
- password: 123456
- jpa:
- hibernate:
- ddl-auto: update #ddl-auto: 设为 create 表示每次都重新建表
- show-sql: true
返回的消息类
- public class Message<T> implements Serializable {
- /**
- * 状态码
- */
- private Integer code;
- /**
- * 返回信息
- */
- private String message;
- /**
- * 返回的数据类
- */
- private T data;
- /**
- * 时间
- */
- private Long time;
- // getter,setter 以及 构造方法略...
- }
工具类
用于处理返回的数据以及信息类, 代码注释很详细不说了.
- public class MessageUtil {
- /**
- * 成功并返回数据实体类
- * @param o
- * @param <E>
- * @return
- */
- public static <E>Message<E> ok(E o){
- return new Message<>(200, "success", o, new Date().getTime());
- }
- /**
- * 成功, 但无数据实体类返回
- * @return
- */
- public static <E>Message<E> ok(){
- return new Message<>(200, "success", null, new Date().getTime());
- }
- /**
- * 失败, 有自定义异常返回
- * @param code
- * @param msg
- * @return
- */
- public static <E>Message<E> error(Integer code,String msg){
- return new Message<>(code, msg, null, new Date().getTime());
- }
- }
自定义异常
通过继承 RuntimeException , 声明 code 用于定义不同类型的自定义异常. 主要是用于异常拦截出获取 code 并将 code 设置到消息类中返回.
- public class CustomException extends RuntimeException{
- /**
- * 状态码
- */
- private Integer code;
- public Integer getCode() {
- return code;
- }
- public void setCode(Integer code) {
- this.code = code;
- }
- public CustomException(Integer code, String message){
- super(message);
- this.code = code;
- }
- }
异常拦截类
通过加入 @RestControllerAdvice 来声明该类可拦截 Controller 请求, 同时在 handle 方法加入 @ExceptionHandler 并在该注解中指定要拦截的异常类.
- @RestControllerAdvice // 控制器增强处理 (返回 JSON 格式数据), 添加了这个注解的类能被 classpath 扫描自动发现
- public class ExceptionHandle {
- @ExceptionHandler(value = Exception.class) // 捕获 Controller 中抛出的指定类型的异常, 也可以指定其他异常
- public <E>Message<E> handler(Exception exception){
- if (exception instanceof CustomException){
- CustomException customException = (CustomException) exception;
- return MessageUtil.error(customException.getCode(), customException.getMessage());
- } else {
- return MessageUtil.error(120, "异常信息:" + exception.getMessage());
- }
- }
- }
这里只对自定义异常以及未知异常进行处理, 如果你在某方法中明确知道可能会抛出某个异常, 可以加多一个特定的处理. 比如说你明确知道该方法可能抛出 NullPointException 可以追加 NullPointException 的处理:
- if (exception instanceof CustomException){
- CustomException customException = (CustomException) exception;
- return MessageUtil.error(customException.getCode(), customException.getMessage());
- } else if (exception instanceof NullPointException ){
- return MessageUtil.error(500, "空指针异常信!");
- } else {
- return MessageUtil.error(120, "异常信息:" + exception.getMessage());
- }
controller 层
- @RestController
- @RequestMapping("/student")
- public class StudentController {
- @Autowired
- private StudentService studentService;
- @GetMapping("/{id}")
- public Message<Student> findStudentById(@PathVariable("id") Integer id){
- if (id < 0){
- // 测试自定义错误
- throw new CustomException(110, "参数不能是负数!");
- } else if (id == 0){
- // 硬编码, 为了测试
- Integer i = 1/id;
- return null;
- } else {
- Student student = studentService.findStudentById(id);
- return MessageUtil.ok(student);
- }
- }
- }
完整代码
https://github.com/turoDog/Demo/tree/master/springboot_exception_demo
如果觉得对你有帮助, 请给个 Star 再走呗, 非常感谢.
Postman 测试
访问 http://localhost:8080/student/5 测试正常返回数据结果.
访问 http://localhost:8080/student/0 测试未知异常的结果.
访问 http://localhost:8080/student/-11 测试自定义异常的结果.
后语
如果本文对你哪怕有一丁点帮助, 请帮忙点好看. 你的好看是我坚持写作的动力.
另外, 关注之后在发送 1024 可领取免费学习资料. 资料内容详情请看这篇旧文: Python,C++,Java,Linux,Go, 前端, 算法资料分享 https://www.jianshu.com/p/ed43dc8aa11e
来源: https://juejin.im/post/5c7ab4b351882549847e8608