部分内容摘自开涛的《跟我学SpringMVC.PDF》
拦截器,本质类似于AOP,主要的应用场景:
1.日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV等。
2.权限检查:如登录检测,进入处理器检测是否登录,没有登录返回登录页面。
3.性能监控:记录拦截器进入处理器和离开处理器的时间。
4.通用行为:读取cookie中的用户信息放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器的需要都可以使用拦截器实现。
5.OpenSessionView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。
拦截器有两种实现方式:
1.实现拦截器处理器接口:org.springframework.web.servlet.HandlerInterceptor
preHandle(HttpServletRequest request,HttpServletResponse response, Object handler):预处理回调方法,在Controller前执行,返回true继续执行下一个流程(interceptor或handler)。返回false中断执行,不会再调用拦截器或处理器,可以操作reponse来产生响应。
postHandle(HttpServletRequest request,HttpServletResponse response, Object handler,ModelAndView modelAndView):后处理回调方法,在Controller后(渲染视图前)执行,可以通过对ModeAndView进行处理或对视图进行处理,ModeAndView可能为null
afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex):整个请求完毕的回调方法,在视图渲染完毕时回调。
2.继承拦截器适配器类:org.springframework.web.servlet.handler.HandlerInterceptorAdapter
实现拦截器需要重写三个接口,拦截器适配器为这三个方法做了空实现,可以继承这个类,根据需要重写拦截器的1~3个方法。
区别:
1.拦截器适配器为拦截器接口的三个方法做了空实现,可以根据需要复写这1~3个方法。
2.拦截器适配器实现了AsyncHandlerInterceptor接口,提供afterConcurrentHandlingStarted()函数,用于处理Controller的异步请求
项目配置:
xml:
<!-- 拦截器定义 --> <bean id="logInterceptor" class="com.wang.interceptor.LogInterceptor"/> <bean id="performanceInterceptor" class="com.wang.interceptor.PerformanceInterceptor"/> <bean id="testInterceptorAdapter" class="com.wang.interceptor.TestInterceptorAdapter"/>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <!-- 拦截器配置,顺序执行 --> <property name="interceptors"> <list>
<ref bean="logInterceptor"/> <ref bean="performanceInterceptor"/> <ref bean="testInterceptorAdapter"/> </list> </property> </bean>
java:
package com.wang.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; /** * 日志拦截器 * @author wlyfree */ public class LogInterceptor implements HandlerInterceptor{ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.err.println("LogInterceptor preHandle"); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.err.println("LogInterceptor postHandle"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.err.println("LogInterceptor afterCompletion"); } }
package com.wang.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; /** * 性能拦截器 * @author wlyfree */ public class PerformanceInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.err.println("PerformanceInterceptor preHandle()"); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.err.println("PerformanceInterceptor postHandle()"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.err.println("PerformanceInterceptor afterCompletion()"); } }
package com.wang.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; public class TestInterceptorAdapter extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.err.println("TestInterceptorAdapter preHandle()"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.err.println("TestInterceptorAdapter postHandle()"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.err.println("TestInterceptorAdapter afterCompletion()"); } @Override public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.err.println("TestInterceptorAdapter afterConcurrentHandlingStarted()"); } }
jsp:
<%System.err.println("index.jsp"); %>
效果:
LogInterceptor preHandle() PerformanceInterceptor preHandle() TestInterceptorAdapter preHandle() deal request! TestInterceptorAdapter postHandle() PerformanceInterceptor postHandle() LogInterceptor postHandle() index.jsp TestInterceptorAdapter afterCompletion() PerformanceInterceptor afterCompletion() LogInterceptor afterCompletion()
如果把TestInterceptorAdapter.java的preHandle()返回值改为return false,则效果为:
LogInterceptor preHandle()
PerformanceInterceptor preHandle()
TestInterceptorAdapter preHandle()
PerformanceInterceptor afterCompletion()
LogInterceptor afterCompletion()
分析(详情可以查看源码):
正常流程,拦截器的preHandle()都返回true,则顺序执行:
问题流程:
若拦截器preHandle()返回false,则执行执行所有执行成功的拦截器的afterCompletion(),如拦截器2的preHandle()返回false