笔记来源:【尚硅谷】SpringMVC教程丨一套快速上手spring mvc

拦截器和异常处理

1、拦截器

1.1、拦截器的配置

SpringMVC 中的拦截器用于拦截控制器方法的执行,需要实现HandlerInterceptor,并在 SpringMVC 的配置文件中进行配置

方式一

后台测试代码

  1. public class MyInterceptor implements HandlerInterceptor {
  2. @Override
  3. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  4. System.out.println("MyInterceptor==>preHandle");
  5. return HandlerInterceptor.super.preHandle(request, response, handler);
  6. }
  7. @Override
  8. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  9. System.out.println("MyInterceptor==>postHandle");
  10. HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
  11. }
  12. @Override
  13. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  14. System.out.println("MyInterceptor==>afterCompletion");
  15. HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
  16. }
  17. }

配置拦截器

  1. <mvc:interceptors>
  2. <bean id="myInterceptor" class="com.vectorx.springmvc.s00_helloworld.interceptor.MyInterceptor"></bean>
  3. </mvc:interceptors>

访问任意路径,后台日志信息

  1. MyInterceptor==>preHandle
  2. MyInterceptor==>postHandle
  3. MyInterceptor==>afterCompletion

方式二

后台测试代码

  1. @Component
  2. public class MyInterceptor implements HandlerInterceptor {
  3. // 略同
  4. }

配置拦截器

  1. <mvc:interceptors>
  2. <ref bean="myInterceptor"></ref>
  3. </mvc:interceptors>

访问任意路径,后台日志信息

  1. MyInterceptor==>preHandle
  2. MyInterceptor==>postHandle
  3. MyInterceptor==>afterCompletion

方式三

后台测试代码

  1. @Component
  2. public class MyInterceptor implements HandlerInterceptor {
  3. // 略同
  4. }

配置拦截器

  1. <mvc:interceptors>
  2. <mvc:interceptor>
  3. <mvc:mapping path="/**"/>
  4. <mvc:exclude-mapping path="/"/>
  5. <ref bean="myInterceptor"></ref>
  6. </mvc:interceptor>
  7. </mvc:interceptors>

此时除了访问/即首页时不会走拦截器,其他请求都会走拦截器,其后台日志信息

  1. MyInterceptor==>preHandle
  2. MyInterceptor==>postHandle
  3. MyInterceptor==>afterCompletion

注意:这里的path路径配置的是/**,表示任意层路径的请求,符合Ant风格的路径。这与web.xmlurl-pattern/*匹配效果一致,但写法不同

小结

  • 方式一和方式二都是对DispatcherServlet所处理的所有请求进行拦截
  • 方式三可以有选择拦截请求,通过refbean设置拦截器,通过mvc:mapping设置需要拦截的请求,通过mvc:exclude-mapping设置需要排除(即不需要拦截)的请求

1.2、拦截器的三个抽象方法

  • preHandle:控制器方法执行之前执行preHandle(),其 boolean 类型的返回值表示是否拦截或放行
    • 返回 true 表示放行,即调用控制器方法
    • 返回 false 表示拦截,即不调用控制器方法
  • postHandle:控制器方法执行之后执行postHandle()
  • afterCompletion:处理完视图和模型数据,渲染视图完毕之后执行afterCompletion()

1.3、多个拦截器的执行顺序

若每个拦截器的preHandle()都返回true

此时多个拦截器的执行顺序和拦截器在 SpringMVC 的配置文件的配置顺序有关:

preHandle()会按照配置的顺序执行,而postHandle()afterComplation()会按照配置的反序执行

配置顺序

  1. <mvc:interceptors>
  2. <ref bean="myInterceptor"></ref>
  3. <ref bean="myInterceptor2"></ref>
  4. </mvc:interceptors>

后台日志信息

  1. MyInterceptor==>preHandle
  2. MyInterceptor2==>preHandle
  3. MyInterceptor2==>postHandle
  4. MyInterceptor==>postHandle
  5. MyInterceptor2==>afterCompletion
  6. MyInterceptor==>afterCompletion

可以看出,preHandle顺序执行,postHandleafterCompletion反序执行

若某个拦截器的preHandle()返回了false

preHandle()返回 false 和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回 false 的拦截器之前的拦截器的afterComplation()会执行

后台测试代码

  1. @Component
  2. public class MyInterceptor2 implements HandlerInterceptor {
  3. @Override
  4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  5. System.out.println("MyInterceptor2==>preHandle");
  6. return false;
  7. }
  8. // 略同
  9. }

后台日志信息

  1. MyInterceptor==>preHandle
  2. MyInterceptor2==>preHandle
  3. MyInterceptor==>afterCompletion

2、异常处理

2.1、基于配置的异常处理

SpringMVC 提供了一个处理控制器方法执行过程中所出现异常的接口:HandlerExceptionResolver

HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolverSimpleMappingExceptionResolver

07-拦截器和异常处理 - 图1

SpringMVC 提供了自定义的异常处理器SimpleMappingExceptionResolver

配置文件

  1. <bean id="simpleMappingExceptionResolver"
  2. class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
  3. <property name="exceptionMappings">
  4. <props>
  5. <!--
  6. properties的键表示处理器方法执行过程中出现的异常
  7. properties的值表示若出现指定异常,设置一个新的视图名称,跳转到指定页面
  8. -->
  9. <prop key="java.lang.ArithmeticException">error</prop>
  10. </props>
  11. </property>
  12. <!--设置一个属性名,将出现的异常信息共享在请求域中-->
  13. <property name="exceptionAttribute" value="ex"></property>
  14. </bean>

后台测试代码

  1. @RequestMapping("testException")
  2. public String testException() {
  3. int i = 1 / 0;
  4. return "success";
  5. }

测试结果

07-拦截器和异常处理 - 图2

2.2、基于注解的异常处理

  • @ControllerAdvice标识当前类为异常处理的组件
  • @ExceptionHandler设置所标识方法处理的异常

配置注解

  1. // ControllerAdvice 标识当前类为异常处理的组件
  2. @ControllerAdvice
  3. public class ExceptionController {
  4. // ExceptionHandler 设置所标识方法处理的异常
  5. @ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})
  6. // ex 表示当前请求处理过程中出现的异常对象
  7. public String testException(Exception ex, Model model) {
  8. model.addAttribute("ex", ex);
  9. return "error";
  10. }
  11. }

测试结果

07-拦截器和异常处理 - 图3

总结

本节重点掌握

  • 拦截器的自定义方法、三种配置方式、三个抽象方法及执行顺序
  • 异常处理解析器的两种方式:基于配置和基于注解

附上导图,仅供参考

07-拦截器和异常处理.png