Spring MVC通过HandlerExceptionResolver处理程序的异常,包括Handler 映射、数据绑定以及目标方法执行时发生的异常。在Eclipse中可以查看到HandleExceptionResolver接口的实现类:
如果我们没有在springmvc配置文件中配置<mvc:annotation-driven/>,那么DispatcherServlet会默认装配AnnotationMethodHandlerExceptionResolver、DefaultHandlerExceptionResolver和ResponseStatusException三种解析器,但是其中AnnotationMethodHandlerExceptionResolver已经过期了。所以我们配置<mvc:annotation-driven/>,将会把AnnotationMethodHandlerExceptionResolver替换为ExceptionHandlerExceptionResolver。
下面的例子中,我们都默认已经在spring配置文件中配置了<mvc:annotation-driven/>。
ExceptionHandlerExceptionResolver
ExceptionHandlerExceptionResolver主要用于处理Handler 中用@ExceptionHandler注解标记的方法,示例如下:
页面
index.jsp
error.jsp
控制器
运行程序:
点击index.jsp中的超链接,异常处理器会捕获到异常,在控制台输出:
并跳转到error.jsp,且在该页面打印了异常信息:
需要注意的是:
- @ExceptionHandler标记的方法的入参中不能传入Map。 若希望把异常信息传导页面上, 需要使用 ModelAndView 作为返回值。
- @ExceptionHandler 方法标记的异常有优先级的问题。如果我们在上面的例子中同时声明了可以捕获ArithmeticException异常和RuntimeException异常的两个异常处理器,那么会使用匹配度更高的,即捕获ArithmeticException异常的异常处理器。
- 通过以上方式创建的异常处理器只能处理该控制器类内部的异常,若需要统一配置可以捕获所有控制器类抛出的异常,可以新建一个异常处理器类,在类的声明处用@ControllerAdvice注解标记即可。如果在当前 控制器类 中找不到 @ExceptionHandler 方法来处理当前方法出现的异常, 则将去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常。例如,我们现在创建一个异常处理器类,并在其中定义一个可以处理数学异常的方法:12345678910111213public class SpringMVCTestExceptionHandler {private static final String ERROR = "error";public ModelAndView handleArithmeticException1(Exception ex){ModelAndView mv = new ModelAndView(ERROR);System.out.println("[出异常了]:"+ex);mv.addObject("exception",ex);return mv;}}
注释掉之前定义的handleArithmeticException方法,运行程序,与之前的例子类似,仍然跳转到error.jsp,但是在控制台输出:
表示执行的是我们新定义的handleArithmeticException1方法,注意,如果不注释掉handleArithmeticException方法,那么会优先执行handleArithmeticException方法,因为handleArithmeticException方法和抛出异常的testExceptionHandlerExceptionResolver方法定义在同一个控制器类中,testExceptionHandlerExceptionResolver方法抛出异常后会先在当前 控制器类 中找 @ExceptionHandler方法来处理当前方法出现的异常,如果找不到,才会去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常。
ResponseStatusExceptionResolver
ResponseStatusExceptionResolver的作用是在异常及异常父类中找到@ResponseStatus注解,然后使用这个注解的属性进行处理。下面举例说明:
页面
定义一个异常类
模拟一个可以抛出上述异常的方法
运行程序,由于抛出了异常,并且我们没有定义任何异常处理器对该异常进行处理,那么会出现我们定制的异常页面:
此外,@ResponseStatus注解还可以用来标记方法:
现在,我们在浏览器中令i=10,这样方法是不会抛出UserNameNotMatchPasswordException异常的,结果程序跳转到了如下页面:
但是控制台上输出了如下信息,说明这个方法被正常地执行了:
DefaultHandlerExceptionResolver
对一些特殊的异常进行处理,比如NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException等,具体处理哪些异常可以在DefaultHandlerExceptionResolver源码中查看doResolveException()方法。
SimpleMappingExceptionResolver
SimpleMappingExceptionResolver可以将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。下面进行测试:
页面
index.jsp
error.jsp
控制器
spring配置文件
运行程序:
由于目标方法抛出了数组下标越界异常,程序跳转到了error.jsp页面,并且在页面上打印了异常信息,这是因为在SimpleMappingExceptionResolver中有一个String类型的属性exceptionAttribute,其默认值为exception,所以我们在error.jsp中通过${exception }可以获取到。也可以在配置文件中配置exceptionAttribute的值,例如:
那么,此时需要在error.jsp中通过如下方式在可以获取到异常信息: