Spring異常處理@ExceptionHandler

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

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

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

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

@ExceptionHandler

源碼以下:spring

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

 

該註解做用對象爲方法,而且在運行時有效,value()能夠指定異常類。由該註解註釋的方法能夠具備靈活的輸入參數(詳細參見Spring API):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

方法返回值能夠爲:spring-mvc

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

@ControllerAdvice

源碼以下:mvc

 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類,這樣全部控制器的異常能夠在一個地方進行處理。app

實例

 異常類:jsp

 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可以集中異常,使異常處理與業務邏輯分離
  • 本文重點理解兩種註解方式的使用

 

參考:

相關文章
相關標籤/搜索