【内含源码】SpringMVC 拦截器实现原理和登录实现

SpringMVC 拦截器的原理图

springMVC 拦截器的实现一般有两种方式

第一种方式是要定义的 Interceptor 类要实现了 Spring 的 HandlerInterceptor 接口

第二种方式是继承实现了 HandlerInterceptor 接口的类,比如 Spring 已经提供的实现了 HandlerInterceptor 接口的抽象类 HandlerInterceptorAdapter

HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。

preHandle():这个方法在业务处理器处理请求之前被调用,SpringMVC 中的 Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个 Interceptor 。每个 Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是 Interceptor 中的 preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值 Boolean 类型的,当它返回为 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当返回值为 true 时就会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会是调用当前请求的 Controller 方法。

postHandle():这个方法在当前请求进行处理之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。postHandle 方法被调用的方向跟 preHandle 是相反的,也就是说先声明的 Interceptor 的 postHandle 方法反而会后执行。

afterCompletion():该方法也是需要当前对应的 Interceptor 的 preHandle 方法的返回值为 true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

下面来看我们的 Interceptor 类

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class CommonInterceptor  extends HandlerInterceptorAdapter{

        private final Logger log = LoggerFactory.getLogger(CommonInterceptor.class);

        public  static  final  String  LAST_PAGE = "lastPage";
        /** 
         * 在业务处理器处理请求之前被调用 
         * 如果返回false 
         *     从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链
         *     
         * 如果返回true 
         *    执行下一个拦截器,直到所有的拦截器都执行完毕 
         *    再执行被拦截的Controller 
         *    然后进入拦截器链, 
         *    从最后一个拦截器往回执行所有的postHandle() 
         *    接着再从最后一个拦截器往回执行所有的afterCompletion() 
         */  
        @Override  
        public boolean preHandle(HttpServletRequest request,  
                HttpServletResponse response, Object handler) throws Exception {            
            if ("GET".equalsIgnoreCase(request.getMethod())) {
                    RequestUtil.saveRequest();
            }
            log.info("==============执行顺序: 1、preHandle================");  
            String requestUri = request.getRequestURI();
            String contextPath = request.getContextPath();
            String url = requestUri.substring(contextPath.length());         if ("/userController/login".equals(url)) {                  
                    return true;
            }else {               
                    String username =  (String)request.getSession().getAttribute("user"); 
                    if(username == null){
                            log.info("Interceptor:跳转到login页面!");
                            request.getRequestDispatcher("/page/index.jsp").forward(request, response);
                            return false;
                    }else
                            return true;   
           }

        }        
        /**
         * 在业务处理器处理请求执行完成后,生成视图之前执行的动作   
         * 可在modelAndView中加入数据,比如当前时间
         */
        @Override  
        public void postHandle(HttpServletRequest request,  
                HttpServletResponse response, Object handler,  
                ModelAndView modelAndView) throws Exception {   
            log.info("==============执行顺序: 2、postHandle================");  
            if(modelAndView != null){  //加入当前时间  
                modelAndView.addObject("haha", "测试postHandle");  
            }  
        }        
        /** 
         * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等    
         * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion() 
         */  
        @Override  
        public void afterCompletion(HttpServletRequest request,  
                HttpServletResponse response, Object handler, Exception ex)  
                throws Exception {  
            log.info("==============执行顺序: 3、afterCompletion================");  
        }  
}

spring-MVC.xml 的相关配置

    <!-- 对静态资源文件的访问-->
    <!-- <mvc:resources mapping="/images/**"  location="/images/"/> 
    <mvc:resources mapping="/css/**"  location="/css/" />
    <mvc:resources mapping="/js/**"  location="/js/" /> 
    <mvc:resources mapping="/favicon.ico"  location="favicon.ico" /> --> 
    <!--配置拦截器, 多个拦截器,顺序执行 -->
    <mvc:interceptors> 
           <mvc:interceptor>
                   <!--  
                       /**的意思是所有文件夹及里面的子文件夹 
                       /*是所有文件夹,不含子文件夹 
                       /是web项目的根目录
                     --> 
                  **<mvc:mapping path="/**" />** 
                   <!-- 需排除拦截的地址 -->  
                   <!--  <mvc:exclude-mapping path="/userController/login"/>  -->
                   **<bean id="commonInterceptor" class="org.shop.interceptor.CommonInterceptor"></bean>** <!--这个类就是我们自定义的Interceptor -->
          </mvc:interceptor> 
          <!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法  -->
    </mvc:interceptors>

就这么简单 SpringMVC 拦截器写好了,登陆的实现用上一篇 filter 的代码就可以进行测试了。

注意:在我测试的时候我用 mvc:resources 不拦截静态资源居然不管用,也不知道是怎么回事,希望有大神指正下应该怎么做

<!-- 对静态资源文件的访问-->
<mvc:resources mapping="/images/**"  location="/images/"/> 
<mvc:resources mapping="/css/**"  location="/css/" />
<mvc:resources mapping="/js/**"  location="/js/" /> 
<mvc:resources mapping="/favicon.ico"  location="favicon.ico" />

所以我只好在 web.xml 进行了对静态资源不拦截的配置

    <!-- 不拦截静态文件 -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/js/*</url-pattern>
        <url-pattern>/css/*</url-pattern>
        <url-pattern>/images/*</url-pattern>
        <url-pattern>/fonts/*</url-pattern>
    </servlet-mapping>

作者:悟空,你真了不得

来源链接:

https://www.cnblogs.com/jianjianyang/p/5009457.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值