Spring全局異常處理


最近學習Spring時,認識到Spring異常處理的強大。之前處理工程異常,代碼中最常見的就是try-catch-finally,有時一個try,多個catch,覆蓋了核心業務邏輯:

復制代碼
1 try{ 2  .......... 3 }catch(Exception1 e){ 4  .......... 5 }catch(Exception2 e){ 6  ........... 7 }catch(Exception3 e){ 8  ........... 9 }
復制代碼

Spring能夠較好的處理這種問題,核心如下,文章主要關注前兩個:

  • @ExceptionHandler:統一處理某一類異常,從而能夠減少代碼重復率和復雜度
  • @ControllerAdvice:異常集中處理,更好的使業務邏輯與異常處理剝離開
  • @ResponseStatus:可以將某種異常映射為HTTP狀態碼

@ExceptionHandler

源碼如下:

復制代碼
1 @Target({ElementType.METHOD}) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 public @interface ExceptionHandler { 5 Class<? extends Throwable>[] value() default {}; 6 }
復制代碼

 

該注解作用對象為方法,並且在運行時有效,value()可以指定異常類。由該注解注釋的方法可以具有靈活的輸入參數(詳細參見Spring API):

  • 異常參數:包括一般的異常或特定的異常(即自定義異常),如果注解沒有指定異常類,會默認進行映射。
  • 請求或響應對象 (Servlet API or Portlet API): 你可以選擇不同的類型,如ServletRequest/HttpServletRequest或PortleRequest/ActionRequest/RenderRequest
  • Session對象(Servlet API or Portlet API): HttpSession或PortletSession。
  • WebRequest或NativeWebRequest 
  • Locale
  • InputStream/Reader 
  • OutputStream/Writer 
  • Model

方法返回值可以為:

  • ModelAndView對象
  • Model對象
  • Map對象
  • View對象
  • String對象
  • 還有@ResponseBody、HttpEntity<?>或ResponseEntity<?>,以及void

@ControllerAdvice

源碼如下:

復制代碼
 1 @Target({ElementType.TYPE})  2 @Retention(RetentionPolicy.RUNTIME)  3 @Documented  4 @Component  5 public @interface ControllerAdvice {  6 @AliasFor("basePackages")  7 String[] value() default {};  8  9 @AliasFor("value") 10 String[] basePackages() default {}; 11 12 Class<?>[] basePackageClasses() default {}; 13 14 Class<?>[] assignableTypes() default {}; 15 16 Class<? extends Annotation>[] annotations() default {}; 17 }
復制代碼

 

該注解作用對象為TYPE,包括類、接口和枚舉等,在運行時有效,並且可以通過Spring掃描為bean組件。其可以包含由@ExceptionHandler、@InitBinder 和@ModelAttribute標注的方法,可以處理多個Controller類,這樣所有控制器的異常可以在一個地方進行處理。

實例

 異常類:

復制代碼
 1 public class CustomGenericException extends RuntimeException{  2 private static final long serialVersionUID = 1L;  3  4 private String errCode;  5 private String errMsg;  6  7 public String getErrCode() {  8 return errCode;  9  } 10 11 public void setErrCode(String errCode) { 12 this.errCode = errCode; 13  } 14 15 public String getErrMsg() { 16 return errMsg; 17  } 18 19 public void setErrMsg(String errMsg) { 20 this.errMsg = errMsg; 21  } 22 23 public CustomGenericException(String errCode, String errMsg) { 24 this.errCode = errCode; 25 this.errMsg = errMsg; 26  } 27 }
復制代碼

 

控制器:

復制代碼
 1 @Controller  2 @RequestMapping("/exception")  3 public class ExceptionController {  4  5 @RequestMapping(value = "/{type}", method = RequestMethod.GET)  6 public ModelAndView getPages(@PathVariable(value = "type") String type) throws Exception{  7 if ("error".equals(type)) {  8 // 由handleCustomException處理  9 throw new CustomGenericException("E888", "This is custom message"); 10 } else if ("io-error".equals(type)) { 11 // 由handleAllException處理 12 throw new IOException(); 13 } else { 14 return new ModelAndView("index").addObject("msg", type); 15  } 16  } 17 }
復制代碼

 

異常處理類:

復制代碼
 1 @ControllerAdvice  2 public class ExceptionsHandler {  3  4 @ExceptionHandler(CustomGenericException.class)//可以直接寫@ExceptionHandler,不指明異常類,會自動映射  5 public ModelAndView customGenericExceptionHnadler(CustomGenericException exception){ //還可以聲明接收其他任意參數  6 ModelAndView modelAndView = new ModelAndView("generic_error");  7 modelAndView.addObject("errCode",exception.getErrCode());  8 modelAndView.addObject("errMsg",exception.getErrMsg());  9 return modelAndView; 10  } 11 12 @ExceptionHandler(Exception.class)//可以直接寫@EceptionHandler,IOExeption繼承於Exception 13 public ModelAndView allExceptionHandler(Exception exception){ 14 ModelAndView modelAndView = new ModelAndView("generic_error"); 15 modelAndView.addObject("errMsg", "this is Exception.class"); 16 return modelAndView; 17  } 18 }
復制代碼

 

JSP頁面:

正常頁面index.jsp:

復制代碼
 1 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  2 <html>  3 <body>  4 <h2>Spring MVC @ExceptionHandler Example</h2>  5  6 <c:if test="${not empty msg}">  7 <h2>${msg}</h2>  8 </c:if>  9 10 </body> 11 </html>
復制代碼

 

異常處理頁面generic_error.jsp

復制代碼
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <html> <body> <c:if test="${not empty errCode}"> <h1>${errCode} : System Errors</h1> </c:if> <c:if test="${empty errCode}"> <h1>System Errors</h1> </c:if> <c:if test="${not empty errMsg}"> <h2>${errMsg}</h2> </c:if> </body> </html>
復制代碼

 

測試運行如下:

正常情況:

 

CustomGenericException異常情況:

IOException異常情況:

總結

  • @ExceptionHandler和@ControllerAdvice能夠集中異常,使異常處理與業務邏輯分離
  • 本文重點理解兩種注解方式的使用

 

參考:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM