SpringBoot 处理异常的几种常见姿势

1. 使用 @ControllerAdvice 和 @ExceptionHandler 处理全局异常

这是目前很常用的一种方式,非常推荐。测试代码中用到了 Junit 5,如果你新建项目验证下面的代码的话,记得添加上相关依赖。

1. 新建异常信息实体类

非必要的类,主要用于包装异常信息。

src/main/java/com/twuc/webApp/exception/ErrorResponse.javapublic class ErrorResponse   private String message;

  private String errorTypeName;  public ErrorResponse(Exception e)

  {           this(e.getClass().getName(), e.getMessage());     }    public ErrorResponse(String errorTypeName, String message)  {        this.errorTypeName = errorTypeName;        this.message = message;    }    省略getter/setter方法}

2. 自定义异常类型

src/main/java/com/twuc/webApp/exception/ResourceNotFoundException.java

一般我们处理的都是 RuntimeException ,所以如果你需要自定义异常类型的话直接集成这个类就可以了。

/* 自定义异常类型 */public class ResourceNotFoundException extends RuntimeException {      private String message;    public ResourceNotFoundException() {                super();    }    public ResourceNotFoundException(String message)   {                   super(message);              this.message = message;    }    @Override    public String getMessage()   {        return message;    }    public void setMessage(String message)  {        this.message = message;    }

}

3. 新建异常处理类

我们只需要在类上加上@ControllerAdvice注解这个类就成为了全局异常处理类,当然你也可以通过 assignableTypes指定特定的 Controller 类,让异常处理类只处理特定类抛出的异常。

src/main/java/com/twuc/webApp/exception/GlobalExceptionHandler.java

@ControllerAdvice(assignableTypes = {ExceptionController.class})@ResponseBodypublic class GlobalExceptionHandler {    ErrorResponse illegalArgumentResponse = new ErrorResponse(new IllegalArgumentException("参数错误!"));    ErrorResponse resourseNotFoundResponse = new ErrorResponse(new ResourceNotFoundException("Sorry, the resourse not found!"));    @ExceptionHandler(value = Exception.class)// 拦截所有异常, 这里只是为了演示,一般情况下一个方法特定处理一种异常    public ResponseEntity<ErrorResponse> exceptionHandler(Exception e) {        if (e instanceof IllegalArgumentException) {            return ResponseEntity.status(400).body(illegalArgumentResponse);        } else if (e instanceof ResourceNotFoundException) {            return ResponseEntity.status(404).body(resourseNotFoundResponse);        }        return null;    }

}

4. controller模拟抛出异常

src/main/java/com/twuc/webApp/web/ExceptionController.java

    @RestController@RequestMapping("/api")public class ExceptionController {    @GetMapping("/illegalArgumentException")    public void throwException() {        throw new IllegalArgumentException();    }    @GetMapping("/resourceNotFoundException")    public void throwException2() {        throw new ResourceNotFoundException();    }}

使用 Get 请求 localhost:8080/api/resourceNotFoundException,服务端返回的 JSON 数据如下:

{    "message": "Sorry, the resourse not found!",       "errorTypeName": "com.twuc.webApp.exception.ResourceNotFoundException"}

5. 编写测试类

MockMvc 由org.springframework.boot.test包提供,实现了对Http请求的模拟,一般用于我们测试 controller 层。

@AutoConfigureMockMvc@SpringBootTestpublic class ExceptionTest {    @Autowired    MockMvc mockMvc;    @Test    void should_return_400_if_param_not_valid() throws Exception {        mockMvc.perform(get("/api/illegalArgumentException"))                .andExpect(status().is(400))                .andExpect(jsonPath("$.message").value("参数错误!"));    }    @Test    void should_return_404_if_resourse_not_found() throws Exception {        mockMvc.perform(get("/api/resourceNotFoundException"))                .andExpect(status().is(404))                .andExpect(jsonPath("$.message").value("Sorry, the resourse not found!"));    }}

2. @ExceptionHandler 处理 Controller 级别的异常

