統一的異常處理對於應用的重要性不言而喻。今天咱們來介紹一下 Spring 如何來進行統一的 Rest 異常處理。同時咱們也會簡單比較一下它們之間的優劣。html
在控制器中聲明一個方法而後用 @ExceptionHandler
註解標記便可:web
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/err")
@ResponseBody
public Object demo1(){
int i = 1 / 0;
return new Date();
}
@ExceptionHandler({RuntimeException.class})
public ModelAndView fix(Exception ex){
System.out.println(ex.getMessage());
return new ModelAndView("error",new ModelMap("ex",ex.getMessage()));
}
}複製代碼
優勢:編程
@ExceptionHandler
標記的方法返回值類型支持多種。能夠是視圖,也能夠是 json
等。 缺點:json
Controller
中的 @ExceptionHandler
註解上的異常類型不能出現相同的,不然運行時拋異常。 Controller
並非真正意義上的全局異常。若是要想做用於全局須要將其放入全部控制器的父類中。 這是 2. 的改進型,經過定義 @ControllerAdvice
類並在方法上標記 @ExceptionHandler
,達到了全局異常處理的目的:app
@ControllerAdvice
public class TestController {
@ExceptionHandler({RuntimeException.class})
public ModelAndView fix(Exception ex){
System.out.println(ex.getMessage());
return new ModelAndView("error",new ModelMap("ex",ex.getMessage()));
}
}複製代碼
優勢:框架
缺點:ide
Controller
中的 @ExceptionHandler
註解上的異常類型不能出現相同的,不然運行時拋異常。 通常狀況下也建議使用該方式進行異常處理。大多數狀況下都是兼容的。編碼
實現 HandlerExceptionResolver
接口,這裏咱們繼承其抽象實現 AbstractHandlerExceptionResolver
:spa
@Component
public class RestResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver {
@Override
protected ModelAndView doResolveException(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
try {
if (ex instanceof IllegalArgumentException) {
return handleIllegalArgument((IllegalArgumentException) ex, response, handler);
}
//todo more exception
} catch (Exception handlerException) {
//todo
}
return null;
}
private ModelAndView
handleIllegalArgument(IllegalArgumentException ex, HttpServletResponse response)
throws IOException {
response.sendError(HttpServletResponse.SC_CONFLICT);
String accept = request.getHeader(HttpHeaders.ACCEPT);
//todo more response
return new ModelAndView();
}
}複製代碼
優勢:code
JSP
、velocity
等模板視圖比較方便。 ModelAndView
可是由於參數中有 HttpServletResponse
, 咱們能夠利用它來進行定製響應結果。例如,若是客戶端要求輸入application / json
,那麼在出現錯誤狀況時,咱們要確保咱們返回一個以application / json
編碼的響應。 缺點:
HttpServletResponse
交互才能實現各類形式的響應體。 若是你用的框架是 Spring Boot 。 咱們還能夠用它獨特的處理方式。優勢是屏蔽了低級的API,缺點也比較明顯,沒法捕捉到具體的異常。
Spring Boot 在默認狀況下,提供了 /error
映射來處理全部錯誤,在 Servlet 容器裏註冊了全局的錯誤頁面(Whitelabel Error Page)並返回客戶端。經過實現 ErrorController 接口並註冊爲 Bean。這裏再也不舉例。可參考 BasicErrorController
。
ErrorAttributes
咱們也能夠添加 ErrorAttributes 類型的 Bean 來替換替換默認的異常處理。
@Component
public class MyCustomErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(
WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes =
super.getErrorAttributes(webRequest, includeStackTrace);
errorAttributes.put("locale", webRequest.getLocale()
.toString());
errorAttributes.remove("error");
//todo your business
return errorAttributes;
}
}複製代碼
Spring Boot 自動配置還提供了實現 ErrorController 接口異常處理的基類 BasicErrorController,默認是處理 text/html類型請求的錯誤,能夠繼承該基類自定義處理更多的請求類型,添加公共方法並使用 @RequestMapping 註解的 produce屬性指定處理類型。
@Component
public class MyErrorController extends BasicErrorController {
public MyErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes, new ErrorProperties());
}
@RequestMapping(produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<Map<String, Object>> xmlError(HttpServletRequest request) {
//todo your business
}
}複製代碼
另外在最新的 Spring 5 中你還能夠經過 拋出 ResponseStatusException
異常來進行處理。
好處:
缺點:
咱們對經常使用的、不經常使用的 Spring 處理異常的方式進行了總結和優劣上的分析。 相信你能夠從中找到適合你的處理方式。若是對你有用請幫忙點一個贊,您的鼓勵,個人動力!
關注公衆號:Felordcn獲取更多資訊