SpringMVC攔截器

              本文轉載自: http://elim.iteye.com/blog/1750680

    SpringMVC中的Interceptor攔截器也是相當重要和相當有用的,它的主要作用是攔截用戶的請求並進行相應的處理。比如通過它來進行權限驗證,或者是來判斷用戶是否登陸,或者是像12306那樣子判斷當前時間是否是購票時間。

   一、定義Interceptor實現類

   SpringMVC中的Interceptor攔截請求是通過HandlerInterceptor來實現的。在SpringMVC中定義一個Interceptor非常簡單,主要有兩種方式,第一種方式是要定義的Interceptor類要實現了Spring的HandlerInterceptor 接口,或者是這個類繼承實現了HandlerInterceptor接口的類,比如Spring已經提供的實現了HandlerInterceptor接口的抽象類HandlerInterceptorAdapter ;第二種方式是實現Spring的WebRequestInterceptor接口,或者是繼承實現了WebRequestInterceptor的類。

   (一)實現HandlerInterceptor接口

   HandlerInterceptor接口中定義了三個方法,我們就是通過這三個方法來對用戶的請求進行攔截處理的。

   (1)preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)方法,顧名思義,該方法將在請求處理之前進行調用。SpringMVC中的Interceptor是鏈式的調用的,在一個應用中或者說是在一個請求中可以同時存在多個Interceptor。每個Interceptor的調用會依據它的聲明順序依次執行,而且最先執行的都是Interceptor中的preHandle方法,所以可以在這個方法中進行一些前置初始化操作或者是對當前請求的一個預處理,也可以在這個方法中進行一些判斷來決定請求是否要繼續進行下去。該方法的返回值是布爾值Boolean類型的,當它返回爲false時,表示請求結束,後續的Interceptor和Controller都不會再執行;當返回值爲true時就會繼續調用下一個Interceptor的preHandle方法,如果已經是最後一個Interceptor的時候就會是調用當前請求的Controller方法。

   (2)postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)方法,由preHandle方法的解釋我們知道這個方法包括後面要說到的afterCompletion方法都只能是在當前所屬的Interceptor的preHandle方法的返回值爲true時才能被調用。postHandle方法,顧名思義就是在當前請求進行處理之後,也就是Controller方法調用之後執行,但是它會在DispatcherServlet進行視圖返回渲染之前被調用,所以我們可以在這個方法中對Controller處理之後的ModelAndView對象進行操作。postHandle方法被調用的方向跟preHandle是相反的,也就是說先聲明的Interceptor的postHandle方法反而會後執行,這和Struts2裏面的Interceptor的執行過程有點類型。Struts2裏面的Interceptor的執行過程也是鏈式的,只是在Struts2裏面需要手動調用ActionInvocation的invoke方法來觸發對下一個Interceptor或者是Action的調用,然後每一個Interceptor中在invoke方法調用之前的內容都是按照聲明順序執行的,而invoke方法之後的內容就是反向的。

   (3)afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法,該方法也是需要當前對應的Interceptor的preHandle方法的返回值爲true時纔會執行。顧名思義,該方法將在整個請求結束之後,也就是在DispatcherServlet渲染了對應的視圖之後執行。這個方法的主要作用是用於進行資源清理工作的。

    

import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
  
import org.springframework.web.servlet.HandlerInterceptor;  
import org.springframework.web.servlet.ModelAndView;  
  
public class SpringMVCInterceptor implements HandlerInterceptor {  
  
  
    /** 
     * preHandle方法是進行處理器攔截用的,顧名思義,該方法將在Controller處理之前進行調用,SpringMVC中的Interceptor攔截器是鏈式的,可以同時存在 
     * 多個Interceptor,然後SpringMVC會根據聲明的前後順序一個接一個的執行,而且所有的Interceptor中的preHandle方法都會在 
     * Controller方法調用之前調用。SpringMVC的這種Interceptor鏈式結構也是可以進行中斷的,這種中斷方式是令preHandle的返 
     * 回值爲false,當preHandle的返回值爲false的時候整個請求就結束了。 
     */  
    @Override  
    public boolean preHandle(HttpServletRequest request,  
            HttpServletResponse response, Object handler) throws Exception {  
        // TODO Auto-generated method stub  
        return false;  
    }  
      
    /** 
     * 這個方法只會在當前這個Interceptor的preHandle方法返回值爲true的時候纔會執行。postHandle是進行處理器攔截用的,它的執行時間是在處理器進行處理之 
     * 後,也就是在Controller的方法調用之後執行,但是它會在DispatcherServlet進行視圖的渲染之前執行,也就是說在這個方法中你可以對ModelAndView進行操 
     * 作。這個方法的鏈式結構跟正常訪問的方向是相反的,也就是說先聲明的Interceptor攔截器該方法反而會後調用,這跟Struts2裏面的攔截器的執行過程有點像, 
     * 只是Struts2裏面的intercept方法中要手動的調用ActionInvocation的invoke方法,Struts2中調用ActionInvocation的invoke方法就是調用下一個Interceptor 
     * 或者是調用action,然後要在Interceptor之前調用的內容都寫在調用invoke之前,要在Interceptor之後調用的內容都寫在調用invoke方法之後。 
     */  
    @Override  
    public void postHandle(HttpServletRequest request,  
            HttpServletResponse response, Object handler,  
            ModelAndView modelAndView) throws Exception {  
        // TODO Auto-generated method stub  
          
    }  
  
    /** 
     * 該方法也是需要當前對應的Interceptor的preHandle方法的返回值爲true時纔會執行。該方法將在整個請求完成之後,也就是DispatcherServlet渲染了視圖執行, 
     * 這個方法的主要作用是用於清理資源的,當然這個方法也只能在當前這個Interceptor的preHandle方法的返回值爲true時纔會執行。 
     */  
    @Override  
    public void afterCompletion(HttpServletRequest request,  
            HttpServletResponse response, Object handler, Exception ex)  
    throws Exception {  
        // TODO Auto-generated method stub  
          
    }  
      
}

(二)實現WebRequestInterceptor接口

  WebRequestInterceptor中也定義了三個方法,我們也是通過這三個方法來實現攔截的。這三個方法都傳遞了同一個參數WebRequest,那麼這個WebRequest是什麼呢?這個WebRequest是Spring定義的一個接口,它裏面的方法定義都基本跟HttpServletRequest一樣,在WebRequestInterceptor中對WebRequest進行的所有操作都將同步到HttpServletRequest中,然後在當前請求中一直傳遞。

   (1)preHandle(WebRequestrequest)方法。該方法將在請求處理之前進行調用,也就是說會在Controller方法調用之前被調用。這個方法跟HandlerInterceptor中的preHandle是不同的,主要區別在於該方法的返回值是void,也就是沒有返回值,所以我們一般主要用它來進行資源的準備工作,比如我們在使用Hibernate的時候可以在這個方法中準備一個Hibernate的Session對象,然後利用WebRequest的setAttribute(name, value, scope)把它放到WebRequest的屬性中。這裏可以說說這個setAttribute方法的第三個參數scope,該參數是一個Integer類型的。在WebRequest的父層接口RequestAttributes中對它定義了三個常量:

   SCOPE_REQUEST:它的值是0,代表只有在request中可以訪問。

   SCOPE_SESSION:它的值是1,如果環境允許的話它代表的是一個局部的隔離的session,否則就代表普通的session,並且在該session範圍內可以訪問。

   SCOPE_GLOBAL_SESSION:它的值是2,如果環境允許的話,它代表的是一個全局共享的session,否則就代表普通的session,並且在該session範圍內可以訪問。

   (2)postHandle(WebRequestrequest, ModelMap model)方法。該方法將在請求處理之後,也就是在Controller方法調用之後被調用,但是會在視圖返回被渲染之前被調用,所以可以在這個方法裏面通過改變數據模型ModelMap來改變數據的展示。該方法有兩個參數,WebRequest對象是用於傳遞整個請求數據的,比如在preHandle中準備的數據都可以通過WebRequest來傳遞和訪問;ModelMap就是Controller處理之後返回的Model對象,我們可以通過改變它的屬性來改變返回的Model模型。

   (3)afterCompletion(WebRequestrequest, Exception ex)方法。該方法會在整個請求處理完成,也就是在視圖返回並被渲染之後執行。所以在該方法中可以進行資源的釋放操作。而WebRequest參數就可以把我們在preHandle中準備的資源傳遞到這裏進行釋放。Exception參數表示的是當前請求的異常對象,如果在Controller中拋出的異常已經被Spring的異常處理器給處理了的話,那麼這個異常對象就是是null。

import org.springframework.ui.ModelMap;  
import org.springframework.web.context.request.WebRequest;  
import org.springframework.web.context.request.WebRequestInterceptor;  
  
public class AllInterceptor implements WebRequestInterceptor {  
      
    /** 
     * 在請求處理之前執行,該方法主要是用於準備資源數據的,然後可以把它們當做請求屬性放到WebRequest中 
     */  
    @Override  
    public void preHandle(WebRequest request) throws Exception {  
        // TODO Auto-generated method stub  
        System.out.println("AllInterceptor...............................");  
        request.setAttribute("request", "request", WebRequest.SCOPE_REQUEST);//這個是放到request範圍內的,所以只能在當前請求中的request中獲取到  
        request.setAttribute("session", "session", WebRequest.SCOPE_SESSION);//這個是放到session範圍內的,如果環境允許的話它只能在局部的隔離的會話中訪問,否則就是在普通的當前會話中可以訪問  
        request.setAttribute("globalSession", "globalSession", WebRequest.SCOPE_GLOBAL_SESSION);//如果環境允許的話,它能在全局共享的會話中訪問,否則就是在普通的當前會話中訪問  
    }  
  
    /** 
     * 該方法將在Controller執行之後,返回視圖之前執行,ModelMap表示請求Controller處理之後返回的Model對象,所以可以在 
     * 這個方法中修改ModelMap的屬性,從而達到改變返回的模型的效果。 
     */  
    @Override  
    public void postHandle(WebRequest request, ModelMap map) throws Exception {  
        // TODO Auto-generated method stub  
        for (String key:map.keySet())  
            System.out.println(key + "-------------------------");;  
        map.put("name3", "value3");  
        map.put("name1", "name1");  
    }  
  
    /** 
     * 該方法將在整個請求完成之後,也就是說在視圖渲染之後進行調用,主要用於進行一些資源的釋放 
     */  
    @Override  
    public void afterCompletion(WebRequest request, Exception exception)  
    throws Exception {  
        // TODO Auto-generated method stub  
        System.out.println(exception + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");  
    }  
      
}

二、把定義的攔截器類加到SpringMVC的攔截體系中

         1.在SpringMVC的配置文件中加上支持MVC的schema

   xmlns:mvc="http://www.springframework.org/schema/mvc"  
    xsi:schemaLocation=" http://www.springframework.org/schema/mvc  
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" 
        
        
        
   <beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:mvc="http://www.springframework.org/schema/mvc"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
     http://www.springframework.org/schema/context  
     http://www.springframework.org/schema/context/spring-context-3.0.xsd  
     http://www.springframework.org/schema/mvc  
     http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 
     
     <mvc:interceptors>  
    <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求 -->  
    <bean class="com.host.app.web.interceptor.AllInterceptor"/>  
    <mvc:interceptor>  
        <mvc:mapping path="/test/number.do"/>  
        <!-- 定義在mvc:interceptor下面的表示是對特定的請求才進行攔截的 -->  
        <bean class="com.host.app.web.interceptor.LoginInterceptor"/>  
    </mvc:interceptor>  
</mvc:interceptors>

    由上面的示例可以看出可以利用mvc:interceptors標籤聲明一系列的攔截器,然後它們就可以形成一個攔截器鏈,攔截器的執行順序是按聲明的先後順序執行的,先聲明的攔截器中的preHandle方法會先執行,然而它的postHandle方法和afterCompletion方法卻會後執行。

          在mvc:interceptors標籤下聲明interceptor主要有兩種方式:

                    (1)直接定義一個Interceptor實現類的bean對象。使用這種方式聲明的Interceptor攔截器將會對所有的請求進行攔截。

                    (2)使用mvc:interceptor標籤進行聲明。使用這種方式進行聲明的Interceptor可以通過mvc:mapping子標籤來定義需要進行攔截的請求路徑。

          經過上述兩步之後,定義的攔截器就會發生作用對特定的請求進行攔截了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章