SpringMVC中使用Interceptor攔截器

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

   1、定義Interceptor實現類

 

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

   (一)實現HandlerInterceptor接口

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

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

   (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 方法以後的內容就是反向的。session

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

下面是一個簡單的代碼說明:app

 

Java代碼 複製代碼 收藏代碼ide

  1. import javax.servlet.http.HttpServletRequest;  
  2. import javax.servlet.http.HttpServletResponse;  
  3.   
  4. import org.springframework.web.servlet.HandlerInterceptor;  
  5. import org.springframework.web.servlet.ModelAndView;  
  6.   
  7. public class SpringMVCInterceptor implements HandlerInterceptor {  
  8.   
  9.   
  10.     /** 
  11.      * preHandle方法是進行處理器攔截用的,顧名思義,該方法將在Controller處理以前進行調用,SpringMVC中的Interceptor攔截器是鏈式的,能夠同時存在 
  12.      * 多個Interceptor,而後SpringMVC會根據聲明的先後順序一個接一個的執行,並且全部的Interceptor中的preHandle方法都會在 
  13.      * Controller方法調用以前調用。SpringMVC的這種Interceptor鏈式結構也是能夠進行中斷的,這種中斷方式是令preHandle的返 
  14.      * 回值爲false,當preHandle的返回值爲false的時候整個請求就結束了。 
  15.      */  
  16.     @Override  
  17.     public boolean preHandle(HttpServletRequest request,  
  18.             HttpServletResponse response, Object handler) throws Exception {  
  19.         // TODO Auto-generated method stub  
  20.         return false;  
  21.     }  
  22.       
  23.     /** 
  24.      * 這個方法只會在當前這個Interceptor的preHandle方法返回值爲true的時候纔會執行。postHandle是進行處理器攔截用的,它的執行時間是在處理器進行處理之 
  25.      * 後,也就是在Controller的方法調用以後執行,可是它會在DispatcherServlet進行視圖的渲染以前執行,也就是說在這個方法中你能夠對ModelAndView進行操 
  26.      * 做。這個方法的鏈式結構跟正常訪問的方向是相反的,也就是說先聲明的Interceptor攔截器該方法反而會後調用,這跟Struts2裏面的攔截器的執行過程有點像, 
  27.      * 只是Struts2裏面的intercept方法中要手動的調用ActionInvocation的invoke方法,Struts2中調用ActionInvocation的invoke方法就是調用下一個Interceptor 
  28.      * 或者是調用action,而後要在Interceptor以前調用的內容都寫在調用invoke以前,要在Interceptor以後調用的內容都寫在調用invoke方法以後。 
  29.      */  
  30.     @Override  
  31.     public void postHandle(HttpServletRequest request,  
  32.             HttpServletResponse response, Object handler,  
  33.             ModelAndView modelAndView) throws Exception {  
  34.         // TODO Auto-generated method stub  
  35.           
  36.     }  
  37.   
  38.     /** 
  39.      * 該方法也是須要當前對應的Interceptor的preHandle方法的返回值爲true時纔會執行。該方法將在整個請求完成以後,也就是DispatcherServlet渲染了視圖執行, 
  40.      * 這個方法的主要做用是用於清理資源的,固然這個方法也只能在當前這個Interceptor的preHandle方法的返回值爲true時纔會執行。 
  41.      */  
  42.     @Override  
  43.     public void afterCompletion(HttpServletRequest request,  
  44.             HttpServletResponse response, Object handler, Exception ex)  
  45.     throws Exception {  
  46.         // TODO Auto-generated method stub  
  47.           
  48.     }  
  49.       
  50. }  
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 中,而後在當前請求中一直傳遞。post

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

   SCOPE_REQUEST :它的值是0 ,表明只有在request 中能夠訪問。

   SCOPE_SESSION :它的值是1 ,若是環境容許的話它表明的是一個局部的隔離的session,不然就表明普通的session,而且在該session範圍內能夠訪問。

   SCOPE_GLOBAL_SESSION :它的值是2 ,若是環境容許的話,它表明的是一個全局共享的session,不然就表明普通的session,而且在該session 範圍內能夠訪問。

   (2 )postHandle(WebRequest request, ModelMap model) 方法。該方法將在請求處理以後,也就是在Controller 方法調用以後被調用,可是會在視圖返回被渲染以前被調用,因此能夠在這個方法裏面經過改變數據模型ModelMap 來改變數據的展現。該方法有兩個參數,WebRequest 對象是用於傳遞整個請求數據的,好比在preHandle 中準備的數據均可以經過WebRequest 來傳遞和訪問;ModelMap 就是Controller 處理以後返回的Model 對象,咱們能夠經過改變它的屬性來改變返回的Model 模型。

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

 

   下面是一個簡單的代碼說明:

Java代碼 複製代碼 收藏代碼

  1. import org.springframework.ui.ModelMap;  
  2. import org.springframework.web.context.request.WebRequest;  
  3. import org.springframework.web.context.request.WebRequestInterceptor;  
  4.   
  5. public class AllInterceptor implements WebRequestInterceptor {  
  6.       
  7.     /** 
  8.      * 在請求處理以前執行,該方法主要是用於準備資源數據的,而後能夠把它們當作請求屬性放到WebRequest中 
  9.      */  
  10.     @Override  
  11.     public void preHandle(WebRequest request) throws Exception {  
  12.         // TODO Auto-generated method stub  
  13.         System.out.println("AllInterceptor...............................");  
  14.         request.setAttribute("request", "request", WebRequest.SCOPE_REQUEST);//這個是放到request範圍內的,因此只能在當前請求中的request中獲取到  
  15.         request.setAttribute("session", "session", WebRequest.SCOPE_SESSION);//這個是放到session範圍內的,若是環境容許的話它只能在局部的隔離的會話中訪問,不然就是在普通的當前會話中能夠訪問  
  16.         request.setAttribute("globalSession", "globalSession", WebRequest.SCOPE_GLOBAL_SESSION);//若是環境容許的話,它能在全局共享的會話中訪問,不然就是在普通的當前會話中訪問  
  17.     }  
  18.   
  19.     /** 
  20.      * 該方法將在Controller執行以後,返回視圖以前執行,ModelMap表示請求Controller處理以後返回的Model對象,因此能夠在 
  21.      * 這個方法中修改ModelMap的屬性,從而達到改變返回的模型的效果。 
  22.      */  
  23.     @Override  
  24.     public void postHandle(WebRequest request, ModelMap map) throws Exception {  
  25.         // TODO Auto-generated method stub  
  26.         for (String key:map.keySet())  
  27.             System.out.println(key + "-------------------------");;  
  28.         map.put("name3", "value3");  
  29.         map.put("name1", "name1");  
  30.     }  
  31.   
  32.     /** 
  33.      * 該方法將在整個請求完成以後,也就是說在視圖渲染以後進行調用,主要用於進行一些資源的釋放 
  34.      */  
  35.     @Override  
  36.     public void afterCompletion(WebRequest request, Exception exception)  
  37.     throws Exception {  
  38.         // TODO Auto-generated method stub  
  39.         System.out.println(exception + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");  
  40.     }  
  41.       
  42. }  
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 + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");
	}
	
}

 

 

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

 

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

