详解SpringBoot 处理异常的几种常见姿势
一、使用@ControllerAdvice和@ExceptionHandler处理全局异常
这是目前很常用的一种方式,非常推荐。测试代码中用到了Junit5,如果你新建项目验证下面的代码的话,记得添加上相关依赖。
1.新建异常信息实体类
非必要的类,主要用于包装异常信息。
src/main/java/com/twuc/webApp/exception/ErrorResponse.java
/** *@authorshuang.kou */ publicclassErrorResponse{ privateStringmessage; privateStringerrorTypeName; publicErrorResponse(Exceptione){ this(e.getClass().getName(),e.getMessage()); } publicErrorResponse(StringerrorTypeName,Stringmessage){ this.errorTypeName=errorTypeName; this.message=message; } ......省略getter/setter方法 }
2.自定义异常类型
src/main/java/com/twuc/webApp/exception/ResourceNotFoundException.java
一般我们处理的都是RuntimeException,所以如果你需要自定义异常类型的话直接集成这个类就可以了。
/** *@authorshuang.kou *自定义异常类型 */ publicclassResourceNotFoundExceptionextendsRuntimeException{ privateStringmessage; publicResourceNotFoundException(){ super(); } publicResourceNotFoundException(Stringmessage){ super(message); this.message=message; } @Override publicStringgetMessage(){ returnmessage; } publicvoidsetMessage(Stringmessage){ this.message=message; } }
3.新建异常处理类
我们只需要在类上加上@ControllerAdvice注解这个类就成为了全局异常处理类,当然你也可以通过assignableTypes指定特定的Controller类,让异常处理类只处理特定类抛出的异常。
src/main/java/com/twuc/webApp/exception/GlobalExceptionHandler.java
/** *@authorshuang.kou */ @ControllerAdvice(assignableTypes={ExceptionController.class}) @ResponseBody publicclassGlobalExceptionHandler{ ErrorResponseillegalArgumentResponse=newErrorResponse(newIllegalArgumentException("参数错误!")); ErrorResponseresourseNotFoundResponse=newErrorResponse(newResourceNotFoundException("Sorry,theresoursenotfound!")); @ExceptionHandler(value=Exception.class)//拦截所有异常,这里只是为了演示,一般情况下一个方法特定处理一种异常 publicResponseEntityexceptionHandler(Exceptione){ if(einstanceofIllegalArgumentException){ returnResponseEntity.status(400).body(illegalArgumentResponse); }elseif(einstanceofResourceNotFoundException){ returnResponseEntity.status(404).body(resourseNotFoundResponse); } returnnull; } }
4.controller模拟抛出异常
src/main/java/com/twuc/webApp/web/ExceptionController.java
/** *@authorshuang.kou */ @RestController @RequestMapping("/api") publicclassExceptionController{ @GetMapping("/illegalArgumentException") publicvoidthrowException(){ thrownewIllegalArgumentException(); } @GetMapping("/resourceNotFoundException") publicvoidthrowException2(){ thrownewResourceNotFoundException(); } }
使用Get请求localhost:8080/api/resourceNotFoundException[1](curl-i-s-XGETurl),服务端返回的JSON数据如下:
{ "message":"Sorry,theresoursenotfound!", "errorTypeName":"com.twuc.webApp.exception.ResourceNotFoundException" }
5.编写测试类
MockMvc由org.springframework.boot.test包提供,实现了对Http请求的模拟,一般用于我们测试controller层。
/** *@authorshuang.kou */ @AutoConfigureMockMvc @SpringBootTest publicclassExceptionTest{ @Autowired MockMvcmockMvc; @Test voidshould_return_400_if_param_not_valid()throwsException{ mockMvc.perform(get("/api/illegalArgumentException")) .andExpect(status().is(400)) .andExpect(jsonPath("$.message").value("参数错误!")); } @Test voidshould_return_404_if_resourse_not_found()throwsException{ mockMvc.perform(get("/api/resourceNotFoundException")) .andExpect(status().is(404)) .andExpect(jsonPath("$.message").value("Sorry,theresoursenotfound!")); } }
二、@ExceptionHandler处理Controller级别的异常
我们刚刚也说了使用@ControllerAdvice注解可以通过assignableTypes指定特定的类,让异常处理类只处理特定类抛出的异常。所以这种处理异常的方式,实际上现在使用的比较少了。
我们把下面这段代码移到src/main/java/com/twuc/webApp/exception/GlobalExceptionHandler.java中就可以了。
@ExceptionHandler(value=Exception.class)//拦截所有异常 publicResponseEntityexceptionHandler(Exceptione){ if(einstanceofIllegalArgumentException){ returnResponseEntity.status(400).body(illegalArgumentResponse); }elseif(einstanceofResourceNotFoundException){ returnResponseEntity.status(404).body(resourseNotFoundResponse); } returnnull; }
三、ResponseStatusException
研究ResponseStatusException我们先来看看,通过ResponseStatus注解简单处理异常的方法(将异常映射为状态码)。
src/main/java/com/twuc/webApp/exception/ResourceNotFoundException.java
@ResponseStatus(code=HttpStatus.NOT_FOUND) publicclassResourseNotFoundException2extendsRuntimeException{ publicResourseNotFoundException2(){ } publicResourseNotFoundException2(Stringmessage){ super(message); } }
src/main/java/com/twuc/webApp/web/ResponseStatusExceptionController.java
@RestController @RequestMapping("/api") publicclassResponseStatusExceptionController{ @GetMapping("/resourceNotFoundException2") publicvoidthrowException3(){ thrownewResourseNotFoundException2("Sorry,theresoursenotfound!"); } }
使用Get请求localhost:8080/api/resourceNotFoundException2[2],服务端返回的JSON数据如下:
{ "timestamp":"2019-08-21T07:11:43.744+0000", "status":404, "error":"NotFound", "message":"Sorry,theresoursenotfound!", "path":"/api/resourceNotFoundException2" }
这种通过ResponseStatus注解简单处理异常的方法是的好处是比较简单,但是一般我们不会这样做,通过ResponseStatusException会更加方便,可以避免我们额外的异常类。
@GetMapping("/resourceNotFoundException2") publicvoidthrowException3(){ thrownewResponseStatusException(HttpStatus.NOT_FOUND,"Sorry,theresoursenotfound!",newResourceNotFoundException()); }
使用Get请求localhost:8080/api/resourceNotFoundException2[3],服务端返回的JSON数据如下,和使用ResponseStatus实现的效果一样:
{ "timestamp":"2019-08-21T07:28:12.017+0000", "status":404, "error":"NotFound", "message":"Sorry,theresoursenotfound!", "path":"/api/resourceNotFoundException3" }
ResponseStatusException提供了三个构造方法:
publicResponseStatusException(HttpStatusstatus){ this(status,null,null); } publicResponseStatusException(HttpStatusstatus,@NullableStringreason){ this(status,reason,null); } publicResponseStatusException(HttpStatusstatus,@NullableStringreason,@NullableThrowablecause){ super(null,cause); Assert.notNull(status,"HttpStatusisrequired"); this.status=status; this.reason=reason; }
构造函数中的参数解释如下:
- status:httpstatus
- reason:response的消息内容
- cause:抛出的异常
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。