1. 程式人生 > >Struts2學習——攔截器(interceptor)學習

Struts2學習——攔截器(interceptor)學習

  • 攔截器(interceptor)是struts2框架的又一主要功能,他是基於過濾器(Filter)來開發的,主要功能就是對使用者的請求進行包裝,處理等等。

  • 例如,前面學習的Action中獲取引數的幾種方式,都是在請求到達Action之前,在攔截器中進行獲取並封裝的,我們在Action類中建立屬性,只不過是給獲取的引數建立一個容器,好讓前面的攔截器可以將引數封裝進去。

  • Struts2框架自帶了一堆攔截器(20個左右)

  •  這是Struts2預設的攔截器棧,也就是請求到達action預設要經過這些攔截器。可以看到其中有一個叫做
    • <interceptor-ref name="modelDriven"/>
  • 的攔截器,他的功能就是實現模型驅動封裝引數。
<interceptor-stack name="defaultStack">
    <interceptor-ref name="exception"/>
    <interceptor-ref name="alias"/>
    <interceptor-ref name="servletConfig"/>
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="prepare"/>
    <interceptor-ref name="chain"/>
    <interceptor-ref name="scopedModelDriven"/>
    <interceptor-ref name="modelDriven"/>
    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="datetime"/>
    <interceptor-ref name="multiselect"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="actionMappingParams"/>
    <interceptor-ref name="params"/>
    <interceptor-ref name="conversionError"/>
    <interceptor-ref name="validation">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="workflow">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="debugging"/>
</interceptor-stack>

我們知道有的系統(網站)、會要求使用者必須登入,否則就無法使用網站中的各種功能,這就可以使用攔截器來實現,想要使用攔截器實現,當然要回建立並配置攔截器,接下來就學習了攔截器的基本用法:

  • 1. 如何建立攔截器interceptor

建立攔截器又有三種方式:

  • 方式一:實現Interceptor介面(最原始的方式)
// 介面中有三個方法需要實現,分別是建立時執行的方式、銷燬時執行的方法,和攔截器具體行為
// 這裡介紹一下攔截器的生命週期:隨專案工程部署而建立(開啟伺服器)、隨專案關閉而銷燬
public class MyInterceptor1 implements Interceptor{

	@Override
	public void destroy() {
	}
	@Override
	public void init() {	
	}
	@Override
    // intercept方法,引數顧名思義:Action呼叫,用於執行action類的物件
	public String intercept(ActionInvocation invocation) throws Exception {
        /*
         * 放行之前書寫在action執行之前的操作
         */
        // 放行
        String str =i nvocation.invoke();
        /*
         * 放行之後書寫在action執行之後的操作
         */	
        return str;

        // 如果不想放行(不執行後續攔截器及Action類),可以直接返回一個結果字元創,如error
        // return "error"; // 當然前面的放行程式碼可以刪掉,這樣他會直接去到配置的中
                            // 查詢name為error的result元素,並執行相應的跳轉操作
	}
}
  • 方式二:繼承AbstractInterceptor 類
// AbstractInterceptor類也是實現的Interceptor介面,他只是方便開發者書寫程式碼,
// 因為init方法與destroy方法基本用不到,所以他就簡化了需要實現的方法。
public class MyInterceptor1 extends AbstractInterceptor{

	@Override
	public String intercept(ActionInvocation arg0) throws Exception {
		return null;
	}
}
  • 方式三:繼承MethodFilterInterceptor 類
// MethodFilterInterceptor類可以說是方法過濾攔截器。
// 他的功能就是:定製攔截器攔截的方法——攔截哪些方法、不攔截哪些方法
// 具體程式碼與其他幾種方式相同
public class MyInterceptor1 extends MethodFilterInterceptor{

	@Override
	protected String doIntercept(ActionInvocation arg0) throws Exception {
		return null;
	}
}

 

  • 2. 如何使用(配置)攔截器

  • 寫好了攔截器後,當然要使其生效,所以需要對攔截器進行具體配置,有優秀基礎的人,攔截器配置的步驟可以參照struts-default.xml中的配置來寫。

攔截器配置步驟:

  • 1. 註冊攔截器
<!-- 攔截器主元素:位置:package元素裡面,action元素前面 -->
<interceptors>
    <!-- interceptor元素:用於註冊攔截器
             name屬性:為該攔截器起個名稱;
             class屬性:填寫該攔截器類的全包名
     -->
	<interceptor name="login" class="com.huhu.web.interceptor.MyInterceptor"></interceptor>
</interceptors>
  • 2. 建立攔截器棧
<!-- 該元素建立攔截器棧,放在interceptors元素裡面,interceptor元素後面。name屬性,為棧起個名稱-->
<interceptor-stack name="loginStack">
    <!-- 將自己書寫的攔截器棧引入進來,並引入struts2預設的攔截器 -->
	<interceptor-ref name="login"></interceptor-ref>
	<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
  • 3. 指定攔截器工作範圍
