統一的異常處理對於應用的重要性不言而喻。今天咱們來介紹一下 Spring 如何來進行統一的 Rest 異常處理。同時咱們也會簡單比較一下它們之間的優劣。html
在控制器中聲明一個方法而後用 @ExceptionHandler
註解標記便可:java
@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())); } }
優勢:web
@ExceptionHandler
標記的方法返回值類型支持多種。能夠是視圖,也能夠是 json
等。缺點:編程
Controller
中的 @ExceptionHandler
註解上的異常類型不能出現相同的,不然運行時拋異常。Controller
並非真正意義上的全局異常。若是要想做用於全局須要將其放入全部控制器的父類中。這是 2. 的改進型,經過定義 @ControllerAdvice
類並在方法上標記 @ExceptionHandler
,達到了全局異常處理的目的:json
@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())); } }
優勢:segmentfault
缺點:app
Controller
中的 @ExceptionHandler
註解上的異常類型不能出現相同的,不然運行時拋異常。通常狀況下也建議使用該方式進行異常處理。大多數狀況下都是兼容的。框架
實現 HandlerExceptionResolver
接口,這裏咱們繼承其抽象實現 AbstractHandlerExceptionResolver
:ide
@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(); } }
優勢:編碼
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 獲取更多資訊