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

 更新时间:2019年08月29日 16:29:09   作者:java互联网架构  
这篇文章主要介绍了详解SpringBoot 处理异常的几种常见姿势,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、使用 @ControllerAdvice 和 @ExceptionHandler 处理全局异常

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

1. 新建异常信息实体类

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

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

/** 
 * @author shuang.kou 
 */ 
public 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 ,所以如果你需要自定义异常类型的话直接集成这个类就可以了。

/** 
 * @author shuang.kou 
 * 自定义异常类型 
 */ 
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

/** 
 * @author shuang.kou 
 */ 
@ControllerAdvice(assignableTypes = {ExceptionController.class}) 
@ResponseBody 
public 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

/** 
 * @author shuang.kou 
 */ 
@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[1] (curl -i -s -X GET url),服务端返回的 JSON 数据如下:

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

5. 编写测试类

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

/** 
 * @author shuang.kou 
 */ 
@AutoConfigureMockMvc 
@SpringBootTest 
public 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!")); 
 } 
} 

二、 @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; 
} 

三、 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 :抛出的异常

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 手把手教你如何获取微信用户openid

    手把手教你如何获取微信用户openid

    众所周知小程序的openid相当重要,它是用户的唯一标识id,牵扯的支付,登录,授权等,下面这篇文章主要给大家介绍了关于如何获取微信用户openid的相关资料,需要的朋友可以参考下
    2023-02-02
  • JAVA熔断和降级真实关系的图文详解

    JAVA熔断和降级真实关系的图文详解

    这篇文章主要介绍了Java熔断和降级的关系,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • java稀疏数组的示例代码

    java稀疏数组的示例代码

    这篇文章主要介绍了java稀疏数组,稀疏数组,记录一共有几行几列,有多少个不同值,把具有不同值的元素和行里了及值记录在一个小规模的数组中,从而缩小程序的规模,对java稀疏数组相关知识感兴趣的朋友一起看看吧
    2022-07-07
  • 聊聊java 过滤器、监听器、拦截器的区别(终结篇)

    聊聊java 过滤器、监听器、拦截器的区别(终结篇)

    这篇文章主要介绍了聊聊java 过滤器、监听器、拦截器的区别(终结篇),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • springmvc级联属性处理无法转换异常问题解决

    springmvc级联属性处理无法转换异常问题解决

    这篇文章主要介绍了springmvc级联属性处理无法转换异常问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Springboot集成kafka高级应用实战分享

    Springboot集成kafka高级应用实战分享

    这篇文章主要介绍了Springboot集成kafka高级应用实战分享,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • Java如何实现将类文件打包为jar包

    Java如何实现将类文件打包为jar包

    这篇文章主要介绍了Java如何实现将类文件打包为jar包,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Java实现发送手机短信语音验证功能代码实例

    Java实现发送手机短信语音验证功能代码实例

    这篇文章主要介绍了Java实现发送手机短信语音验证功能代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • Spring中Cache的使用方法详解

    Spring中Cache的使用方法详解

    这篇文章主要介绍了Spring中Cache的使用方法详解,Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能,Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,需要的朋友可以参考下
    2024-01-01
  • Spring cloud alibaba之Ribbon负载均衡实现方案

    Spring cloud alibaba之Ribbon负载均衡实现方案

    Spring cloud Ribbon是基于Netflix Ribbon实现的一套客户端的负载均衡工具,Ribbon客户端提供一系列完善的配置,如超时、重试等,Ribbon也可以实现自己的负载均衡算法,感兴趣的朋友跟随小编一起看看吧
    2021-07-07

最新评论