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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM