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)说明

  1. 两个类无须直接的实现一个调用关系,也可以实现代码的附加;
  2. 拦截器就是基于的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的配置文件中定义的先后顺序有关

最终顺序:

spring 过滤器 执行顺序 spring过滤器和拦截器顺序_拦截器