struts2:攔截器

攔截器(Interceptor)是Struts 2的核心組件,Struts 2框架的大部分功能都是經過攔截器來完成的,例如數據校驗,國際化,文件上傳和下載等。爲了實現這些功能,Struts 2框架提供了一個強大的攔截器策略。html

  • 攔截器是Struts 2框架中的重要組成部分,它是AOP(面向方向編程)思想的一種實現。使用攔截器給開發過程帶來了不少好處:能夠把大問題分解成多個小問題以便分別處理,同時可使Action更專一於處理的事情,而把其餘的一些相關功能分配給各個攔截器來進行處理。
  • 在Struts 2中可將各個功能應的攔截器分開定義,每一個攔截器完成單個功能,若是要運用某個功能就加入對應的攔截器,實現了攔截器的可插拔式的設計,即這些攔截器能夠自由選擇,靈活的組合在一塊兒造成攔截器鏈(Interceptor  Chain)或攔截器棧(Interceptor  Stack)。
  • 所謂攔截器鏈是指對應各個功能的攔截器組成的集合,它們按照必定的順序排列在一塊兒造成鏈,當有適配攔截器鏈訪問的請求進來時,這些攔截器就會按照以前定義的順序被調用。

使用Struts2攔截器

1. 配置攔截器

攔截器的配置是在struts.xml文件中完成的,攔截器一般使用<interceptor>標籤來定義,該標籤有兩個屬性name和class,分別用來指定攔截器名稱及其實現類。java

<interceptor name="interceptorName" class="interceptorClass">
        <param name="paramName">paramValue</param>
</interceptor>

2. 攔截器棧

  • 當開發的過程當中須要定義多個攔截器時,能夠將它們定義爲一個攔截器棧。
  • 當一個攔截器棧被附加到一個Action上面時,在執行該Action以前,必須先執行攔截器棧中的每個攔截器。
  • 使用攔截器棧不只能夠肯定多個攔截器的執行順序(攔截器棧中各個攔截器是按照其定義的順序來執行的),同時,把相關的攔截器放在同一個棧中,管理起來也更爲方便。
  • 定義攔截器棧須要用到<interceptor-stack>標籤,該標籤內包含了一系列的<interceptor-ref>子標籤,這些子標籤用來定義攔截器棧中包含的多個攔截器引用。
<package name="default" extends="struts-default" >
<interceptors>
       <!--定義兩個攔截器,攔截器名分別爲interceptor1和interceptor2-->
        <interceptor name="interceptor1" class=」interceptorClass」/>
        <interceptor name="interceptor2" class=」interceptorClass」/>
       <!--定義一個攔截器棧,攔截器包含了兩個攔截器-->
        <interceptor-stack name="myStack">
          <interceptor-ref name="interceptor1"/>
          <interceptor-ref name="interceptor2"/>
        </interceptor-stack>
  </interceptors>
</package>

注意:在一個攔截器棧中也能夠引用另外一個攔截器棧。spring

3. 默認攔截器

  • 若是想對一個包下的多個Action使用相同的攔截器,則須要爲該包中每一個Action都重複指定同一個攔截器,顯然過於繁瑣,解決這個問題的方法就是使用默認攔截器。
  • 默認攔截器是指在一個包下定義的攔截器,該攔截器對包下全部的Action都起做用。
  • 一旦爲某一個包指定了默認攔截器且該包中的Action未顯式的指定攔截器,則該默認攔截器會起做用。反之,若此包中的Action顯式指定了某個攔截器,則該默認攔截器被屏蔽,不會起做用,此時,若仍想使用默認攔截器,則須要用戶手動配置該默認攔截器的引用。
  • 默認攔截器的配置須要使用<default-interceptor-ref>標籤,在該標籤中經過指定name屬性來引用已經定義好的攔截器 。
  • 須要注意的是,每一個包下只能定義一個默認攔截器。若是確實須要指定多個攔截器共同做爲默認攔截器,則能夠將這些攔截器定義爲一個攔截器棧,再將這個攔截器棧配置成默認攔截器就能夠了。
  • 實際上,攔截器類是定義在一個特殊的配置文件中的,這個配置文件就是struts-default.xml。當自定義包繼承了struts-default默認包後,它不只繼承了其內置的各個攔截器,並且還繼承了其默認攔截器棧,也就是說對於繼承了struts-default包的某個自定義包下的全部的Action,struts-default包的默認攔截器棧會做用於全部這些Action。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="default" extends="struts-default">
    <interceptors>
        <!--定義兩個攔截器-->
        <interceptor name="interceptor1" class="interceptorClass"/>
        <interceptor name="interceptor2" class="interceptorClass"/>
        <!--定義一個攔截器棧-->
        <interceptor-stack name="myStack">
            <interceptor-ref name="interceptor1"/>
            <interceptor-ref name="interceptor2"/>
            <interceptor-ref name="defaultStack"/>
        </interceptor-stack>
    </interceptors>
    <!--配置包下的默認攔截器,既能夠是攔截器,也能夠是攔截器棧-->
    <default-interceptor-ref name="myStack"/>
    <action name="login" class="tutorial.Login">
        <result name="input">login.jsp</result>
    </action>
</package>
</struts>

struts-default.xml文件位於:struts2-core-2.3.x.jar文件中。包struts-default內容參考以下(摘錄自struts-default.xml):apache

    <package name="struts-default" abstract="true">
        <result-types>
            <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
            <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
            <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
            <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
            <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
            <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
            <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
            <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
            <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
            <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
        </result-types>

        <interceptors>
            <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
            <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
            <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
            <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
            <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
            <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
            <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
            <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
            <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
            <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
            <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
            <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
            <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
            <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
            <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
            <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
            <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
            <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
            <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
            <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
            <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
            <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
            <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
            <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
            <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
            <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
            <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
            <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
            <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
            <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
            <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
            <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />

            <!-- Basic stack -->
            <interceptor-stack name="basicStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <interceptor-ref name="conversionError"/>
            </interceptor-stack>

            <!-- Sample validation and workflow stack -->
            <interceptor-stack name="validationWorkflowStack">
                <interceptor-ref name="basicStack"/>
                <interceptor-ref name="validation"/>
                <interceptor-ref name="workflow"/>
            </interceptor-stack>

            <!-- Sample file upload stack -->
            <interceptor-stack name="fileUploadStack">
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample model-driven stack  -->
            <interceptor-stack name="modelDrivenStack">
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample action chaining stack -->
            <interceptor-stack name="chainStack">
                <interceptor-ref name="chain"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample i18n stack -->
            <interceptor-stack name="i18nStack">
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- An example of the paramsPrepareParams trick. This stack
                 is exactly the same as the defaultStack, except that it
                 includes one extra interceptor before the prepare interceptor:
                 the params interceptor.

                 This is useful for when you wish to apply parameters directly
                 to an object that you wish to load externally (such as a DAO
                 or database or service layer), but can't load that object
                 until at least the ID parameter has been loaded. By loading
                 the parameters twice, you can retrieve the object in the
                 prepare() method, allowing the second params interceptor to
                 apply the values on the object. -->
            <interceptor-stack name="paramsPrepareParamsStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <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-stack>

            <!-- A complete stack with all the common interceptors in place.
                 Generally, this stack should be the one you use, though it
                 may do more than you need. Also, the ordering can be
                 switched around (ex: if you wish to have your servlet-related
                 objects applied before prepare() is called, you'd need to move
                 servletConfig interceptor up.

                 This stack also excludes from the normal validation and workflow
                 the method names input, back, and cancel. These typically are
                 associated with requests that should not be validated.
                 -->
            <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="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <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>

            <!-- The completeStack is here for backwards compatibility for
                 applications that still refer to the defaultStack by the
                 old name -->
            <interceptor-stack name="completeStack">
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>

            <!-- Sample execute and wait stack.
                 Note: execAndWait should always be the *last* interceptor. -->
            <interceptor-stack name="executeAndWaitStack">
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
            </interceptor-stack>

       </interceptors>

        <default-interceptor-ref name="defaultStack"/>

        <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
    </package>
View Code

4. 使用攔截器

  • 將攔截器和攔截器棧定義好之後,就可使用這些已定義的攔截器或攔截器棧來攔截Action了,攔截器或攔截器棧會先攔截並處理用戶請求,而後再執行Action的execute方法。
  • 使用攔截器時須要在Action中進行配置,經過<interceptor-ref>標籤來指定在Action中使用的攔截器。
 
默認攔截器的配置參考上節,本節講述經過<interceptor-ref>標籤來指定在Action中使用的攔截器。
<package name="default" extends="struts-default">
    <interceptors>
        <!--定義三個攔截器-->
        <interceptor name="interceptor1" class="interceptorClass"/>
        <interceptor name="interceptor2" class="interceptorClass"/>
        <interceptor name="interceptor3" class="interceptorClass">
            <param name="paramName">paranValue1</param>
        </interceptor>
        <!--定義一個攔截器棧-->
        <interceptor-stack name="myStack">
            <interceptor-ref name="interceptor1"/>
            <interceptor-ref name="interceptor2"/>
            <interceptor-ref name="defaultStack"/>
        </interceptor-stack>
    </interceptors>
    <action name="login" class="tutorial.Login">
        <result name="input">login.jsp</result>
        <!--在名爲login的Action中使用已經定義的攔截器-->
        <interceptor-ref name="interceptor1"/>
        <interceptor-ref name="interceptor2"/>
        <interceptor-ref name="interceptor3">
            <param name="paramName">paramValue2</param>
        </interceptor-ref>
        <interceptor-ref name="myStack"/>
    </action>
</package>

注意:攔截器的參數指定有兩種方式,一種是在定義攔截器時指定參數,該種方式指定的參數是默認參數;另外一種是在使用攔截器時指定參數,該種方式指定的參數將會覆蓋默認參數值。編程

上述內容摘錄自:《Java Web整合開發實戰》第8章cookie

 

實例,未登陸用戶不予查看明細

1. JSP頁面

login.jsp,登陸界面session

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page isELIgnored="false"%>
<%@ taglib uri="/struts-tags" prefix="s"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <body>
        <font style="color:red"><s:property value="errorMessage"/></font>
        <s:form action="intercepLogin" method="post">
            帳號:<s:textfield name="username"></s:textfield>
            <br />
            密碼:<s:textfield name="password"></s:textfield>
            <br />
            <s:submit value="提交"></s:submit>
        </s:form>
    </body>
</html>

showDetail.jsp,顯示詳細信息頁面app

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page isELIgnored="false"%>
<%@ taglib uri="/struts-tags" prefix="s"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <body>
        Hello, we are here!
    </body>
</html>

2. Action類與Interceptor類

InptercepLoginAction.java,處理登陸請求框架

package com.clzhang.struts2.demo11;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class InptercepLoginAction extends ActionSupport {
    private String username;
    private String password;
    
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }

    public String execute() {
        System.out.println(username + "\t" + password);

        // 一到登陸頁面,即移除session中變量
        ActionContext.getContext().getSession().remove("userInfo");
        
        // 只要用戶名與密碼長度大於等於4,都認爲是合法用戶
        if (username.trim().length() >= 4 && password.trim().length() >= 4) {
            ActionContext.getContext().getSession().put("userInfo", username);
            
            return SUCCESS;
        }
        
        return INPUT;
    }
}

