1.SpringMVC拦截器
所有的controller都会执行拦截器,只不过原来的拦截器都是框架定义好的.
查看doDispatch()方法源码,里面的拦截器先执行applyPreHandle()(第35行),再applyPostHandle()(第45行),后applyAfterConcurrentHandlingStarted()(第62行)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
现在自己来定义一下拦截器
(1)创建拦截器类:
实现HandlerInterceptor接口,继承它的三个方法,preHandle()拦截器开始,postHandle() 拦截器结束,afterCompletion()最后执行
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器开始执行");
//return false表示不继续往后执行true表示继续执行
//拦截器开始执行->controller->拦截器结束
return true;//true表示继续往后执行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器结束执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("无论是否有异常都要执行");
}
}
(2)配置拦截器
拦截所有请求
<mvc:interceptors>
<bean id="my" class="com.pdh.util.MyInterceptor"/>
</mvc:interceptors>
拦截指定请求:
<mvc:interceptors>
<mvc:interceptor >
<mvc:mapping path="/test1" />
<mvc:mapping path="/test2" />
<bean id="my" class="com.pdh.util.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
(3)测试
编写测试类TestInterceptor:
@Controller
public class TestInterceptor {
@RequestMapping("/test")
public void test(){
System.out.println("test--------->");
}
}
启动服务后浏览器端访问
localhost:8080/test
执行后输出的结果
拦截器开始执行
test--------->
拦截器结束执行
无论是否有异常都要执行
(4)说明
-
两个类无须直接的实现一个调用关系,也可以实现代码的附加;
-
拦截器就是基于的aop(面向切面编程)实现的,多个拦截器称为拦截器栈(栈的概念,先进后出,顺序是根据配置文件里面的拦截器添加顺序springmvc.xml文件),(interceptor:拦截器,filter:过滤器)
2.拓展
2.1springMVC拦截器使用场景
1、日志记录 :记录请求信息的日志
2、权限检查,如登录检查
3、性能检测:检测方法的执行时间
2.2 SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系
Filter
依赖于servlet容器,在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
Interceptor
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程 (AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理
多个过滤器与拦截器的代码执行顺序
(1)过滤器的运行是依赖于servlet容器的,跟springmvc等框架并没有关系。并且,多个过滤器的执行顺序跟xml文 件中定义的先后关系有关(先定义先执行)
(2)对于多个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关
最终顺序: