如何优雅的处理异常?SpringBoot全局异常与数据校验

开发 后端
在现在的前后端交互中,通常都规范了接口返回方式,如返回的接口状态(成功|失败)以及要返回的数据在那个字段取,或者说失败了以后提示信息从接口哪里返回,因此,如果想做全局异常,并且异常发生后能准确的返回给前端解析,那么需要异常发生时返回给前端的格式与正常失败场景的格式一致。

 要思考的问题

在现在的前后端交互中,通常都规范了接口返回方式,如返回的接口状态(成功|失败)以及要返回的数据在那个字段取,或者说失败了以后提示信息从接口哪里返回,因此,如果想做全局异常,并且异常发生后能准确的返回给前端解析,那么需要异常发生时返回给前端的格式与正常失败场景的格式一致。

项目建立

利用idea 工具,很容易的搭建一个SpringBoot项目,要引入的maven依赖如下: 

  1. <dependency>  
  2.  <groupId>org.springframework.boot</groupId>  
  3.  <artifactId>spring-boot-starter-validation</artifactId>  
  4. </dependency>  
  5. <dependency>  
  6.  <groupId>org.springframework.boot</groupId>  
  7.  <artifactId>spring-boot-starter-web</artifactId>  
  8. </dependency>  
  9. <dependency>  
  10.  <groupId>org.springframework.boot</groupId>  
  11.  <artifactId>spring-boot-starter-test</artifactId>  
  12.  <scope>test</scope>  
  13. </dependency> 

很简单,除了加入web功能还加入了我们需要用到的JSR-303校验框架。

定义成功失败 返回码 

  1. public class Code {  
  2.  /**  
  3.  * 成功  
  4.  */  
  5.  public static int SUCCESSED = 1 
  6.  /**  
  7.  * 失败  
  8.  */  
  9.  public static int FAILED = -1;  

定义接口返回响应实体 

  1. public class Response<T> implements Serializable{  
  2.  /**  
  3.  *   
  4.  */  
  5.  private static final long serialVersionUID = 4250719891313555820L 
  6.  /**  
  7.  * 返回结果集  
  8.  */  
  9.  private T result;  
  10.  /**  
  11.  * 返回消息  
  12.  */  
  13.  private String msg;  
  14.  /**  
  15.  * 响应码  
  16.  */  
  17.  private Integer code;  
  18.  //set get 略  

全局异常拦截和验证

定义自定义业务异常 

  1. public class MyException extends RuntimeException {  
  2.  private static final long serialVersionUID = -5875371379845226068L;  
  3.  public MyException(){}  
  4.  public MyException(String msg){  
  5.  this.msg = msg ;  
  6.  }  
  7.  /**  
  8.  * 异常信息  
  9.  */  
  10.  private String msg ;  
  11.  /**  
  12.  * 具体异常码  
  13.  */  
  14.  private int code = Code.FAILED;  
  15.  get set 略  

编写全局异常控制器并对自定义异常做处理 

  1. @ControllerAdvice  
  2. public class GlobalExceptionHandler {  
  3.  private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);  
  4. @ExceptionHandler(value = MyException.class)  
  5. @ResponseBody  
  6. public Response<String> myExceptionErrorHandler(MyException ex) throws Exception {  
  7.  logger.error("myExceptionErrorHandler info:{}",ex.getMessage());  
  8.  Response<String> r = new Response<>();  
  9.  r.setMsg(ex.getMsg());  
  10.  r.setCode(ex.getCode());  
  11.  return r;  

编写controller模拟抛出业务异常 

  1. @RestController  
  2. @RequestMapping("/user")  
  3. public class UserController {  
  4. @PostMapping(value = "/update" 
  5. Response<Boolean> update(User user){  
  6.  //todo 此处为模拟异常抛出  
  7.  if(true){  
  8.  throw new MyException("更新失败");  
  9.  }  
  10.  //todo 此处为模拟返回  
  11.  Response<Boolean> response = new Response<>();  
  12.  response.setCode(Code.SUCCESSED);  
  13.  response.setResult(true);  
  14.  return response;  
  15.  

postMan模拟请求接口,进行验证

数据绑定异常处理

通常我们操作数据的时候,不仅前端需要进行数据校验,后端也应当进行拦截和进行相应的错误提示,JSR-303校验框架也是我们的一种选择。

编写实体`User`,并对属性进行注解控制 

  1. public class User {  
  2.  @NotNull(message = "用户名不能为空" 
  3.  private String userName;  
  4.  private int age;  
  5.  //... 

全局异常控制类加入拦截 

  1. @ControllerAdvice  
  2. public class GlobalExceptionHandler {  
  3.  private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);  
  4.  @ExceptionHandler(value = BindException.class)  
  5.  @ResponseBody  
  6.  public Response<String> bindExceptionErrorHandler(BindException ex) throws Exception {  
  7.  logger.error("bindExceptionErrorHandler info:{}",ex.getMessage());  
  8.  Response<String> r = new Response<>();  
  9.  StringBuilder sb = new StringBuilder();  
  10.  FieldError fieldError = ex.getFieldError();  
  11.  sb.append(fieldError.getDefaultMessage());  
  12.  r.setMsg(sb.toString());  
  13.  r.setCode(Code.FAILED);  
  14.  return r;  
  15.  }  
  16.  //... 

编写控制器 

  1. @RestController  
  2. @RequestMapping("/user")  
  3. public class UserController {  
  4.  @PostMapping(value = "/add" 
  5.  Response<User> add(@Validated User user){  
  6.  //todo 此处为模拟返回  
  7.  Response<User> response = new Response<>();  
  8.  response.setCode(Code.SUCCESSED);  
  9.  response.setResult(new User());  
  10.  return response;  
  11.  }  
  12.  //... 

postMan模拟请求

不填写任何属性,模拟添加操作,准确进行拦截和报错

项目结构预览:

结尾

适合的才是***的,每个团队都应摸索出自己的一套异常解决方案,本文所提仅针对业务异常,希望大家也能有所收获

责任编辑:庞桂玉 来源: 今日头条
相关推荐

2017-08-10 10:28:43

SpringBootSpring

2022-08-03 07:07:10

Spring数据封装框架

2023-10-10 13:23:18

空指针异常Java

2022-03-04 08:31:07

Spring异常处理

2021-04-20 10:50:38

Spring Boot代码Java

2022-05-03 10:43:43

SpringJava

2023-12-27 07:53:08

全局异常处理处理应用

2023-10-27 08:20:12

springboot微服务

2020-03-16 17:20:02

异常处理Spring Boot

2009-02-06 14:11:36

ASP.NET.NET全局异常处理

2019-08-29 14:30:16

代码开发工具

2023-12-13 13:28:00

Spring全局异常处理架构

2020-08-24 13:35:59

trycatchJava

2022-03-01 21:25:30

对象代码Proxy

2019-03-14 15:59:44

前端开发编程

2021-09-26 09:40:25

React代码前端

2011-05-26 14:43:49

ORACLE数据库异常处理

2011-04-07 15:47:28

MySQL数据库

2023-12-11 14:19:00

Java程序异常

2022-10-26 07:14:25

Spring 6Spring业务
点赞
收藏

51CTO技术栈公众号