ShowAction.java,處理顯示詳細信息請求jsp

package com.clzhang.struts2.demo11;

import com.opensymphony.xwork2.ActionSupport;

public class ShowAction extends ActionSupport {
    public String execute() {
        return SUCCESS;
    }
}

LoginInterceptor.java,攔截器類,處理檢查用戶是否已經登陸

package com.clzhang.struts2.demo11;

import java.util.Map;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class LoginInterceptor extends AbstractInterceptor {

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        // 取得請求相關的ActionContext實例
        ActionContext ctx = invocation.getInvocationContext();
        Map session = ctx.getSession();
        String user = (String)session.get("userInfo");

        // 若是沒有登錄
        if (user != null) {
            System.out.println("當前用戶已經登陸,繼續處理請求...");
            
            return invocation.invoke();
        }

        ctx.put("errorMessage", "你尚未登陸,或者登陸超時,請從新登陸後繼續操做!");
        
        return Action.LOGIN;
    }
}

3. struts.xml文件修改以下內容

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <package name="myStruts" extends="struts-default">
        <interceptors>
            <interceptor name="authority" class="com.clzhang.struts2.demo11.LoginInterceptor">
            </interceptor>
            <!-- 攔截器棧 -->
            <interceptor-stack name="myDefault">
                <interceptor-ref name="defaultStack" />
                <interceptor-ref name="authority"/>
            </interceptor-stack>
        </interceptors>

        <global-results>
            <result name="login">/struts2/demo11/login.jsp</result>  
        </global-results>

        <action name="intercepLogin" class="com.clzhang.struts2.demo11.InptercepLoginAction">
            <result name="input">/struts2/demo11/login.jsp</result>
            <result name="success" type="redirectAction">
                <param name="actionName">intercepShow</param>
            </result>
        </action>

        <action name="intercepShow" class="com.clzhang.struts2.demo11.ShowAction">
            <result>/struts2/demo11/showDetail.jsp</result>
            <interceptor-ref name="myDefault"/>  
        </action>
    </package>
</struts>

4. 測試

打開IE,輸入地址:http://127.0.0.1:8080/st/struts2/intercepShow.action

結果以下:

任意輸入4位長度用戶名與密碼,登陸,便可以顯示詳細頁面。

相關文章
相關標籤/搜索