SpringMVC (17)_Exception Handling

       Foreword: This article mainly introduces the related concepts and usage of data verification in the data binding process of SpringMVC .

       Spring MVC handles exceptions through HandlerExceptionResolver, including Handler mapping, data binding, and exceptions that occur when the target method is executed. The test page is as follows:


  

1. Implementation class of HandlerExceptionResolver


      DispatcherServlet will by default assemble the HandlerExceptionResolver implementation class :

      If the <mvc:annotation-driven/> configuration is not used:

  • AnnotationMethodHandlerExceptionResolver(obsolete);
  • ResponseStatusExceptionResolver;
  • DefaultHandlerExceptionResolver;

       If using <mvc:annotation-driven/> configuration :

  • ExceptionHandlerExceptionResolver;
  • ResponseStatusExceptionResolver;
  • DefaultHandlerExceptionResolver;

       When using SpringMVC as the MVC framework, it is generally necessary to configure <mvc:annotation-driven/>, and ExceptionHandlerExceptionResolver is also the main method to handle exceptions in Hander.

2. ExceptionHandlerExceptionResolver

       ExceptionHandlerExceptionResolver mainly handles the methods defined with the @ExceptionHandler annotation in the controller Handler.

The method priority problem       defined by the @ExceptionHandler annotation : For example, NullPointerException occurs , but the declared exceptions are RuntimeException and Exception. At this time, the @ExceptionHandler annotation method with the shallowest inheritance depth will be found according to the recent inheritance relationship of the exception, that is, the mark method for RuntimeException.

       If the method annotated by @ExceptionHandler cannot be found inside the ExceptionHandlerMethodResolver, it will look for the @ExceptionHandler method in @ControllerAdvice globally.

 

       Background test code:

@RequestMapping("/testExceptionHandlerExceptionResolver.action")
public String testExceptionHandlerExceptionResolver(@RequestParam("i") int i){
    System.out.println("result: " + (10 / i)); // If the divisor is 0, an ArithmeticException runtime exception will occur
    return "success";
}

/**
 * 1. A parameter of type Exception can be added to the input parameter of the @ExceptionHandler method, which corresponds to the exception object that occurred
 * 2. Map cannot be passed in the input parameter of @ExceptionHandler method. If you want to transmit exception information to the page, you need to use ModelAndView as the return value
 * 3. @ExceptionHandler 方法标记的异常有优先级的问题. 
 * 4. @ControllerAdvice: 如果在当前 Handler 中找不到 @ExceptionHandler 方法来出来当前方法出现的异常, 
 * 则将去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常. 
 */
@ExceptionHandler({ArithmeticException.class})
public ModelAndView handleArithmeticException(Exception ex){
    System.out.println("【ArithmeticException】: " + ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);
    return mv;
}

@ExceptionHandler({RuntimeException.class})
public ModelAndView handleArithmeticException2(Exception ex){
    System.out.println("【RuntimeException】: " + ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);
    return mv;
}

        如果testExceptionHandlerExceptionResolver方法抛出ArithmeticException异常,根据异常优先级,会先被handleArithmeticException方法捕获。如果上述handleArithmeticException和handleArithmeticException2异常处理方法都未定义,但在SpringMVCTestExceptionHandler类中定义异常处理,如下所示:

@ControllerAdvice
public class SpringMVCTestExceptionHandler {

    @ExceptionHandler({ArithmeticException.class})
    public ModelAndView handleArithmeticException(Exception ex){
        System.out.println("【ControllerAdvice】" + ex);
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception", ex);
        return mv;
    }
    
}

        处理器内部若找不到@ExceptionHandler注解的方法,会全局找@ControllerAdvice中的@ExceptionHandler方法进行异常处理。

 

 3. ResponseStatusExceptionResolver

         控制器方法上或是修饰异常类使用@ResponseStatus 注解,则ResponseStatusExceptionResolver会使用这个注解的属性进行处理

         后台测试代码:

         1. 首先@ResponseStatus修饰异常处理类:

@ResponseStatus(value=HttpStatus.FORBIDDEN, reason="自定义异常")
public class CustomizedException extends RuntimeException{
    private static final long serialVersionUID = 1L;
}

           2. 然后是@ResponseStatus在控制器中修饰方法(测试中同时是功能处理方法):

@ResponseStatus(reason="测试",value=HttpStatus.NOT_FOUND)
@RequestMapping("/testResponseStatusExceptionResolver.action")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
    if(i == 13){
        throw new CustomizedException();
    }
    System.out.println("testResponseStatusExceptionResolver...");
    
    return "success";
}

           说明:若i == 13,则返回异常类定义的响应;若i  != 13,则返回异常方法定义的响应。

         3. 前台代码略,可参见附件代码

        4. 测试结果

            (测试的时候将ExceptionHandlerExceptionResolver对异常处理的操作去掉,以免会捕获i == 13时抛出的自定义异常!)

            当i == 13时


               当 i != 13时:

 4. DefaultHandlerExceptionResolver

        DefaultHandlerExceptionResolver对一些特殊的异常进行处理,如:

        后台测试代码为:
@RequestMapping("/testSimpleMappingExceptionResolver.action")
public String testSimpleMappingExceptionResolver(@RequestParam("i") int i){
    String [] vals = new String[10];
    System.out.println(vals[i]);
    return "success";
}

          vals数组大小为10,若入参的i大小超过9,则会数组越界,会抛出java.lang.ArrayIndexOutOfBoundsException异常。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326269172&siteId=291194637