SpringMVC拦截器
拦截器跟过滤器有着相似的地方所以很多人会把他们搞混,这文章将详细讲解一下拦截器的用法与用处。
拦截器:是springmvc框架中的一种对象, 需要实现接口HandlerInterceptor. 拦截用户的请求。 拦截到controller的请求。
作用:拦截用户的请求, 可以预先对请求做处理。 根据处理结果, 决定是否执行controller 。 也可以把多个controller中共用的功能定义到拦截器。
特点:
- 拦截器可以分为系统拦截器和自定义拦截器。
- 一个项目可以多个拦截器。0,或多个自定义拦截器。
- 拦截器侧重拦截用户的请求。
- 拦截器是在请求处理之前先执行的。
拦截器的定义:
1)创建类实现拦截器接口HandlerInterceptor,实现接口中的方法(3个)
2)在springmvc配置文件中,声明拦截器对象,并指定拦截的uri地址
演示:
//创建一个拦截器,拦截器必须得实现HandlerInterceptor接口和方法
public class MyInterceptor implements HandlerInterceptor {
/**
* preHandle: 预先处理请求的方法。
* 参数:
* Object handler : 被拦截的控制器对象(MyController)
* 返回值: boolean
* true: 请求是正确的,可以被controller处理的。
* false: 请求不能被处理, 控制器方法不会执行。 请求到此截止。
* 如果返回值是true则允许执行控制器方法,false反之。
* 特点:
* 1. 预处理方法他的执行时间: 在控制器方法之前先执行的。
* 2. 可以对请求做处理, 可以做登录的检查, 权限的判断, 统计数据等等。
* 3. 决定请求是否执行。
* 4. 控制器方法执行前得经过这里允许
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
/*
*可以在这里面判断是否继续执行控制器的方法
*/
System.out.println("=====MyInterceptor拦截器的preHandle====");
return true;
}
/**
* postHandle: 后处理方法
* 参数:
* Object handler : 被拦截的控制器对象(MyController)
* ModelAndView mv: 控制器方法的返回值(请求的执行结果)
*控制器执行完传来的数据,并没返回到客户端,可以在这里修改
数据再传到客户端。
* 特点:
* 1. 在控制器方法之后执行的。
* 2. 能获取到控制器方法的执行结果。 可以修改原来的执行结果。
* 可以修改数据, 也可以修改视图
* 3. 可以做对请求的二次处理。
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView mv) throws Exception {
System.out.println("=====MyInterceptor拦截器的postHandle====");
}
/**
* afterCompletion: 最后执行的方法
* 请求成功返回到客户端后执行的方法
* 参数:
* Object handler : 被拦截的控制器对象(MyController)
* Exception ex: 异常对象
*
* 特点:
* 1. 在请求处理完成后执行的,
* 请求处理完成的标志是 视图处理完成,对视图执行forward操作后。
*
* 2. 可以做程序最后要做的工作, 释放内存, 清理临时变量。
*
* 3. 方法的执行条件:
* 1)当前的拦截器他的preHandle()方法必须执行。
* 2)preHandle()必须返回true。
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
System.out.println("=====MyInterceptor拦截器的afterCompletion====");
}
}
SpringMVC配置文件
<!--声明拦截器-->
<mvc:interceptors>
<!--声明第一个拦截器-->
<mvc:interceptor>
<!--指定拦截器的拦截地址
path:拦截的uri地址,使用 ** 通配符。
例如: path="/user/**"
http://localhost:8080/user/listUser.do
http://localhost:8080/user/query/queryUser.do
-->
<mvc:mapping path="/**"/>
<!--指定使用的拦截器,指定类(而不是包)-->
<bean class="com.bjpowernode.handler.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
当你的preHandle返回true, 执行结果:
=====MyInterceptor拦截器的preHandle====
执行了MyController的doSome方法
=====MyInterceptor拦截器的postHandle====
=====MyInterceptor拦截器的afterCompletion====
请求的执行顺序: 用户some.do---preHandle---doSome---postHandle--afterComplietion
当 preHandle返回 false
=====MyInterceptor拦截器的preHandle====
多个拦截器
使用两个拦截器, 主要看拦截器的执行顺序,以及按个方法控制请求的执行
1)两个拦截器,第一个preHandle=true, 第二个拦截器preHandle=true
=====MyInterceptor111111拦截器的preHandle====
=====MyInterceptor222222拦截器的preHandle====
执行了MyController的doSome方法
=====MyInterceptor222222拦截器的postHandle====
=====MyInterceptor111111拦截器的postHandle====
=====MyInterceptor222222拦截器的afterCompletion====
=====MyInterceptor111111拦截器的afterCompletion====
请求的执行顺序:
用户some.do—拦截器1的preHandle----拦截器2preHandle—控制器doSome—拦截器2postHandle—拦截器1的postHandle—拦截器2的afterCompletion—拦截器1的afterCompletion。
2)两个拦截器,第一个preHandle=true, 第二个拦截器preHandle=false
=====MyInterceptor111111拦截器的preHandle====
=====MyInterceptor222222拦截器的preHandle====
=====MyInterceptor111111拦截器的afterCompletion====
3)两个拦截器,第一个preHandle=false, 第二个拦截器preHandle=true|false
=====MyInterceptor111111拦截器的preHandle====
为什么要使用多个拦截器 ?
- 把验证功能分散到独立的拦截器。 每个拦截器做单一的验证处理。
- 组合多个拦截器。
总结:
多个拦截器, 串在一个链条上的。 多个拦截器和一个控制器对象在一个链条上 ,框架中使用HandlerExecutionChain(处理器执行链),表示这个执行链条
public class HandlerExecutionChain {
private final Object handler; // 存放控制器对象的,MyController
@Nullable
private HandlerInterceptor[] interceptors; // 存放多个拦截器对象的。MyInterceptor 1, 2
@Nullable
private List<HandlerInterceptor> interceptorList;
}
拦截器怎么实现 1,2, 2,1的执行顺序, 遍历HandlerInterceptor[] interceptors 数组
HandlerInterceptor[] interceptors = { MyInterceptor1, MyInterceptor2};
//循环调用方法 1-2
for(int i=0;i<interceptors.length;i++){
HandlerInterceptor obj= interceptors[i];
obj.preHandle();
}
MyController.doSome();
// 2-1
for(int i=interceptors.length-1 ;i>=0;i--){
HandlerInterceptor obj= interceptors[i];
obj.postHandle();
}
如图:
拦截器和过滤器的对比
1)拦截器是springmvc框架中的对象。 过滤器是servlet中的对象。
2)拦截器对象是框架容器创建的, 过滤器对象是tomcat创建的对象。
-
拦截器是侧重对请求做判断的,处理的, 可以截断请求。 过滤器是侧重对request,response对象的属性,参数设置值的。 例如request.setCharacterEncoding(“utf-8”)
-
拦截器的他执行时间有三个, 控制器方法之前, 之后, 请求完成后。 过滤器是在请求之前。
5)拦截器是拦截对controller,动态资源请求的 。 过滤器可以过滤所有请求动态的和静态的。
6)拦截器和过滤器一起执行的, 先执行的过滤器,后面是 中央调度器 , 后面才是拦截器, 再后面是控制器方法