Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括处理器映射、数据绑定及处理器执行时发生的异常。HandlerExceptionResolver 仅有一个接口方法。
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,Object handler,Exception ex)
当发生异常时,Spring MVC 将调用 resolveException()方法,并转到 ModelAndView 对应的视图中,作为一个异常报告页面反馈给用户。
HandlerExceptionResolver 拥有4个实现类,分别是 DefaultHandlerExceptionResolver、
SimpleMappingExceptionResolver、AnnotationMethodHandlerExceptionResolver 以及 ResponseStatusExceptionResolver。
1.DefaultHandlerExceptionResolver
Spring MVC 默认装配了 DefaultHandlerExceptionResolver,它会将 Spring MVC 框架的异常转换为相应的响应状态码,具体说明如下图所示。
可以在 web.xml 中为响应状态码配置一个对应的页面,代码如下:
<error-page> <error-code>404</error-code> <location>/404.htm</location> </error-page>
2.AnnotationMethodHandIerExceptionResoIver
Spring MVC 默认注册了 AnnotationMethodHandlerExceptionResolver,它允许通过 @ExceptionHandler 注解指定处理特定异常的方法,如下面代码所示。
@Controller @RequestMapping("/user") public class UserController { @RequestMapping(value = "/throwException")//① public String throwException() { if(2>1){ throw new RuntimeException("ddd"); } return "success"; } @ExceptionHandler(RuntimeException.class)//② public String handleException(RuntimeException re, HttpServletRequest request) { return "forward:/error.jsp"; } }
①处的处理方法在调用时抛出一个 RuntimeException 异常,它会被处于同一处理器类中②处的 handleException() 方法捕获。@ExceptionHandler 可以指定多个异常,如 @ExceptionHandler({AException.class, BException.class})。异常处理方法的标签非常灵活,请参见 ExceptionHandler 的 Javadoc 文档
不清楚是 Spring MVC 的 Bug 还是有意为之,标注 @ExceptionHandler 的异常处理方法只能对同一处理类中的其他处理方法进行异常响应处理,笔者现在还受困于 @ExceptionHandler 的这个限制中。
ResponseStatusExceptionResolver 和 AnnotationMethodHandlerExceptionResolver 类似,允许通过 @ResponseStatus 注解标注一个方法,用于处理特定类型的响应状态码。
3.SimpleMappingExceptionResolver
如果希望对所有异常进行统一处理,则可以使用 SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。
请看下面的异常映射配置片段:
<bean id="handlerExceptionResolver class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.springframework.dao.DataAccessException">dataAccessFailure</prop>① <prop key="org.springframework.transaction.TransactionException">dataAccessFailure</prop>② </props> </property> </bean>
在①处指定当控制器发生 DataAccessException 异常时,使用 dataAccessFailure 视图显示。在②处指定当控制器发生 TransactionException 异常时,使用 dataAccessFailure 视图显示。
当然,用户也可以自己实现 ExceptionResolver 覆盖 resolveException() 接口方法,编写自己的异常解析器,执行一些特定的工作,如将异常信息保存到数据库中等。编写好自定义的 ExceptionResolver,在 smart-servlet.xml 中注册成一个 Bean 即可工作。
RequestContextHolder的使用
在 Spring API 中提供了一个非常便捷的工具类 RequestContextHolder,能够在 Controller 中获取 request 和 session 对象。其使用方法如下:
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder·getRequestAttributes()).getRequest();
需要注意的是,如果直接使用该工具类,则会抛出一个空指针异常,原因是还需要在 web.xml 中配置一个监听器,代码如下:
<listener> <listener-class> org·springframework.web,context.request.RequestContextListener </listener-class> </listener>