在系统中,经常需要在处理用户请求前后执行一些行为,如“权限检测”和“日志记录”,当然不仅这些,还有在请求的前后添加处理逻辑。
SpringMVC提供了Interceptor拦截器机制,有两种实现的方法:
- 实现HandlerInterceptor接口,或者继承实现了该接口的类(如:HandlerInterceptorAdapter)
- 实现Spring的WebRequestInterceptor接口,或者继承实现了该接口的类。
1. HadnlerInterceptor接口
1.1 HandlerInterceptor接口源码:
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception;
void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception;
}
- preHandle方法:在Handler方法之前执行,返回false表示拦截请求,不再向下执行。返回true表示放行。(返回true才能执行以下方法)这个方法可以对请求进行判断,决定程序是否继续执行,或者进行一些前置初始化操作及对请求做预处理。
- postHandle方法:在Handler方法之后,返回modelAndView之前执行。由于该方法会在DispatcherServlet进行返回视图渲染之前被调用,所以此方法多用于统一处理返回的视图。例如:将公用的模型数据(例如导航栏菜单)添加到视图,或者根据其他情况指定公用的视图。
- afterCompletion方法:在执行完Handler之后执行。由于是在Controller方法执行完毕后执行该方法,所以该方法适合进行统一的异常或日志处理操作。
1.2 拦截器配置
实现接口之后,需要在Spring的类加载配置文件中配置才能生效。
有两种配置方式:“针对HandlerMapping配置”和“全局配置”。
针对HandlerMapping配置样例:
<!--拦截器映射器配置-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="hInterceptor1"/>
<ref bean="hInterceptor2"/>
</list>
</property>
</bean>
<bean id="hInterceptor1" class="cn.com.mvc.interceptor.HandlerInterceptorDemo1"/>
<bean id="hInterceptor2" class="cn.com.mvc.interceptor.HandlerInterceptorDemo2"/>
- 优点:针对具体的处理器映射器进行拦截操作。
- 缺点:当处理器映射器很多时,配置比较繁琐。
全局配置
<!--全局拦截器配置-->
<mvc:interceptors>
<!--多个拦截器顺序执行-->
<mvc:interceptor>
<!--/** 表示所有url包括子url路径-->
<mvc:mapping path="/**"/>
<bean class="cn.com.mvc.interceptor.HandlerInterceptorDemo1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.com.mvc.interceptor.HandlerInterceptorDemo2"/>
</mvc:interceptor>
</mvc:interceptors>
2. WebRequestInterceptor接口
HandlerInterceptor主要进行请求前和请求后的拦截,而WebRequestInterceptor接口针对请求的拦截器接口,该接口方法参数中没有response,所以使用该接口只进行请求数据准备和处理。
2.1 WebRequestInterceptor接口源码
package org.springframework.web.context.request;
import org.springframework.ui.ModelMap;
public interface WebRequestInterceptor {
void preHandle(WebRequest var1) throws Exception;
void postHandle(WebRequest var1, ModelMap var2) throws Exception;
void afterCompletion(WebRequest var1, Exception var2) throws Exception;
}
每个方法中都有WebRequest参数,WebRequest的方法定义与HttpServletRequest基本相同。对WebRequest进行的所有操作都讲同步到HttpServletRequest中,然后在当前请求中一直传递。
-
preHandle方法:在Handler方法之前执行。该方法返回值为void,即无返回值。所以该方法主要进行书的前期准备。
利用WebRequest的setAttribute(name, value, scope)方法,将需要准备的参数放到WebRequest属性中。scope参数类型为Integer,在WebRequest的父层接口RequestAttributes中为它定义了三个常量。
常量名 | 真实值 | 释义 |
---|---|---|
SCOPE_REQUEST | 0 | 代表只有在request中可以访问。 |
SCOPE_SESSION | 1 | 如果环境允许它代表一个局部的隔离的session,否则就代表普通的session,并且在该session范围内可以访问。 |
SCOPE_GLOBAL_SESSION | 2 | 如果环境允许,它代表一个全局共享的session,否则就代表普通的session,并且在该session范围内可以访问 |
- postHandle方法:在Handler方法之后,返回modelAndView之前执行。其中有一个数据模型ModelMap,它是Controller处理之后返回的Model对象,可以通过改变ModelMap中的属性来该拜年Controller最终返回的Model模型。
- afterCompletion方法:在执行完Handler之后执行。若之前的preHandle方法中的WebRequest准备了一些参数,那么这里可以将WebRequest参数中不需要的准备资源释放掉。
WebRequestInterceptor拦截接口与HandlerInceptor有两点区别:
- HandlerInterceptor接口的preHandle有一个Boolean类型的返回值,而WebRequestInterceptor的preHandle方法没有返回值。
- HandlerInterceptor是针对请求的整个过程的,接口方法中都含有response参数。而WebRequestInterceptor是针对请求的,接口方法参数中没有response。