Xml代碼 複製代碼 收藏代碼

  1.     xmlns:mvc="http://www.springframework.org/schema/mvc"  
  2.     xsi:schemaLocation=" http://www.springframework.org/schema/mvc  
  3.         http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"  
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"

 

         下面是個人聲明示例:

Xml代碼 複製代碼 收藏代碼

  1. <beans xmlns="http://www.springframework.org/schema/beans"  
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
  3.     xmlns:mvc="http://www.springframework.org/schema/mvc"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5.      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  6.      http://www.springframework.org/schema/context  
  7.      http://www.springframework.org/schema/context/spring-context-3.0.xsd  
  8.      http://www.springframework.org/schema/mvc  
  9.      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">

         這樣在SpringMVC的配置文件中就可使用mvc標籤了,mvc標籤中有一個mvc:interceptors是用於聲明SpringMVC的攔截器的。

 

        (二)使用mvc:interceptors標籤來聲明須要加入到SpringMVC攔截器鏈中的攔截器

Xml代碼 複製代碼 收藏代碼

  1. <mvc:interceptors>  
  2.     <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截全部的請求 -->  
  3.     <bean class="com.host.app.web.interceptor.AllInterceptor"/>  
  4.     <mvc:interceptor>  
  5.         <mvc:mapping path="/test/number.do"/>  
  6.         <!-- 定義在mvc:interceptor下面的表示是對特定的請求才進行攔截的 -->  
  7.         <bean class="com.host.app.web.interceptor.LoginInterceptor"/>  
  8.     </mvc:interceptor>  
  9. </mvc:interceptors>  
<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子標籤來定義須要進行攔截的請求路徑。

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

相關文章
相關標籤/搜索