SpringMVC的所有请求都要通过Dispatherservlet
来接收,然后通过Handlermapping
来决定使用哪个控制器,再根据ViewResolver
来决定返回哪个视图,从流程来看,Handlermapping
就是我们可以实现拦截器的第一种方法,另外还有一种是实现WebRequestInterceptor
接口,或者继承其子类。
实现HandlerInterceptor接口
实现HandlerInterceptor
接口或者继承HandlerInterceptor
的子类,比如Spring
已经提供的实现了HandlerInterceptor
接口的抽象类HandlerInterceptorAdapter
,下面讲实现其接口的写法。
实现WebRequestInterceptor接口
WebRequestInterceptor
中定义了三个方法,我们也是通过这三个方法来实现拦截的。这三个方法都传递了同一个参数WebRequest
,那么这个WebRequest
是什么呢?这个WebRequest
是Spring
定义的一个接口,它里面的方法定义都基本跟HttpServletRequest
一样,在WebRequestInterceptor
中对WebRequest
进行的所有操作都同步到HttpServletRequest
中,然后在当前请求中一直传递。
- 方法
preHandle
: 方法将在请求处理之前进行调用,也就是说会在Controller
方法调用之前被调用。这个方法跟HandlerInterceptor
中的preHandle
是不同的,主要区别在于该方法的返回值是void
,也就是没有返回值,所以我们一般主要用它来进行资源的准备工作,比如我们在使用Hibernate
的时候可以在这个方法中准备一个Hibernate
的Session
对象,然后利用WebRequest
的setAttribute(name, value, scope)
把它放到WebRequest
的属性中。这里可以说说这个setAttribute方法的第三个参数
scope,该参数是一个
Integer类型的。在
WebRequest的父层接口
RequestAttributes中对它定义了三个常量:
SCOPE_REQUEST: 它的值是0,代表只有在
request中可以访问。
SCOPE_SESSION: 它的值是1,如果环境允许的话它代表的是一个局部的隔离的
session,否则就代表普通的
session,并且在该
session范围内可以访问。
SCOPE_GLOBAL_SESSION: 它的值是2,如果环境允许的话,它代表的是一个全局共享的
session,否则就代表普通的
session,并且在该
session`范围内可以访问。 - 方法
postHandle
: 该方法将在请求处理之后,也就是在Controller
方法调用之后被调用,但是会在视图返回被渲染之前被调用,所以可以在这个方法里面通过改变数据模型ModelMap
来改变数据的展示。该方法有两个参数,WebRequest
对象是用于传递整个请求数据的,比如在preHandle
中准备的数据都可以通过WebRequest
来传递和访问;ModelMap
就是Controller
处理之后返回的Model
对象,我们可以通过改变它的属性来改变返回的Model
模型。 - 方法
afterCompletion
: 该方法会在整个请求处理完成,也就是在视图返回并被渲染之后执行。所以在该方法中可以进行资源的释放操作。而WebRequest
参数就可以把我们在preHandle
中准备的资源传递到这里进行释放。Exception
参数表示的是当前请求的异常对象,如果在Controller
中抛出的异常已经被Spring
的异常处理器给处理了的话,那么这个异常对象就是是null
。
|
|
拦截器的配置
mvc:interceptors标签来声明需要加入到SpringMVC拦截器链中的拦截器
由上面的示例可以看出可以利用mvc:interceptors
标签声明一系列的拦截器,然后它们就可以形成一个拦截器链,拦截器的执行顺序是按声明的先后顺序执行的,先声明的拦截器中的preHandle
方法会先执行,然而它的postHandle
方法和afterCompletion
方法却会后执行。
在mvc:interceptors
标签下声明interceptor
主要有两种方式:
1) 直接定义一个Interceptor
实现类的bean对象。使用这种方式声明的Interceptor
拦截器将会对所有的请求进行拦截。
2) 使用mvc:interceptor
标签进行声明。使用这种方式进行声明的Interceptor
可以通过mvc:mapping
子标签来定义需要进行拦截的请求路径。
经过上述两步之后,定义的拦截器就会发生作用对特定的请求进行拦截了。