- @ControllerAdvice 註解定義全局異常處理類
@ControllerAdvice public class GlobalExceptionHandler { }
- @ExceptionHandler 註解聲明異常處理方法
方法handleException()會處理所有Controller層拋出的Exception及其子類的異常,Controller層就不需要單獨處理異常了。@ControllerAdvice public class GlobalExceptionHandler{ @ExceptionHandler(Exception.class) @ResponseBody public String handleException() { ex.printStackTrace(); return "fail"; } }
但如上代碼只能處理 Controller 層的異常,對於未進入Controller的異常,如Interceptor(攔截器)層的異常,Spring 框架層的異常無效,還是會將錯誤直接返回給用戶。對此,只需要在配置文件中添加:spring.mvc.throw-exception-if-no-handler-found=true spring.resources.add-mappings=false
- 被 @ExceptionHandler 註解的方法還可以聲明很多種參數類型,具體可以參考文檔:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html
這裏我選擇了httpServletRequest, HttpServletResponse httpServletResponse, Exception ex三個參數,應用如下:@ControllerAdvice public class GlobalExceptionHandler{ @ExceptionHandler(Exception.class) @ResponseBody public CommonReturnType handleException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Exception ex) { ex.printStackTrace(); // 線上環境替換爲對應的log Map<String,Object> responseData = new HashMap<>(); if( ex instanceof BusinessException){ BusinessException businessException = (BusinessException)ex; responseData.put("errCode",businessException.getErrCode()); responseData.put("errMsg",businessException.getErrMsg()); }else if(ex instanceof ServletRequestBindingException){ responseData.put("errCode",BusinessError.UNKNOWN_ERROR.getErrCode()); responseData.put("errMsg","url綁定路由問題"); }else if(ex instanceof NoHandlerFoundException){ responseData.put("errCode",BusinessError.UNKNOWN_ERROR.getErrCode()); responseData.put("errMsg","沒有找到對應的訪問路徑"); }else{ responseData.put("errCode", BusinessError.UNKNOWN_ERROR.getErrCode()); responseData.put("errMsg", BusinessError.UNKNOWN_ERROR.getErrMsg()); } return CommonReturnType.create(responseData,"fail"); } }
如此,所有的 Controller 層的異常日誌都可以通過GlobalExceptionHandler 記錄。Controller 層也不需要在手動記錄異常日誌了。