详解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:抛出的异常
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。