拦截器
1. Spring MVC拦截器应用
1.1. Spring MVC拦截器概述
拦截器是SpringMVC中的一个核心应用组件,主要用于处理多个Controller的共性问题.当我们的请求由DispatcherServlet派发到具体Controller之前首先要执行拦截器中一些相关方法,在这些方法中可以对请求进行相应预处理(例如权限检测,参数验证),这些方法可以决定对这个请求进行拦截还是放行.通过spring mvc 架构图分析,拦截器在Spring MVC中处理流程中的一个位置
回顾Spring MVC详细架构图
各组件在企业架构中定位
思考:
1)假如对请求数据进行编码,是应在过滤器还是拦截器?推荐使用过滤器.
2)拦截器有哪些有些应用场景呢?(处理后台控制业务的共性)
a)进行身份认证(判定用户是否是合法用户)
b)进行系统监控
c)进行日志记录
d)..........
1.2. Spring MVC拦截器编写及基本配置
拦截器如何编写?
我们自己编写Spring MVC拦截器需要实现HandlerInterceptor接口或者继承此接口的实现类 HandlerInterceptorAdapter(继承这个类时可根据需求重写必要的方法)
例如定义一个拦截器,计算controller方法的执行时间
public class TimeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle( HttpServletRequest request,
HttpServletResponse response,
Object handler)throws Exception {
System.out.println("time.preHandle");
long startTime=System.nanoTime();
request.setAttribute("startTime", startTime);
return true;//true表示放行,false表示拦截
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler,ModelAndView modelAndView) throws Exception {
System.out.println("time.postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("time.afterCompletion");
long endTime=System.nanoTime();
long startTime=(Long)request.getAttribute("startTime");
System.out.println("time:"+(endTime-startTime));
}
}
这些方法的简易执行流程点如下图所示:
这些方法的详细的执行时间点如下:(如何知道如下执行流程?)
我们自己的拦截器编写完成以后需要在spring配置文件中进行配置,,
例如:
<mvc:interceptors>
<mvc:interceptor>
<!-- 指定拦截哪些请求路径 -->
<mvc:mapping path="/**"/>
<!-- 排除要拦截的路径 -->
<mvc:exclude-mapping path="/user/doLogin.do"/>
<!-- 拦截器(这个bean也可以通过ref方式引用,前提是在外面要通过xml或注解方式定义)-->
<bean class="com.spring.TimeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
1.3. Spring MVC拦截器链及配置实现
当我们系统中有多个拦截器时,这些拦截器可以构成一个拦截器链.其原理类似过滤器中的过滤链。在多个拦截器应用中仅当所有匹配的拦截器的preHandle()都执行之后,才会调用Controller中处理请求的方法,然后再执行所有匹配的拦截器的postHandler(),最后执行所有匹配的拦截器的afterCompletion()。
在拦截器链中,各拦截器的执行先后顺序取决于配置文件中配置的节点的先后顺序!
例如:再定义一个日志拦截器
@Component
public class LogInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
System.out.println("log.preHandler");
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
System.out.println("log.afterCompletion");
}
}
配置日志拦截器
<!-- 配置拦截器 (要注意标签的编写顺序)-->
<mvc:interceptors>
<!-- 当存在多个拦截器时,哪个拦截器的方法先执行,要看拦截器配置的顺序 -->
<mvc:interceptor>
<mvc:mapping path="/user/*"/>
<ref bean="logInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<!-- 拦截所有请求(这些请求要交给拦截器处理) -->
<mvc:mapping path="/**"/>
<!-- 定制对哪些请求不拦截 (这些请求不需要拦截处理)-->
<mvc:exclude-mapping path="/user/doLogin.do"/>
<!-- 拦截器对象 -->
<bean class="com.spring.TimeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
思考:
1) 多个拦截器时,其执行顺序有什么决定?(配置顺序)
2) 拦截器对象何时创建?(启动时创建)
3) 拦截器对象在内存中有几份?(一份)
4) 拦截器中存在变量共享时可能会有线程安全问题吗?(有)
5) Spring管理的Bean对象中存在变量共享时可能会有线程安全吗?(有)
6) 多个拦截器对象如何共享数据?
(通过request,session,ServletContext,)
7) 拦截器对象的生命周期何时结束?(容器销毁时)
8) 拦截器可以解决什么问题?(Controller中共性问题,例如日志处理,系统监控,...)
9) ......