如题,今天介绍 SpringBoot 是如何统一处理全局异常的。SpringBoot 中的全局异常处理主要起作用的两个注解是 @ControllerAdvice@ExceptionHandler ,其中 @ControllerAdvice 是组件注解,添加了这个注解的类能够拦截 Controller 的请求,而 ExceptionHandler 注解可以设置全局处理控制里的异常类型来拦截要处理的异常。 比如:@ExceptionHandler(value = NullPointException.class) 。

准备工作

  • SpringBoot 2.1.3
  • IDEA
  • JDK 8

依赖配置

  1. <dependencies>
  2. <!-- JPA 依赖 -->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-data-jpa</artifactId>
  6. </dependency>
  7. <!-- web 依赖 -->
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-web</artifactId>
  11. </dependency>
  12. <!-- mysql 连接类 -->
  13. <dependency>
  14. <groupId>mysql</groupId>
  15. <artifactId>mysql-connector-java</artifactId>
  16. <scope>runtime</scope>
  17. </dependency>
  18. <!-- lombok 依赖 -->
  19. <dependency>
  20. <groupId>org.projectlombok</groupId>
  21. <artifactId>lombok</artifactId>
  22. <optional>true</optional>
  23. </dependency>
  24. <!-- 单元测试依赖 -->
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-test</artifactId>
  28. <scope>test</scope>
  29. </dependency>
  30. </dependencies>

配置文件

  1. spring:
  2. # 数据库相关
  3. datasource:
  4. driver-class-name: com.mysql.jdbc.Driver
  5. url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true
  6. username: root
  7. password: 123456
  8. jpa:
  9. hibernate:
  10. ddl-auto: update #ddl-auto:设为 create 表示每次都重新建表
  11. show-sql: true

返回的消息类

  1. public class Message<T> implements Serializable {
  2. /**
  3. * 状态码
  4. */
  5. private Integer code;
  6. /**
  7. * 返回信息
  8. */
  9. private String message;
  10. /**
  11. * 返回的数据类
  12. */
  13. private T data;
  14. /**
  15. * 时间
  16. */
  17. private Long time;
  18. // getter、setter 以及 构造方法略。。。
  19. }

工具类

用于处理返回的数据以及信息类,代码注释很详细不说了。

  1. public class MessageUtil {
  2. /**
  3. * 成功并返回数据实体类
  4. * @param o
  5. * @param <E>
  6. * @return
  7. */
  8. public static <E>Message<E> ok(E o){
  9. return new Message<>(200, "success", o, new Date().getTime());
  10. }
  11. /**
  12. * 成功,但无数据实体类返回
  13. * @return
  14. */
  15. public static <E>Message<E> ok(){
  16. return new Message<>(200, "success", null, new Date().getTime());
  17. }
  18. /**
  19. * 失败,有自定义异常返回
  20. * @param code
  21. * @param msg
  22. * @return
  23. */
  24. public static <E>Message<E> error(Integer code,String msg){
  25. return new Message<>(code, msg, null, new Date().getTime());
  26. }
  27. }

自定义异常

通过继承 RuntimeException ,声明 code 用于定义不同类型的自定义异常。主要是用于异常拦截出获取 code 并将 code 设置到消息类中返回。

  1. public class CustomException extends RuntimeException{
  2. /**
  3. * 状态码
  4. */
  5. private Integer code;
  6. public Integer getCode() {
  7. return code;
  8. }
  9. public void setCode(Integer code) {
  10. this.code = code;
  11. }
  12. public CustomException(Integer code, String message){
  13. super(message);
  14. this.code = code;
  15. }
  16. }

异常拦截类

通过加入 @RestControllerAdvice 来声明该类可拦截 Controller 请求,同时在 handle方法加入 @ExceptionHandler 并在该注解中指定要拦截的异常类。

  1. @RestControllerAdvice // 控制器增强处理(返回 JSON 格式数据),添加了这个注解的类能被 classpath 扫描自动发现
  2. public class ExceptionHandle {
  3. @ExceptionHandler(value = Exception.class) // 捕获 Controller 中抛出的指定类型的异常,也可以指定其他异常
  4. public <E>Message<E> handler(Exception exception){
  5. if (exception instanceof CustomException){
  6. CustomException customException = (CustomException) exception;
  7. return MessageUtil.error(customException.getCode(), customException.getMessage());
  8. } else {
  9. return MessageUtil.error(120, "异常信息:" + exception.getMessage());
  10. }
  11. }
  12. }

这里只对自定义异常以及未知异常进行处理,如果你在某方法中明确知道可能会抛出某个异常,可以加多一个特定的处理。比如说你明确知道该方法可能抛出 NullPointException 可以追加 NullPointException 的处理:

  1. if (exception instanceof CustomException){
  2. CustomException customException = (CustomException) exception;
  3. return MessageUtil.error(customException.getCode(), customException.getMessage());
  4. } else if (exception instanceof NullPointException ){
  5. return MessageUtil.error(500, "空指针异常信!");
  6. } else {
  7. return MessageUtil.error(120, "异常信息:" + exception.getMessage());
  8. }

controller 层

  1. @RestController
  2. @RequestMapping("/student")
  3. public class StudentController {
  4. @Autowired
  5. private StudentService studentService;
  6. @GetMapping("/{id}")
  7. public Message<Student> findStudentById(@PathVariable("id") Integer id){
  8. if (id < 0){
  9. //测试自定义错误
  10. throw new CustomException(110, "参数不能是负数!");
  11. } else if (id == 0){
  12. //硬编码,为了测试
  13. Integer i = 1/id;
  14. return null;
  15. } else {
  16. Student student = studentService.findStudentById(id);
  17. return MessageUtil.ok(student);
  18. }
  19. }
  20. }