<!-- 直接在package元素裡配置此元素,意思是該package下的所有action都要走name為loginStack的攔截
        器棧 -->
<default-interceptor-ref name="loginStack"></default-interceptor-ref>

<!-- 也可以指定某個action元素適用的攔截器棧(不常用) 
        將interceptor-ref元素配置在action裡面,即指定該action適用的攔截器棧
-->
<action>
    <interceptor-ref name="loginStack"></interceptor-ref>
</action>
  • 到這裡,技術點都學完了,之後就是適用這些知識實現效果:

  • 訪問功能時,未登入,則跳轉到登入頁面。

詳細實現:這裡就簡單的將程式碼貼出來。

  • 攔截器具體程式碼:
public class LoginInterceptor extends MethodFilterInterceptor{

	@Override
	protected String doIntercept(ActionInvocation invocation) throws Exception {
		// 獲取session域,獲取user
		Object user = ActionContext.getContext().getSession().get("user");
		// 判斷使用者是否登入(user是否存在)
		if (user == null) {
			// 未登入,跳轉到登入頁面
			return "toLogin";
		}
		// 登入放行
		return invocation.invoke();
	}
}
  • 配置檔案詳細程式碼:
<package name="sh" namespace="/" extends="struts-default">
	<!-- 配置程式設計師自定義攔截器,放在package元素的最前面 -->
	<interceptors>
		<!-- 註冊攔截器 -->
		<interceptor name="login" class="com.huhu.web.interceptor.LoginInterceptor"></interceptor>
		<interceptor-stack name="loginStack">
			<!-- 將註冊的攔截器新增到自定義攔截器棧 -->
			<interceptor-ref name="login">
                            <!-- 配置不執行此攔截器棧的方法 -->
				<param name="excludeMethods">login</param>
			</interceptor-ref>
			<!-- 引入struts2預設攔截器棧 -->
			<interceptor-ref name="defaultStack"></interceptor-ref>
		</interceptor-stack>
	</interceptors>
	<!-- 設定package預設攔截器棧 -->
	<default-interceptor-ref name="loginStack"></default-interceptor-ref>
	
	<!-- 配置全域性結果集,整個工程都可以使用的結果集 ,放在全域性異常處理之前-->
	<global-results>
		<result name="toLogin" type="redirect">/login.jsp</result>
	</global-results>

	<action name="custAction_*" class="com.huhu.web.action.CustomerAction" method="{1}">
		<result name="custlist" >/jsp/customer/list.jsp</result>

		<result name="success" type="redirectAction">
		    <param name="actionName">custAction_findCust</param>
                    <param name="namespace">/customer</param>
		</result>
		<!-- 配置可以動態呼叫的方法名,多個方法用,逗號隔開 -->
		<allowed-methods>findCust,add</allowed-methods>
	</action>

	<action name="userAction_*"	class="com.huhu.web.action.UserAction" method="{1}">
		<interceptor-ref name="loginStack"></interceptor-ref>
		<result name="login" type="redirect">/index.jsp</result>
		<result name="error" type="dispatcher">/login.jsp</result>
		<!-- 不知道為啥,以轉發的方式到頁面,頁面載入不到資源,原因:資源路徑前沒加工程名 -->
		<!-- <result name="error" >/login.jsp</result> -->
		<allowed-methods>login</allowed-methods>
	</action>
</package>

這也可以說是已經實現了登入校驗的功能(校驗使用者是否登入)

 

拓展:

  • 1. 攔截器無法攔截頁面的顯示,只能攔截action中的元素,所以想要實現攔截頁面的功能需要使用其他的技術。或者,每個頁面的顯示都是使用action的某個方法跳轉到的,則可以用攔截器攔截這些方法,來起到攔截頁面顯示的作用,不過這種方式可能不太常用。

 

  • 2. 如果頁面使用的是frame框架佈局的頁面,未登入時,跳轉到登入頁面可能只是框架中的某一部分跳轉,如:

  •  如果想讓跳轉到的登入頁只顯示登入頁資訊,可以使用js的一段簡單程式碼解決:

  • 注意:此段程式碼實在想要顯示的頁面的檔案中書寫的,如:我的登入頁面檔名為login.jsp,則在該檔案中書寫
<script type="text/javascript">
	window.onload=function(){
		if(window.parent != window){
			window.parent.location.href="${pageContext.request.contextPath}/login.jsp";
		}
	};
</script>
  • 書寫一個頁面載入完畢事件,作用是,頁面載入完畢後,判斷當前頁面的父視窗是不是瀏覽器的主視窗,如果不是,則將父視窗重新跳轉到當前頁面。