我们刚刚也说了使用@ControllerAdvice注解 可以通过 assignableTypes指定特定的类,让异常处理类只处理特定类抛出的异常。所以这种处理异常的方式,实际上现在使用的比较少了。

我们把下面这段代码移到 src/main/java/com/twuc/webApp/exception/GlobalExceptionHandler.java 中就可以了。

    @ExceptionHandler(value = Exception.class)// 拦截所有异常    public ResponseEntity<ErrorResponse> exceptionHandler(Exception e) {        if (e instanceof IllegalArgumentException) {            return ResponseEntity.status(400).body(illegalArgumentResponse);        } 

else if (e instanceof ResourceNotFoundException) {            return ResponseEntity.status(404).body(resourseNotFoundResponse);        }        return null;    }

3. ResponseStatusException

研究 ResponseStatusException 我们先来看看,通过 ResponseStatus注解简单处理异常的方法(将异常映射为状态码)。

src/main/java/com/twuc/webApp/exception/ResourceNotFoundException.java

@ResponseStatus(code = HttpStatus.NOT_FOUND)public class ResourseNotFoundException2 extends RuntimeException {    public ResourseNotFoundException2() {    }    public ResourseNotFoundException2(String message) {        super(message);    }}

src/main/java/com/twuc/webApp/web/ResponseStatusExceptionController.java

@RestController@RequestMapping("/api")public class ResponseStatusExceptionController {    @GetMapping("/resourceNotFoundException2")         public void throwException3() {        throw new ResourseNotFoundException2("Sorry, the resourse not found!");    }}

使用 Get 请求 localhost:8080/api/resourceNotFoundException2[2] ,服务端返回的 JSON 数据如下:

{    "timestamp": "2019-08-21T07:11:43.744+0000",    "status": 404,    "error": "Not Found",    "message": "Sorry, the resourse not found!",    "path": "/api/resourceNotFoundException2"}

