1. 程式人生 > >web應用中的異常處理

web應用中的異常處理

異常類 row server ade actor pack exc request ext

樓主前幾天寫了一篇“Java子線程中的異常處理(通用)”文章,介紹了在多線程環境下3種通用的異常處理方法。

但是平時大家的工作一般是基於開發框架進行的(比如Spring MVC,或Spring Boot),所以會有相應特定的異常處理方法,這篇文章要介紹的就是web應用中的異常處理。

想快速解決問題的小夥伴可以只看“解決辦法”,想進一步了解細節的小夥伴還可以看“深入剖析”部分。

適用場景

使用Spring MVC或Spring Boot框架搭建的web應用

解決辦法

@ControllerAdvice註解 + @ExceptionHandler註解

實現一個異常處理類,在類上應用@ControllerAdvice註解,並在異常處理方法上應用@ExceptionHandler註解。那麽在web應用中,當Controller的@RequestMapping方法拋出指定的異常類型時,@ExceptionHandler修飾的異常處理方法就會執行。

示例:

 1 @ControllerAdvice
 2 public class WebServerExceptionHandler {
 3     Logger log = LoggerFactory.getLogger(this.getClass());
 4 
 5     public
WebServerExceptionHandler() { 6 } 7 8 // 指定捕獲的異常類型,這裏是自定義的SomeException 9 @ExceptionHandler({SomeException.class}) 10 public ResponseEntity<WebServerExceptionResponse> handle(HttpServletResponse response, SomeException ex) { 11 WebServerExceptionResponse body = new
WebServerExceptionResponse(); 12 body.setStatus(ex.getStatus()); 13 body.setMessage(ex.getMessage()); 14 this.log.info("handle SomeException, status:{}, message:{}", new Object[]{body.getStatus(), body.getMessage()}); 15 return new ResponseEntity(body, HttpStatus.valueOf(ex.getStatus())); 16 } 17 18 // 指定捕獲的異常類型,這裏是自定義的OtherException 19 @ExceptionHandler({OtherException.class}) 20 public ResponseEntity<WebServerExceptionResponse> handle(HttpServletResponse response, OtherException ex) { 21 WebServerExceptionResponse body = new WebServerExceptionResponse(); 22 body.setStatus(ex.getStatus()); 23 body.setMessage(ex.getMessage()); 24 this.log.info("handle OtherException, status:{}, message:{}", new Object[]{body.getStatus(), body.getMessage()}); 25 return new ResponseEntity(body, HttpStatus.valueOf(ex.getStatus())); 26 } 27 }

深入剖析

@ControllerAdvice的定義如下:

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

可以看出它應用在TYPE類型的元素上(也即class或interface),運行時生效。

作用是Controller類的幫助註解,一般搭配@ExceptionHandler註解,用來處理Controller的@RequestMapping修飾的方法拋出的異常。

樓主根據源碼的註釋整理了5個參數的含義,它們都是用來限定需要處理的Controller的:

  • value():等同於basePackages,表示需要被處理的Controller包名數組,例如 @ControllerAdvice("org.my.pkg")。如果不指定,就代表處理所有的Controller類
  • basePackages():表示需要被處理的Controller包名數組,例如 @ControllerAdvice(basePackages={"org.my.pkg","org.my.other.pkg"})
  • basePackageClasses():通過標記類來指定Controller包名數組
  • assignableTypes():通過類的Class對象來指定Controller包名數組
  • annotations():被註解修飾的Controller需要被處理

性能考慮:不要指定過多的參數和異常處理策略,因為異常檢查和處理都是在運行時做的。

@ExceptionHandler的定義如下:

 1 @Target(ElementType.METHOD)
 2 @Retention(RetentionPolicy.RUNTIME)
 3 @Documented
 4 public @interface ExceptionHandler {
 5 
 6     /**
 7      * Exceptions handled by the annotated method. If empty, will default to any
 8      * exceptions listed in the method argument list.
 9      */
10     Class<? extends Throwable>[] value() default {};
11 
12 }

可以看出它作用在方法上面,而且參數很好理解,就是需要處理的異常類的Class對象數組。

但是,它對修飾的異常處理方法的參數和返回值有限定,樓主根據源碼的註釋整理如下:

(1)異常處理方法的參數限定,可以是以下類型,順序任意:

  • 異常類對象
  • HttpServletRequest、HttpServletResponse
  • HttpSession
  • InputStream/Reader、OutputStream/Writer

(2)異常處理方法的返回值限定,最終會寫入response流:

  • ResponseEntity
  • HttpServletResponse
  • ModelAndView
  • Model
  • Map
  • View 

總結

以上就是在Spring web應用中的異常處理方法:使用@ControllerAdvice搭配@ExceptionHandler修飾自定義異常處理方法,處理來自Controller類中的@RequestMapping方法拋出的異常。

使用時需要根據實際情況,合理設置@ControllerAdvice和@ExceptionHandler的參數。

web應用中的異常處理