SpringMVC的拦截器,太牛了

目录

没有使用拦截器

拦截器(HandlerInterceptor)

加入拦截器后的SpringMVC

用法:

当存在多个拦截器时如何执行

源码


没有使用拦截器

回顾一下我们springmvc处理请求的方式:

那我们思考一下,springmvc的请求过程,我们如何干预???

比如我们的系统中,除了登录的方法,其他所有方法都需要先验证一下用户是否登录了,若未登录,让用户先跳转到登录页面,最笨的方法是在所有需要验证的方法内部都加上验证的代码,那么有没有更好的方法呢?

如下图,如果我们将验证登录的代码放在调用自定义controller的方法之前,是不是就特别爽了,就不用在所有代码中都添加验证代码了:

springmvc 确实为我们考虑到了这种需求,springmvc 在处理流程中为我们提供了 3 个扩展点可以对整个处理流程进行干预,这个就是 springmvc 中拦截器提供的功能,下面咱们来看一下拦截器怎么玩的。

拦截器(HandlerInterceptor)

springmvc 中使用org.springframework.web.servlet.HandlerInterceptor接口来表示拦截器,如下,提供了 3 个默认方法。

public interface HandlerInterceptor {

   default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
         throws Exception {

      return true;
   }

   default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
         @Nullable ModelAndView modelAndView) throws Exception {
   }

   default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
         @Nullable Exception ex) throws Exception {
   }

}

 ProHandle方法

在调用自定义的 controller 之前会调用这个方法,若返回 false,将跳过 controller 方法的调用,否则将进入到 controller 的方法中。

PostHandle方法

调用自定义 controller 中的方法之后会调用这个方法,此时还没有渲染视图,也就是还没有将结果输出到客户端 

afterCompletion方法

整个请求处理完毕之后,即结果以及输出到客户端之后,调用这个方法,此时可以做一些清理的工作,注意这个方法最后一个参数是 Exception 类型的,说明这个方法不管整个过程是否有异常,这个方法都会被调用。

加入拦截器后的SpringMVC

处理流程如下,黄色部分就是对应HandlerInterceptor的三个方法

 

用法:

  • 自定义一个类,实现HandlerInterceptor接口,重写其三个方法:
public class HandlerInterceptor1 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println(this.getClass().getSimpleName() + ".preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println(this.getClass().getSimpleName() + ".postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println(this.getClass().getSimpleName() + ".afterCompletion");
    }
}
  • 配置如下,需要将自定义的拦截器添加到 springmvc 配置文件中,可以同时配置多个拦截器,每个拦截器通过<mvc:interceptor>标签来定义,多个拦截器之间可以指定顺序,顺序和<mvc:interceptor>定义的顺序一致,每个拦截器需要指定实现类、拦截的 url、排除的 url

<!-- interceptors用来定义拦截器,其内部可以定义多个拦截器 -->
<mvc:interceptors>
    <!-- mvc:interceptor 标签用来定义一个拦截器 -->
    <mvc:interceptor>
        <!-- 用来指定拦截器匹配的url,比如/user/**会拦截所有以/user开头的url -->
        <mvc:mapping path="/user/**"/>
        <!-- 用来指定拦截器排除的url,即这些url不会被拦截器拦截 -->
        <mvc:exclude-mapping path="/user/login"/>
        <!-- 用来指定拦截器 -->
        <bean class="com.javacode2018.springmvc.chat09.intercetor.HandlerInterceptor1"/>
    </mvc:interceptor>

    <!-- 其他拦截器配置信息 -->
    <mvc:interceptor>
        .....
    </mvc:interceptor>

</mvc:interceptors>

当存在多个拦截器时如何执行

这里就不写案例了,知道上面的请求流程就一切都懂了

源码

拦截器的执行过程主要位于下面这段代码中:

org.springframework.web.servlet.DispatcherServlet#doDispatch

如下代码,咱们将关键代码提取出来,大家注意看注释,解释了每个方法内部干的事情,具体每个方法的内部,咱们就不进去了,很简单,有兴趣的可以自己去看,这里给大家提点建议:看源码的时候,先站在高的层次上面看代码,了解大的功能及流程之后,再去细看某个功能点,要避免上来就陷入细节中,容易迷失方向。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    try {
        Exception dispatchException = null;
        try {
            //①、根据请求找到处理器
            mappedHandler = getHandler(processedRequest);
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            //②、内部会调用拦截器的preHandler方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            //③、调用实际的处理器(即这里面会调用咱们controller中的方法)
            ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            //④、调用拦截器的postHandle方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        } catch (Exception ex) {
            dispatchException = ex;
        }

        //⑤、渲染视图 & 调用拦截器的afterCompletion
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    } catch (Exception ex) {
        //⑥:异常情况,调用拦截器的afterCompletion
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰魄雕狼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值