SpringMVC的请求如以下这样的图所看到的:
能够看出全部的请求都要通过Dispatherservlet来接收,然后通过Handlermapping来决定使用哪个控制器,再依据ViewResolver来决定返回哪个视图.从流程来看,Handlermapping就是我们能够实现拦截器的第一种方法.另外另一种是实现WebRequestInterceptor接口,或者继承其子类.
一.实现HandlerInterceptor接口
实现HandlerInterceptor接口或者继承HandlerInterceptor的子类,比方比方Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter ,以下讲实现其接口的写法,先看一下这个接口的三个方法.
- 方法preHandle: 顾名思义,该方法将在请求处理之前进行调用。SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中能够同一时候存在多个Interceptor 。
每个Interceptor 的调用会依据它的声明顺序依次运行,并且最先运行的都是Interceptor 中的preHandle 方法,所以能够在这种方法中进行一些前置初始化操作或者是对当前请求的一个预处理。也能够在这种方法中进行一些推断来决定请求是否要继续进行下去。
该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,兴许的Interceptor 和Controller 都不会再运行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法。假设已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
- 方法postHandle:由preHandle 方法的解释我们知道这种方法包含后面要说到的afterCompletion 方法都仅仅能是在当前所属的Interceptor 的preHandle 方法的返回值为true 时才干被调用。
postHandle 方法。顾名思义就是在当前请求进行处理之后,也就是Controller 方法调用之后运行。可是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们能够在这种方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的。也就是说先声明的Interceptor 的postHandle 方法反而会后运行,这和Struts2 里面的Interceptor 的运行过程有点类型。
Struts2 里面的Interceptor 的运行过程也是链式的,仅仅是在Struts2 里面须要手动调用ActionInvocation 的invoke 方法来触发对下一个Interceptor 或者是Action 的调用。然后每个Interceptor 中在invoke 方法调用之前的内容都是依照声明顺序运行的,而invoke 方法之后的内容就是反向的。
- 方法afterCompletion:该方法也是须要当前相应的Interceptor 的preHandle 方法的返回值为true 时才会运行。顾名思义。该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了相应的视图之后运行。这种方法的主要作用是用于进行资源清理工作的。
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class SpringMVCInterceptor implements HandlerInterceptor {
/**
* preHandle方法是进行处理器拦截用的,顾名思义,该方法将在Controller处理之前进行调用,SpringMVC中的Interceptor拦截器是链式的。能够同一时候存在
* 多个Interceptor。然后SpringMVC会依据声明的前后顺序一个接一个的运行,并且全部的Interceptor中的preHandle方法都会在
* Controller方法调用之前调用。SpringMVC的这样的Interceptor链式结构也是能够进行中断的。这样的中断方式是令preHandle的返
* 回值为false。当preHandle的返回值为false的时候整个请求就结束了。
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
return false;
}
/**
* 这种方法仅仅会在当前这个Interceptor的preHandle方法返回值为true的时候才会运行。postHandle是进行处理器拦截用的,它的运行时间是在处理器进行处理之
* 后,也就是在Controller的方法调用之后运行。可是它会在DispatcherServlet进行视图的渲染之前运行,也就是说在这种方法中你能够对ModelAndView进行操
* 作。这种方法的链式结构跟正常訪问的方向是相反的,也就是说先声明的Interceptor拦截器该方法反而会后调用。这跟Struts2里面的拦截器的运行过程有点像,
* 仅仅是Struts2里面的intercept方法中要手动的调用ActionInvocation的invoke方法,Struts2中调用ActionInvocation的invoke方法就是调用下一个Interceptor
* 或者是调用action。然后要在Interceptor之前调用的内容都写在调用invoke之前,要在Interceptor之后调用的内容都写在调用invoke方法之后。
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
/**
* 该方法也是须要当前相应的Interceptor的preHandle方法的返回值为true时才会运行。该方法将在整个请求完毕之后,也就是DispatcherServlet渲染了视图运行,
* 这种方法的主要作用是用于清理资源的。当然这种方法也仅仅能在当前这个Interceptor的preHandle方法的返回值为true时才会运行。
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
二.实现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 。
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
public class AllInterceptor implements WebRequestInterceptor {
/**
* 在请求处理之前运行,该方法主要是用于准备资源数据的,然后能够把它们当做请求属性放到WebRequest中
*/
@Override
public void preHandle(WebRequest request) throws Exception {
// TODO Auto-generated method stub
System.out.println("AllInterceptor...............................");
request.setAttribute("request", "request", WebRequest.SCOPE_REQUEST);//这个是放到request范围内的,所以仅仅能在当前请求中的request中获取到
request.setAttribute("session", "session", WebRequest.SCOPE_SESSION);//这个是放到session范围内的,假设环境同意的话它仅仅能在局部的隔离的会话中訪问。否则就是在普通的当前会话中能够訪问
request.setAttribute("globalSession", "globalSession", WebRequest.SCOPE_GLOBAL_SESSION);//假设环境同意的话。它能在全局共享的会话中訪问。否则就是在普通的当前会话中訪问
}
/**
* 该方法将在Controller运行之后,返回视图之前运行。ModelMap表示请求Controller处理之后返回的Model对象,所以能够在
* 这种方法中改动ModelMap的属性,从而达到改变返回的模型的效果。
*/
@Override
public void postHandle(WebRequest request, ModelMap map) throws Exception {
// TODO Auto-generated method stub
for (String key:map.keySet())
System.out.println(key + "-------------------------");;
map.put("name3", "value3");
map.put("name1", "name1");
}
/**
* 该方法将在整个请求完毕之后,也就是说在视图渲染之后进行调用。主要用于进行一些资源的释放
*/
@Override
public void afterCompletion(WebRequest request, Exception exception)
throws Exception {
// TODO Auto-generated method stub
System.out.println(exception + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");
}
}
三.拦截器的配置
1.mvc:interceptors标签来声明须要增加到SpringMVC拦截器链中的拦截器
<mvc:interceptors>
<!-- 使用bean定义一个Interceptor。直接定义在mvc:interceptors根以下的Interceptor将拦截全部的请求 -->
<bean class="com.host.app.web.interceptor.AllInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/test/number.do"/>
<!-- 定义在mvc:interceptor以下的表示是对特定的请求才进行拦截的 -->
<bean class="com.host.app.web.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
由上面的演示样例能够看出能够利用mvc:interceptors标签声明一系列的拦截器,然后它们就能够形成一个拦截器链。拦截器的运行顺序是按声明的先后顺序运行的,先声明的拦截器中的preHandle方法会先运行,然而它的postHandle方法和afterCompletion方法却会后运行。
在mvc:interceptors标签下声明interceptor主要有两种方式:
(1)直接定义一个Interceptor实现类的bean对象。使用这样的方式声明的Interceptor拦截器将会对全部的请求进行拦截。
(2)使用mvc:interceptor标签进行声明。使用这样的方式进行声明的Interceptor能够通过mvc:mapping子标签来定义须要进行拦截的请求路径。
经过上述两步之后。定义的拦截器就会发生作用对特定的请求进行拦截了。
原文链接 http://haohaoxuexi.iteye.com/blog/1750680
样例:
近期正好写了一个简单的登录验证拦截器:
以下拦截器,推断session里面是否存在登录,存在且同意訪问,不存在则跳转到登录页面
package com.aust.interceptor;
import com.aust.model.system.SysUser;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginUserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
String url = httpServletRequest.getRequestURI();
if (url.indexOf("system/login")>0){
return true;
}
//推断session是否已登录
HttpSession session = httpServletRequest.getSession();
SysUser user = (SysUser) session.getAttribute("loginsucess");
if (user != null){
return true;
}
//运行到这里说明没有session,须要拦截
httpServletRequest.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(httpServletRequest,httpServletResponse);
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
须要在springMVC.xml中配置:
<!--訪问拦截-->
<mvc:interceptors>
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根以下的Interceptor将拦截全部的请求 -->
<!--<bean class="com.host.app.web.interceptor.AllInterceptor"/>-->
<mvc:interceptor>
<!-- 对system下的请求全部拦截 -->
<mvc:mapping path="/system/*"/>
<!-- 定义在mvc:interceptor以下的表示是对特定的请求才进行拦截的 -->
<bean class="com.aust.interceptor.LoginUserInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
这样就实现了訪问拦截功能
项目演示样例能够參考:
SSM框架整合: https://github.com/nl101531/JavaWEB