这种通过 ResponseStatus注解简单处理异常的方法是的好处是比较简单,但是一般我们不会这样做,通过ResponseStatusException会更加方便,可以避免我们额外的异常类。

    @GetMapping("/resourceNotFoundException2")    public void throwException3() {        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Sorry, the resourse not found!", new ResourceNotFoundException());    }

使用 Get 请求 localhost:8080/api/resourceNotFoundException2[3] ,服务端返回的 JSON 数据如下,和使用 ResponseStatus 实现的效果一样:

{    "timestamp": "2019-08-21T07:28:12.017+0000",    "status": 404,    "error": "Not Found",    "message": "Sorry, the resourse not found!",    "path": "/api/resourceNotFoundException3"}

ResponseStatusException 提供了三个构造方法:

    public ResponseStatusException(HttpStatus status) {        this(status, null, null);    }    public ResponseStatusException(HttpStatus status, @Nullable String reason) {        this(status, reason, null);    }    public ResponseStatusException(HttpStatus status, @Nullable String reason, @Nullable Throwable cause) {        super(null, cause);        Assert.notNull(status, "HttpStatus is required");            this.status = status;        this.reason = reason;    }

构造函数中的参数解释如下:

•status :http status

•reason :response 的消息内容

•cause :抛出的异常

SpringBoot 处理异常的几种常见姿势的更多相关文章

  1. Upfile的几种常见姿势

    记录一下文件上传的常见姿势,更全面的可以做upload-labs. 实验环境:win2003 phpstudy 实验平台:upfile 一.准备上传的一句话木马 eval函数将接受的字符串当做代码执行 ...

  2. 补习系列(7)-springboot 实现拦截的五种姿势

    目录 简介 姿势一.使用 Filter 接口 1. 注册 FilterRegistrationBean 2. @WebFilter 注解 姿势二.HanlderInterceptor 姿势三.@Exc ...

  3. C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路

    C#不用union,而是有更好的方式实现   用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...

  4. 适用于app.config与web.config的ConfigUtil读写工具类 基于MongoDb官方C#驱动封装MongoDbCsharpHelper类(CRUD类) 基于ASP.NET WEB API实现分布式数据访问中间层(提供对数据库的CRUD) C# 实现AOP 的几种常见方式

    适用于app.config与web.config的ConfigUtil读写工具类   之前文章:<两种读写配置文件的方案(app.config与web.config通用)>,现在重新整理一 ...

  5. Python爬虫突破封禁的6种常见方法

    转 Python爬虫突破封禁的6种常见方法 2016年08月17日 22:36:59 阅读数:37936 在互联网上进行自动数据采集(抓取)这件事和互联网存在的时间差不多一样长.今天大众好像更倾向于用 ...

  6. 几种常见RuntimeException

    一般面试java Exception(runtimeException )是个问题必须要问 常见的异常上市45种,它的基本要求.许多其他....需要注意的积累   常见的几种例如以下:   NullP ...

  7. SpringBoot 开发案例之参数传递的正确姿势

    前言 开发这么多年,肯定还有不少小伙伴搞不清各种类型的参数是如何传递的,很多同学都是拿来即用,复制粘贴一把撸,遇到问题还是一脸懵逼. 姿势 学习参数传递的正确姿势,先说怎么做,再说为什么,本质上还是复 ...

  8. SpringBoot 全局异常配置

    在日常web开发中发生了异常,往往是需要通过一个统一的异常处理来保证客户端能够收到友好的提示. 一.默认异常机制 默认异常处理(SpringBoot 默认提供了两种机制,一种是针对于web浏览器访问的 ...

  9. Redis 的几种常见使用方式

    常见使用方式 Redis 的几种常见使用方式包括: Redis 单副本 Redis 多副本(主从) Redis Sentinel(哨兵) Redis Cluster Redis 自研 各种使用方式的优 ...

随机推荐

  1. frp 使用基础笔记

    0x01 简介 为什么需要内网穿透? 很多时候从公网访问自己内网的设备是困难的,毕竟自己没有一个独立的IP地址. Frp 服务器进行内网穿透,速度快还十分简单.可以实现很多功能,包括不限于远程桌面,文 ...

  2. vscode git连接github

    上一篇文章中介绍了vscode中git的简单使用方法vscode git的简单使用 上次只讲到了本地库的创建,这次说明下怎么push到github上 首先需要有一个github的账号  github官 ...

  3. FULL OUTER JOIN

    FULL OUTER JOIN 关键字只要左表(table1)和右表(table2)其中一个表中存在匹配,则返回行. SELECT Web.name, access.count, access.dat ...

  4. C语言与汇编的嵌入式编程:main中模拟函数的调用(两数交换)

    编写一个两数交换函数swap,具体代码如下: #include<stdio.h> void swap(int *p1,int *p2) { int temp; temp = *p1; *p ...

  5. JavaScript学习笔记之二

    一 js与json数据格式的转换:序列号与反序列化 JSON.stringify(jsobj, '  ');//将js的obj转换为json对象: JSON.parse()把json对象变成一个Jav ...

  6. 【PAT甲级】1080 Graduate Admission (30 分)

    题意: 输入三个正整数N,M,K(N<=40000,M<=100,K<=5)分别表示学生人数,可供报考学校总数,学生可填志愿总数.接着输入一行M个正整数表示从0到M-1每所学校招生人 ...

  7. 【C语言】将输入的10个数排序

    代码: #include <stdio.h> int main() { ], t; int i, j, max; printf("请输入10个数:\n"); ; i & ...

  8. 自己实现java中Iterator(迭代器功能)

    今天躺在床上忽然想到一个问题,迭代器的代码是如何实现的?于是乎不由自主的爬起来敲两行代码. List<String> list=new ArrayList<>(2); list ...

  9. mysql成功的远程连接

    1.在虚拟机上的window7中安装mysql,版本mysql-5.7.27-win32,可以是解压版或者是安装版的, MySQL安装文件分为两种,一种是msi格式的,一种是zip格式的.如果是msi ...

  10. java.io.NotSerializableException 没有序列化异常

    在实现MyBatis的二级缓存时,遇到此异常,其原因是实体类未实现Serializable接口. 异常: org.apache.ibatis.cache.CacheException: Error s ...