javascript
Spring 3.2的REST异常处理
1.概述
本文將重點介紹如何使用REST API的Spring實現異常處理 。 我們將介紹在Spring 3.2之前可用的較舊的解決方案,然后是對Spring 3.2的新支持。
本文的主要目的是展示如何最好地將應用程序中的異常映射到HTTP狀態代碼。 哪種狀態代碼不適合本文中的哪種情況,REST錯誤表示的語法也不屬于本文的范圍。
在Spring 3.2之前,在Spring MVC應用程序中處理異常的兩種主要方法是: HandlerExceptionResolver和@ExceptionHandler批注。 Spring 3.2引入了新的@ControllerAdvice注釋,以解決前兩種解決方案的局限性。
所有這些確實有一個共同點–它們很好地處理了關注點分離 :標準應用程序代碼可以正常拋出異常以指示某種類型的失敗–然后可以通過以下任意方式處理異常。
2.通過控制器級別
定義帶有@ExceptionHandler注釋的Controller級別方法非常容易:
public class FooController{...@ExceptionHandler({ CustomException1.class, CustomException2.class })public void handleException() {//} }一切都很好,但是這種方法確實有一個主要缺點–帶@ExceptionHandler注釋的方法僅對特定Controller有效 ,而不對整個應用程序全局有效。 當然,這使其不適用于通用異常處理機制。
一個常見的解決方案是讓應用程序中的所有Controller都擴展Base Controller類 -但是,對于由于某種原因無法使Controllers擴展為此類的應用程序來說,這可能是個問題。 例如,控制器可能已經從另一個基類擴展了,該基類可能在另一個jar中,或者不能直接修改,或者它們本身也不能直接修改。
接下來,我們將討論另一種解決異常處理問題的方法-一種全局的方法,不包括對現有工件(如Controllers)的任何更改。
3.通過
為了在REST API中實現統一的異常處理機制 ,我們需要使用HandlerExceptionResolver-這將解決應用程序在運行時拋出的所有異常。 在尋求自定義解析器之前,讓我們看一下現有的實現。
3.1。 ExceptionHandlerExceptionResolver
該解析器是在Spring 3.1中引入的,默認情況下已在DispatcherServlet中啟用。 這實際上是前面介紹的@ ExceptionHandler機制如何工作的核心組件。
3.2。 DefaultHandlerExceptionResolver
該解析器是在Spring 3.0中引入的,默認情況下已在DispatcherServlet中啟用。 它用于將標準Spring異常解析為其對應的HTTP狀態代碼,即客戶端錯誤– 4xx和服務器錯誤– 5xx狀態代碼。 這是它處理的Spring Exception 的完整列表 ,以及如何將它們映射到狀態代碼。
盡管它確實正確設置了響應的狀態碼,但此解析器的一個局限性在于它沒有對響應的主體設置任何內容。 但是,在REST API的上下文中,狀態代碼確實不足以向客戶端提供信息-響應也必須具有正文,以允許應用程序提供有關失敗原因的其他信息。
這可以通過配置View分辨率和通過ModelAndView渲染錯誤內容來解決,但是解決方案顯然不是最優的-這就是為什么Spring 3.2提供了更好的選擇的原因-我們將在本文的后半部分討論。
3.3。 ResponseStatusExceptionResolver
該解析器也在Spring 3.0中引入,默認情況下在DispatcherServlet中啟用。 它的主要職責是使用自定義異常上可用的@ResponseStatus批注,并將這些異常映射到HTTP狀態代碼。
這樣的自定義異常可能看起來像:
@ResponseStatus(value = HttpStatus.NOT_FOUND) public final class ResourceNotFoundException extends RuntimeException {public ResourceNotFoundException() {super();}public ResourceNotFoundException(String message, Throwable cause) {super(message, cause);}public ResourceNotFoundException(String message) {super(message);}public ResourceNotFoundException(Throwable cause) {super(cause);} }與DefaultHandlerExceptionResolver一樣 ,此解析器在處理響應主體方面也受到限制 -它確實將狀態代碼映射到響應上,但主體仍為null。
3.4。 SimpleMappingExceptionResolver和AnnotationMethodHandlerExceptionResolver
SimpleMappingExceptionResolver已經存在了很長時間–它來自較早的Spring MVC模型,并且與REST Service無關 。 它用于將異常類名稱映射到視圖名稱。
Spring 3.0中引入了AnnotationMethodHandlerExceptionResolver來通過@ExceptionHandler批注處理異常,但是從Spring 3.2開始, ExceptionHandlerExceptionResolver已棄用該方法。
3.5。 自定義HandlerExceptionResolver
DefaultHandlerExceptionResolver和ResponseStatusExceptionResolver的組合在為Spring RESTful Service提供良好的錯誤處理機制方面有很長的路要走-但主要的限制-無法控制響應的主體-證明創建新的異常解析器是合理的。
因此,新解析器的一個目標是啟用一個信息量更大的響應主體,該主體也應符合客戶端請求的表示類型(由Accept標頭指定):
@Component public class RestResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver {@Overrideprotected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {try {if (ex instanceof IllegalArgumentException) {return handleIllegalArgument((IllegalArgumentException) ex, response, handler);}...} catch (Exception handlerException) {logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);}return null;}private ModelAndView handleIllegalArgument(IllegalArgumentException ex, HttpServletResponse response) throws IOException {response.sendError(HttpServletResponse.SC_CONFLICT);String accept = request.getHeader(HttpHeaders.ACCEPT);...return new ModelAndView();} }這里需要注意的一個細節是請求本身是可用的,因此應用程序可以考慮客戶端發送的Accept標頭的值。 例如,如果客戶端要求輸入application / json,則在出現錯誤情況時,應用程序仍應返回以application / json編碼的響應正文。
另一個重要的實現細節是返回ModelAndView -這是響應的主體,它將允許應用程序對其進行必要的設置。
這種方法是用于Spring REST服務的錯誤處理的一致且易于配置的機制。 但是它確實有局限性 :它與低級HtttpServletResponse交互,并且適合使用ModelAndView的舊MVC模型-因此仍有改進的空間。
4.通過新的
Spring 3.2通過新的@ControllerAdvice批注支持全局@ExceptionHandler 。 這將啟用一種機制,該機制有別于舊的MVC模型,并利用ResponseEntity以及@ExceptionHandler的類型安全性和靈活性:
@ControllerAdvice public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {@ExceptionHandler(value = { IllegalArgumentException.class, IllegalStateException.class })protected ResponseEntity<Object> handleConflict(RuntimeException ex, WebRequest request) {String bodyOfResponse = "This should be application specific";return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);} }新的批注允許將之前分散的多個@ExceptionHandler合并到單個全局錯誤處理組件中 。
實際的機制非常簡單,但也非常靈活:
- 它允許完全控制響應的主體以及狀態代碼
- 它允許將多個異常映射到同一方法,以便一起處理
- 它充分利用了更新的RESTful ResposeEntity響應
5.結論
本教程討論了幾種在Spring中為REST API實現異常處理機制的方法,從較舊的機制開始,一直到對Spring 3.2的新支持。 要在現實世界的REST服務中完整實現這些異常處理機制,請查看github項目 。
翻譯自: https://www.javacodegeeks.com/2013/02/exception-handling-for-rest-with-spring-3-2.html
總結
以上是生活随笔為你收集整理的Spring 3.2的REST异常处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样申请微信账号注册
- 下一篇: 使用Spring Security添加R