SpringBoot全局異常與數據校驗

異常處理是每個項目中都繞不開的話題,那麼如何優雅的處理異常,是本文的話題。本文將結合SpringBoot框架一起和大家探討下。

要思考的問題

在現在的前後端交互中,通常都規範了接口返回方式,如返回的接口狀態(成功|失敗)以及要返回的數據在那個字段取,或者說失敗了以後提示信息從接口哪裏返回,因此,如果想做全局異常,並且異常發生後能準確的返回給前端解析,那麼需要異常發生時返回給前端的格式與正常失敗場景的格式一致。

項目建立

利用idea 工具,很容易的搭建一個SpringBoot項目,要引入的maven依賴如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

很簡單,除了加入web功能還加入了我們需要用到的JSR-303校驗框架。

定義成功失敗 返回碼

public class Code {

    /**
     * 成功
     */
    public static int SUCCESSED = 1;
    /**
     * 失敗
     */
    public static int FAILED = -1;
}

定義接口返回響應實體

public class Response<T> implements Serializable{

   /**
    * 
    */
   private static final long serialVersionUID = 4250719891313555820L;
   /**
    * 返回結果集
    */
   private T result;
   /**
    * 返回消息
    */
   private String msg;
   /**
    * 響應碼
    */
   private Integer code;
   //set get 略
}

全局異常攔截和驗證

定義自定義業務異常

public class MyException extends RuntimeException {

    private static final long serialVersionUID = -5875371379845226068L;


    public MyException(){}

    public MyException(String msg){
        this.msg = msg ;
    }

    /**
     * 異常信息
     */
    private String msg ;

    /**
     * 具體異常碼
     */
    private int code = Code.FAILED;
   get set 略 

編寫全局異常控制器並對自定義異常做處理

@ControllerAdvice
public class GlobalExceptionHandler {
     private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = MyException.class)
@ResponseBody
public Response<String> myExceptionErrorHandler(MyException ex) throws Exception {
    logger.error("myExceptionErrorHandler info:{}",ex.getMessage());
    Response<String> r = new Response<>();
    r.setMsg(ex.getMsg());
    r.setCode(ex.getCode());
    return r;
}

編寫controller模擬拋出業務異常

@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping(value = "/update")
Response<Boolean> update(User user){

    //todo 此處爲模擬異常拋出
    if(true){
        throw new MyException("更新失敗");
    }
    //todo 此處爲模擬返回
    Response<Boolean> response = new Response<>();
    response.setCode(Code.SUCCESSED);
    response.setResult(true);
    return  response;
}

}

postMan模擬請求接口,進行驗證

在這裏插入圖片描述

數據綁定異常處理

通常我們操作數據的時候,不僅前端需要進行數據校驗,後端也應當進行攔截和進行相應的錯誤提示,
JSR-303校驗框架也是我們的一種選擇。

編寫實體User,並對屬性進行註解控制

public class User {

    @NotNull(message = "用戶名不能爲空")
    private String userName;

    private  int age;
   //...

全局異常控制類加入攔截

@ControllerAdvice
public class GlobalExceptionHandler {
     private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

     @ExceptionHandler(value = BindException.class)
     @ResponseBody
     public Response<String> bindExceptionErrorHandler(BindException ex) throws Exception {
          logger.error("bindExceptionErrorHandler info:{}",ex.getMessage());
          Response<String> r = new Response<>();
          StringBuilder sb = new StringBuilder();
          FieldError fieldError = ex.getFieldError();
          sb.append(fieldError.getDefaultMessage());
          r.setMsg(sb.toString());
          r.setCode(Code.FAILED);
          return r;
     }
  //...

編寫控制器

@RestController
@RequestMapping("/user")
public class UserController {

    @PostMapping(value = "/add")
    Response<User> add(@Validated User user){

        //todo 此處爲模擬返回
        Response<User> response = new Response<>();
        response.setCode(Code.SUCCESSED);
        response.setResult(new User());
        return  response;
    }
  //...

postMan模擬請求

不填寫任何屬性,模擬添加操作,準確進行攔截和報錯
在這裏插入圖片描述

代碼地址

代碼地址:https://github.com/pengziliu/spring-boot-2.0-leaning
項目結構預覽:

在這裏插入圖片描述
在這裏插入圖片描述

結尾

適合的纔是最好的,每個團隊都應摸索出自己的一套異常解決方案,本文所提僅針對業務異常,希望大家也能有所收穫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章