完整代码

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」送你一套完整的 java 教程。



Spring Boot2 系列教程 (十四) | 统一异常处理的更多相关文章

  1. Spring Boot2 系列教程(十四)CORS 解决跨域问题

    今天和小伙伴们来聊一聊通过CORS解决跨域问题. 同源策略 很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略. 同源策略是由 Netsca ...

  2. Spring Boot2 系列教程(十)Spring Boot 整合 Freemarker

    今天来聊聊 Spring Boot 整合 Freemarker. Freemarker 简介 这是一个相当老牌的开源的免费的模版引擎.通过 Freemarker 模版,我们可以将数据渲染成 HTML ...

  3. Spring Boot2 系列教程 (十) | 实现声明式事务

    前言 如题,今天介绍 SpringBoot 的 声明式事务. Spring 的事务机制 所有的数据访问技术都有事务处理机制,这些技术提供了 API 用于开启事务.提交事务来完成数据操作,或者在发生错误 ...

  4. Spring Boot2 系列教程(十二)@ControllerAdvice 的三种使用场景

    严格来说,本文并不算是 Spring Boot 中的知识点,但是很多学过 SpringMVC 的小伙伴,对于 @ControllerAdvice 却并不熟悉,Spring Boot 和 SpringM ...

  5. Spring Boot2 系列教程(十八)Spring Boot 中自定义 SpringMVC 配置

    用过 Spring Boot 的小伙伴都知道,我们只需要在项目中引入 spring-boot-starter-web 依赖,SpringMVC 的一整套东西就会自动给我们配置好,但是,真实的项目环境比 ...

  6. Spring Boot2 系列教程(十九)Spring Boot 整合 JdbcTemplate

    在 Java 领域,数据持久化有几个常见的方案,有 Spring 自带的 JdbcTemplate .有 MyBatis,还有 JPA,在这些方案中,最简单的就是 Spring 自带的 JdbcTem ...

  7. Spring Boot2 系列教程 (十八) | 整合 MongoDB

    微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 如题,今天介绍下 SpringBoot 是如何整合 MongoDB 的. MongoDB 简介 MongoDB 是由 C++ ...

  8. Spring Boot2 系列教程 (十五) | 服务端参数校验之一

    估计很多朋友都认为参数校验是客户端的职责,不关服务端的事.其实这是错误的,学过 Web 安全的都知道,客户端的验证只是第一道关卡.它的参数验证并不是安全的,一旦被有心人抓到可乘之机,他就可以有各种方法 ...

  9. Spring Boot2 系列教程 (十二) | 整合 thymeleaf

    前言 如题,今天介绍 Thymeleaf ,并整合 Thymeleaf 开发一个简陋版的学生信息管理系统. SpringBoot 提供了大量模板引擎,包含 Freemarker.Groovy.Thym ...

随机推荐

  1. Python--day25--抽象类

    什么是抽象类: 抽象类: #一切皆文件 import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type='file' ...

  2. Codeforces Round #182 (Div. 1 + Div. 2)

    A. Eugeny and Array \(r-l+1\)是奇数时,和显然无法为0. 奇数的情况需要判断-1和1的个数是否大于等于长度的一半. B. Eugeny and Play List 模拟. ...

  3. Capistrano:自动完成多台服务器上新版本的同步更新,包括数据库的改变

    https://baike.baidu.com/item/Capistrano/6844928?fr=aladdin   Capistrano是一种在多台服务器上运行脚本的开源工具,它主要用于部署we ...

  4. vue 打包后,页面空白及图片路径的问题

    打包之后打开dist的页面显示空白: 1.记得改一下config下面的index.js中bulid模块导出的路径. 这里需要将 assetsPublicPath: '/'改为assetsPublicP ...

  5. 9月29更新美版T-mobile版本iPhone7代和7P有锁机卡贴解锁方法

    ​ T版是块难解的砖头,之前一直没有找到稳定解锁办法,经过多次不写努力和实验,终于解决 不管是用超雪卡贴还是GPP卡贴,第一次先用连接WIFI激活手机! 注意:一定不要用ICCID通用激活,或者是TM ...

  6. H3C系统调试的操作

  7. 连接远程mysql(Linux环境)

    保证三点: 1.打开/etc/my.cnf,找到[mysqld]项,在其后加入一句:skip-name-resolve,保存,重启mysql服务. service mysqld restart  或者 ...

  8. 解决html2canvas图片跨域合成失败的问题

    /** * 将图片转换为base64 * 解决html2canvas跨域合成失败的问题 */ var getBase64Image = function(src, cb) { var img = do ...

  9. SPOJ VLATTICE (莫比乌斯反演)

    传送门:https://www.spoj.com/problems/VLATTICE/en/ 题意: 在三维坐标系下,你在点(0,0,0),看的范围是(n,n,n)以内,求你可以看见多少个点没有被遮挡 ...

  10. 关于redis有序集合http://www.runoob.com/redis/redis-sorted-sets.html

    redis有序集合和集合一样,元素都是字符串类型,而且不能重复 和普通集合不同的是它关联一个double类型的分数,redis是同个元素的分数来对元素进行排序 有序集合的元素是唯一的,但是分数可以重复 ...