Spring MVC拦截器

重点:Spring MVC的拦截器只会拦截控制器的请求,如果是jsp、js、image、html则会放行。

什么是拦截器

运行在服务器的程序,先于Servlet或JSP之前运行实现对请求资源的拦截,可以拦截一个或多个Servlet或JSP,可以先于Servlet或JSP检查请求信息,也可以处理响应信息。

什么是SpringMVC拦截器

Spring MVC独特的拦截器,根据在Spring MVC配置文件中定义的拦截规则去拦截控制器(Controller)的请求,如果请求时jsp、js、image、html则不会拦截(这点与在web配置的DispatcherServlet所拦截的范围并不冲突

使用SpringMVC拦截器

创建SpringMVC拦截器

使用Spring MVC会导致只有一个Servlet(DispatcherServlet),所以拦截器在物理模型中处在DispatchServlet与Controller之间。要实现Spring MVC拦截器主要有两种方法,现在只介绍其中一个方法用作理解Spring MVC拦截器的作用。

实现HandlerInterceptor接口

HandlerInterceptor接口为Spring MVC提供的拦截器接口之一,所以我们来实现一个Spring MVC拦截器:

MyInterceptor:
// 定义拦截器拦截请求
public class MyIntercept implements HandlerInterceptor {
    // 依赖注入
    @Autowired
    private MyController controller;

    /**
     * preHandle:在DispatcherServlet请求单元方法执行之前执行,并根据该方法的返回值判断是否放行。
     *
     * 利用HandlerMethod对象调用当前的单元方法,只会执行方法体,但是不会返回单元方法的ModelAndView的对象,可以拿到HttpServletRequest、HttpServletResponse对象
     * 进行页面的重定向或者转发
     *
     *
     * @param httpServletRequest 由DispatcherServlet传递的httpServletRequest
     * @param httpServletResponse 由DispatcherServlet传递的httpServletResponse
     * @param o 这个就是HandlerMethod,是反射的另一种方式,储存了单元方法的方法对象
      * @return 是否放行
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println(o instanceof HandlerMethod);
        HandlerMethod hm = (HandlerMethod) o;
        Method method = hm.getMethod();
        method.invoke(controller,httpServletResponse);
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("MyIntercept.postHandle");

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("MyIntercept.afterCompletion");
    }
}

根据上面代码,我们看出该接口提供了3个方法:

  • preHandles:先于单元方法执行前执行。
  • postHandle:在调用方法后解析视图前执行。
  • afterCompletion:在视图渲染后执行,即整个请求完成。

其实这三个方法的作用段很好理解。

preHandle:DispatcherServlet根据请求调用Controller中的单元方法,而拦截器此时拦截了请求,则会优先调用MyInterceptor中的preHandle方法,在此方法中判断是否对该请求放行,如果放行返回true,反之则返回false,其中的Object类型的o对象,其实是HandlerMethod对象(有需要自己百度),为什么会有这个对象呢?我的理解是不论这个请求被拦截后放不放行,咱们的用户总要得到一个结果,所以如果因为其他原因不放行,但是结果却在单元方法中得出,这个时候就可以利用HandlerMethod对象得到Method对象再反射调用单元方法得出结果响应给用户。

postHandle:如果请求放行,则会调用单元方法,当方法体执行完毕,返回视图时(ModelAndView)给视图解析器时,这个时候就会进入到postHandle中进行请求和模型数据的修改(如果有需求的话),执行完成便会将修改好的ModelAndView交给视图解析器进行解析并渲染视图。为什么需要传入ModelAndView? 有时我们可能需要对数据或者视图进行进一步调正处理,比如在固定时间段的敏感词汇,届时可能不在单元方法中进行处理,所以我们就会在此方法中进行数据处理。

afterCompletion:此方法的作用段就在视图渲染完成后调用,主要是用来对资源的关闭,比如IO流亦或者是异常的处理。

光定义了拦截器还不行,我们需要在Spring MVC的配置文件中配置咱们定义的拦截器,接下里就是配置文件了:

 <context:component-scan base-package="com.lyl.controller"/>

    <mvc:annotation-driven/>

    <mvc:resources mapping="/js/**" location="/js/"/>
    <mvc:resources mapping="/img/**" location="/img/"/>
    <mvc:resources mapping="/css/**" location="/css/"/>
    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <!-- 配置全局拦截器,将会拦截所有的请求 -->
        <bean id="all" class="com.lyl.intercept.AllIntercept"/>
        <!-- 可以配置多个拦截器,并声明其拦截范围,以及定义的拦截器 -->
        <mvc:interceptor>
            <!-- 设置拦截器的范围 -->
            <mvc:mapping path="/demo"/>
            <!-- 配置拦截器的bean对象 -->
            <bean id="my1" class="com.lyl.intercept.MyIntercept"/>
        </mvc:interceptor>
        
        <mvc:interceptor>
            <!-- 设置拦截器的范围 -->
            <mvc:mapping path="/demo1"/>
            <mvc:mapping path="/demo2"/>
            <mvc:mapping path="/my/*"/> <!-- *标识为通配符 -->
            <!-- 配置拦截器的bean对象 -->
            <bean id="my1" class="com.lyl.intercept.MyIntercept"/>
        </mvc:interceptor>
        <!-- 可以嵌套多个拦截器,拦截器的顺序也会有所不同,将拦截器看作是环绕通知执行,方法体时自生而下,画一个物理视图就简单明了 -->
    </mvc:interceptors>