1. 程式人生 > >SpringMVC攔截器簡單使用

SpringMVC攔截器簡單使用

SpringMVC的處理器攔截器,類似於Servlet開發中的過濾器Filter,用於對處理器進行預處理和後處理。

(1)過濾器:

依賴於servlet容器。在實現上基於函式回撥,可以對幾乎所有請求進行過濾,但是缺點是一個過濾器例項只能在容器初始化時呼叫一次。使用過濾器的目的是用來做一些過濾操作,比如:在過濾器中修改字元編碼;在過濾器中修改HttpServletRequest的一些引數,包括:過濾低俗文字、危險字元等。

(2)攔截器:

依賴於web框架,在實現上基於Java的反射機制,屬於面向切面程式設計(AOP)的一種運用。由於攔截器是基於web框架的呼叫,因此可以使用Spring的依賴注入(DI)進行一些業務操作,同時一個攔截器例項在一個controller生命週期之內可以多次呼叫。

1、常見應用場景

1)日誌記錄:記錄請求資訊的日誌,以便進行資訊監控、資訊統計、計算PV(Page View)等。

2)許可權檢查:如登入檢測,進入處理器檢測是否登入,如果沒有直接返回到登入頁面;

3)效能監控:有時候系統在某段時間莫名其妙的慢,可以通過攔截器在進入處理器之前記錄開始時間,在處理完後記錄結束時間,從而得到該請求的處理時間(如果有反向代理,如apache可以自動記錄);

4)通用行為:讀取cookie得到使用者資訊並將使用者物件放入請求,從而方便後續流程使用,還有如提取Locale、Theme資訊等,只要是多個Controller中的處理方法都需要的,我們就可以使用攔截器實現。

5)OpenSessionInView:如Hibernate,在進入處理器開啟Session,在完成後關閉Session。

…………本質也是AOP(面向切面程式設計),也就是說符合橫切關注點的所有功能都可以放入攔截器實現。

    

2、SpringMVC提供的攔截器介面:HandlerInterceptor 

public interface HandlerInterceptor {
	boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
	    throws Exception;

	void postHandle(
			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
			throws Exception;

	void afterCompletion(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception;
}

攔截器一個有3個回撥方法,而一般的過濾器Filter才兩個:

preHandle:預處理回撥方法,實現處理器的預處理(如登入檢查),第三個引數為響應的處理器返回值:true表示繼續流程(如呼叫下一個攔截器或處理器);false表示流程中斷(如登入檢查失敗),不會繼續呼叫其他的攔截器或處理器,此時我們需要通過response來產生響應;

postHandle:後處理回撥方法,實現處理器的後處理(但在渲染檢視之前),此時我們可以通過modelAndView(模型和檢視物件)對模型資料進行處理或對檢視進行處理,modelAndView也可能為null。

afterCompletion:整個請求處理完畢回撥方法,即在檢視渲染完畢時回撥,如效能監控中我們可以在此記錄結束時間並輸出消耗時間,還可以進行一些資源清理,類似於try-catch-finally中的finally,但僅呼叫處理器執行鏈中preHandle返回true的攔截器才會執行afterCompletion

3、攔截器介面卡:HandlerInterceptorAdapter

有時我們可能只需要實現三個回撥方法中的某一個,如果實現HandlerInterceptor介面的話,三個方法必須實現,此時spring提供了一個HandlerInterceptorAdapter介面卡(一種介面卡設計模式的實現),允許我們只實現需要的回撥方法。

public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
		return true;
	}

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

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

	public void afterConcurrentHandlingStarted(
			HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	}
}

二、 自定義攔截器例項

1) 自定義兩個攔截器(繼承攔截器介面卡:HandlerInterceptorAdapter)HandlerInterceptor1  和 HandlerInterceptor2

public class HandlerInterceptor1 extends HandlerInterceptorAdapter{

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("--1--HandlerInterceptor1.preHandle");
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("--1--HandlerInterceptor1.postHandle");
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("--1--HandlerInterceptor1.afterCompletion");
	}
}

2)在 springmvc.xml 配置檔案中配置攔截器:

(1)攔截所有Controller類裡的所有處理方法

	<!-- 配置攔截器:-->
	<mvc:interceptors>
		<!-- 會攔截所有Controller類裡的所有處理方法 -->
		<bean class="cn.jq.sshweb.web.HandlerInterceptor1"></bean>
		<bean class="cn.jq.sshweb.web.HandlerInterceptor2"></bean>
	</mvc:interceptors>

如果 HandlerInterceptor2 preHandle 方法返回 false , 在訪問:http://127.0.0.1:8080/sshweb/檢視沒有渲染

(2)只攔截某個請求路徑的處理方法

	<!-- 配置攔截器:-->
	<mvc:interceptors>
		<!-- 會攔截所有Controller類裡的所有處理方法 -->
		<bean class="cn.jq.sshweb.web.HandlerInterceptor1"></bean>
		<mvc:interceptor>
			<!-- 只攔截該路徑 -->
			<mvc:mapping path="/users"/>
			<bean class="cn.jq.sshweb.web.HandlerInterceptor2"></bean>
		</mvc:interceptor>
	</mvc:interceptors>

(3)攔截器深入配置:注意  /** (任意分層路徑下) ,/* (該任意單路徑下)

	<!-- 配置攔截器:-->
	<mvc:interceptors>
		<!-- 會攔截所有Controller類裡的所有處理方法 -->
		<bean class="cn.jq.sshweb.web.HandlerInterceptor1"></bean>
		<mvc:interceptor>
			<!-- 只攔截該路徑 -->
			<mvc:mapping path="/users"/>
			<bean class="cn.jq.sshweb.web.HandlerInterceptor2"></bean>
		</mvc:interceptor>
		<mvc:interceptor>
			<!-- 攔截所有請求,排除攔截 /toAdd 請求 -->
			<mvc:mapping path="/**"/>
			<mvc:exclude-mapping path="/toAdd"/>
			<bean class="cn.jq.sshweb.web.HandlerInterceptor3"></bean>
		</mvc:interceptor>
	</mvc:interceptors>