拦截器是Spring MVC中强大的控件,它可以在进入处理器之前做一些操作,或者在处理器完成后进行操作,甚至是在渲染视图后进行操作。
拦截器的定义
Spring要求处理器的拦截器都要实现接口org.springframe-work.web.servlet. HandlerInterceptor,这个接口定义了3个方法
•preHandle方法:在处理器之前执行的前置方法,这样Spring MVC可以在进入处理器前处理一些方法了。注意,它将返回一个boolean值,会影响到后面Spring MVC的流程。
•postHandle方法:在处理器之后执行的后置方法,处理器的逻辑完成后运行它。
•afterCompletion方法:无论是否产生异常都会在渲染视图后执行的方法。
•preHandle方法:在处理器之前执行的前置方法,这样Spring MVC可以在进入处理器前处理一些方法了。注意,它将返回一个boolean值,会影响到后面Spring MVC的流程。
•postHandle方法:在处理器之后执行的后置方法,处理器的逻辑完成后运行它。
•afterCompletion方法:无论是否产生异常都会在渲染视图后执行的方法。
拦截器的执行流程
在进入处理器之前或者之后处理一些逻辑,或者在渲染视图之后处理一些逻辑,都是允许的。有时候要自己实现一些拦截器,以加强请求的功能。注意,当前置方法返回false时,就不会再执行后面的逻辑了。在拦截器中可以完成前置方法、后置方法和完成方法的相关逻辑。
开发拦截器
在开发拦截器之前,要先了解拦截器的设计,拦截器必须实现HandlerInterceptor接口,而Spring也为增强功能而开发了多个拦截器。
注意,当XML配置文件加入了元素<mvc:annotation-driven>或者使用Java配置使用注解@EnableWebMvc时,系统就会初始化拦截器ConversionServiceExposingInterceptor,它是个一开始就被Spring MVC系统默认加载的拦截器,它的主要作用是根据配置在控制器上的注解来完成对应的功能。
Spring MVC提供公共拦截器HandlerInterceptorAdapter,Spring之所以那么做,是为了提供适配器,就是当只想实现3个拦截器方法中的一到两个时,那么只要继承它,根据需要覆盖掉原有的方法就可以了。
代码清单15-31:拦截器
代码清单15-32:配置拦截器(比如dispatcher-servlet.xml)
注意,当XML配置文件加入了元素<mvc:annotation-driven>或者使用Java配置使用注解@EnableWebMvc时,系统就会初始化拦截器ConversionServiceExposingInterceptor,它是个一开始就被Spring MVC系统默认加载的拦截器,它的主要作用是根据配置在控制器上的注解来完成对应的功能。
Spring MVC提供公共拦截器HandlerInterceptorAdapter,Spring之所以那么做,是为了提供适配器,就是当只想实现3个拦截器方法中的一到两个时,那么只要继承它,根据需要覆盖掉原有的方法就可以了。
代码清单15-31:拦截器
package com.ssm.chapter15.interceptor; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class RoleInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.err.println("preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.err.println("postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.err.println("afterCompletion"); } }
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/role/*.do"/> <bean class="com.ssm.chapter15.interceptor.RoleInterceptor1"/> </mvc:interceptor> </mvc:interceptors>
多个拦截器执行的顺序
编写拦截器RoleInterceptor1 ,RoleInterceptor2 ,RoleInterceptor3
Spring会先从第一个拦截器开始进入前置方法,这样前置方法是按配置顺序运行的,然后运行处理器的代码,最后运行后置方法。注意,后置方法和完成方法则是按照配置逆序运行的,这和责任链模式的运行顺序是一致的,掌握了责任链模式这个顺序就好理解了。
有些时候前置方法可能返回false,那么返回false会怎么样呢?将RoleInterceptor2中的前置方法preHandle修改为返回false,然后进行测试,其日志结果如下:
注意,当其中的一个preHandle方法返回为false后,按配置顺序,后面的preHandle方法都不会运行了,而控制器和所有的后置方法postHandle也不会再运行。执行过preHandle方法且该方法返回为true的拦截器的完成方法(afterCompletion)会按照配置的逆序运行。
......
preHandle1
preHandle2
preHandle3
......控制器逻辑日志......
postHandle3
postHandle2
postHandle1
......
afterCompletion3
afterCompletion2
afterCompletion1
......
有些时候前置方法可能返回false,那么返回false会怎么样呢?将RoleInterceptor2中的前置方法preHandle修改为返回false,然后进行测试,其日志结果如下:
preHandle1
preHandle2
afterCompletion1