前言
在設計Restful 風格API時,如何進行錯誤響應,也是一個重要的環節。我在實踐中發現,如果可以統一封裝錯誤響應,那么會給調用者帶來很大的便利。下面就來說說使用Spring Boot框架時,如何進行統一的錯誤響應。
在Spring Boot項目中有3種級別的異常處理:
- 全局的錯誤處理
- Controller的錯誤處理
- 具體方法中的try/catch處理
為了演示如何使用上面的方式進行錯誤處理,我們假定擁有三個類
- BaseException 其它自定義異常類的父類
- CustomException1 繼承自BaseException
- CustomException2 繼承自BaseException
我們會創建以下幾種方法,來觸發不同的異常
- ex1() throws BaseException
- ex2() throws CustomException1
- ex3() throws CustomException2
- ex4() throws NullPointerException
- ex5() throws NumberFormatException
接著我們來看如何使用上面提到的處理流程來處理不同的異常。
我們創建一個類,用 **@ControllerAdvice **和 @RestController修飾。 這表明本類可以返回一個Rest的響應。
@ControllerAdvice 表明本類會進行應用全局的異常處理。
@RestController 表明本類是一個Controller
使用 @ExceptionHandler 注解 定義需要捕獲的異常類. (基類異常會捕獲派生類異常)
用可以通過使用 @ResponseStatus 注解來修改響應的返回狀態。
** HomeController.class **
<pre>
package com.ekiras.controller;
import com.ekiras.exception.BaseException;
import com.ekiras.exception.CustomException1;
import com.ekiras.exception.CustomException2;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
@author ekansh
-
@since 19/2/16
*/
@RestController
@RequestMapping({"","/"})
public class HomeController {@RequestMapping("/ex1")
public String ex1(){
// 被全局的異常捕獲方法 handleBaseException 捕獲
throw new BaseException("Base Exception");
}@RequestMapping("/ex2")
public String ex2(){
// 被全局的異常捕獲方法 handleCustomException1 捕獲
throw new CustomException1();
}@RequestMapping("/ex3")
public String ex3(){
// 被全局的異常捕獲方法 handleBaseException 捕獲
throw new CustomException2();
}@RequestMapping("/ex4")
public String ex4(){
// 被全局的異常捕獲方法 handleBaseException 捕獲
throw new NullPointerException("null pointer exception");
}@RequestMapping("/ex5")
public String ex5(){
// 被Controller級的異常捕獲方法 nfeHandler 捕獲
throw new NumberFormatException("number format exception");
}/**
- This method will handle all the Number Format Exceptions that arise within this controller.
- */
@ExceptionHandler(value = NumberFormatException.class)
public String nfeHandler(NumberFormatException e){
return e.getMessage();
}
}
</pre>
GlobalExceptionHandler.class
<pre>
package com.ekiras.handler.exception;
import com.ekiras.exception.BaseException;
import com.ekiras.exception.CustomException1;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
/**
@author ekansh
-
@since 19/2/16
*/
@ControllerAdvice
@RestController
public class GlobalExceptionHandler {@ExceptionHandler(value = CustomException1.class)
public String handleCustomException1(CustomException1 e){
return e.getMessage();
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = BaseException.class)
public String handleBaseException(BaseException e){
return e.getMessage();
}
@ExceptionHandler(value = Exception.class)
public String handleException(Exception e){return e.getMessage();}
}
</pre>
結論:
-
handleCustomException1(CustomException1 e)
會捕獲所有來自CustomException1的異常。 -
handleBaseException(BaseException e)
會捕獲所有來自BaseException and CustomException2的異常。 - **handleException(Exception e) :: **
會捕獲所有派生自Exception 類的異常 - 如果有更接近異常類的異常處理方法,那么異常由其優先捕獲,否則繼續向上查找。
- 我們可以使用全局的異常處理流程來捕獲異常進行統一格式的錯誤響應。
參考
http://www.ekiras.com/2016/02/how-to-do-exception-handling-in-springboot-rest-application.html