Spring 異常處理之全域性處理
阿新 • • 發佈:2019-01-31
承接上文Spring異常處理之本地處理,本文介紹spring異常處理的第三種方式,也就是全域性處理。為什麼將該方式取名為全域性處理,其實很簡單,因為該方式本質上和本地處理是一樣的,無非就是本地處理將異常處理方法或者說異常處理邏輯直接寫在controller中,而全域性處理其實就是把本地處理中的異常處理方法抽取出來,放到一個地方集中管理。
- 控制器以及業務方法
/** * 結合 GlobalExceptionHandlerControllerAdvice 使用 */ @Controller @RequestMapping(value = {"/global"}) public class WithoutExceptionHandlerController { /** * Throws an unannotated <tt>DataIntegrityViolationException</tt>. Must be caught by an * exception handler. * * @return Nothing - it always throws the exception. * @throws DataIntegrityViolationException Always thrown. */ @RequestMapping("/dataIntegrityViolation") String throwDataIntegrityViolationException() { throw new DataIntegrityViolationException("ID 重複"); } /** * Simulates a database exception by always throwing <tt>SQLException</tt>. Must be caught by an * exception handler. * * @return Nothing - it always throws the exception. * @throws SQLException Always thrown. */ @RequestMapping("/sqlException") public String throwSqlException() throws SQLException { throw new SQLException(); } /** * Always throws a <tt>SupportInfoException</tt>. Must be caught by an exception handler. * * @return Nothing - it always throws the exception. */ @RequestMapping("/supportInfoException") public String throwCustomException() { throw new SupportInfoException("出錯了"); } }
- 集中在一起的異常處理邏輯
/** * 結合 WithoutExceptionHandlerController 使用 * * 對比 ExceptionHandlerController 可以發現,其實這個全域性異常處理就是通過使用 ControllerAdvice 註解將 ExceptionHandler * * 從 controller 中提取出來集中到一處 */ @ControllerAdvice public class GlobalExceptionHandlerControllerAdvice { private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandlerControllerAdvice.class); /** * 異常處理之 @ControllerAdvice 之一 */ @ResponseStatus(value = HttpStatus.CONFLICT, reason = "資料衝突") @ExceptionHandler(DataIntegrityViolationException.class) public void conflict() { // 什麼也不做 } /** * 異常處理之使用 @ControllerAdvice 之二 | 指定了 view * * @param exception 異常物件 * @return 檢視名稱 */ @ExceptionHandler({SQLException.class}) public String databaseError(Exception exception) { logger.info(exception.toString()); return "database.error"; } /** * 異常處理之使用 @ControllerAdvice 之三 | 完全控制 - model 、view 、有用的異常資訊 * * @param req 當前的 HTTP 請求物件. * @param exception 丟擲的異常 - 也就是 {@link SupportInfoException}. * @return 模型和檢視 * @throws Exception 異常 */ @ExceptionHandler(SupportInfoException.class) public ModelAndView handleError(HttpServletRequest req, Exception exception) throws Exception { if (AnnotationUtils.findAnnotation(exception.getClass(), ResponseStatus.class) != null) throw exception; logger.error("Request: " + req.getRequestURI() + " raised " + exception); ModelAndView mav = new ModelAndView(); // 注意這裡,這個 exception 是一個物件 | 而 DefaultErrorAttributes 中的 exception 是異常物件的完全限定名 mav.addObject("exception", exception); mav.addObject("url", req.getRequestURL()); mav.addObject("timestamp", new Date().toString()); mav.addObject("status", 500); mav.setViewName("support.error"); return mav; } }
對比上一篇文章我們可以發現,唯一的不同之處就是該方式通過使用@ControllerAdvice註解將所有的異常處理邏輯集中起來了。
到這裡為止,三種異常處理的方式就介紹完了。其實我們可以看出來,本地處理和全域性處理其實是一樣的。關於到底使用哪種方式更合適呢,個人認為第三種是最合適的,因為第一種需要繫結HTTP狀態碼,第二種將異常處理邏輯直接寫在controller中,導致業務程式碼和異常處理程式碼混在一起,第三種明顯靈活的多。
- 參考