1. 程式人生 > >Struts2與OGNL的聯絡

Struts2與OGNL的聯絡

1、Struts與OGNL的結合原理

(1)值棧:

 

 

 OGNL表示式要想執行就要準備一個OGNLContext物件,Struts2內部含有一個OGNLContext物件,名字叫做值棧。

 值棧也由兩部分組成,一部分叫做root,裡面放置的是棧,另一部分是context放入的是資料中心。

(2)棧:

 

 

 利用了棧先進先出的特點,每次放入元素的時候是放入到索引為零的位置,取出的時候也是取出索引為零的元素,即:從下圖的最上方元素取,符合棧的先進先出的特性。

 

 

 

2、<s:debug>標籤(檢視值棧中的內容)

(1)root(棧)

 

 

 預設情況下棧中存放當前訪問的Action。

(2)context:

存放以下這些東西:

 即:

 

 3、Struts2與OGNL結合的體現

(1)Action以屬性名的方式獲取資料解析:

直接輸出屬性名,保持和表單的name屬性的值相同。

 

 表單將資料提交給攔截器,攔截器獲取到“name=zhai”後,交給OGNL處理,OGNL從root中拿到name屬性並賦值為“zhai”,由此,Action獲取到了表單提交的資料。

(2)物件方式:

表單:

 獲取:

  OGNL從棧頂獲得user物件後,獲得其name屬性並將其值設定為“zhai”,由此,Action獲取到了表單提交的資料。

(3)模型驅動

 OGNL獲取到name=zhai後,在值棧的root中,將user壓入棧頂,並給user中的name賦值,也就是說從棧頂取元素並賦值。

 原理演示:

建立一個Action:

public class ActionStack extends ActionSupport implements Preparable {
    User user=new User();
    public String execute(){
        System.out.println(user);
        return "success";
    }

    @Override
    public void prepare() throws Exception {
        ValueStack valueStack=ActionContext.getContext().getValueStack();
        valueStack.push(user);
    }
}

實現Preparable介面的原因:

要在賦值前將user壓入棧頂 ,而將獲取棧的程式碼和將user物件壓入棧頂的程式碼寫入到prepare()函式中的目的正是獲取棧並在賦值前將user物件壓入棧頂。

原始碼分析:

 <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-ref name="deprecation"/>
            </interceptor-stack>

在眾多的攔截器中,params攔截器位置相對靠後,因此需要將params攔截器放到prepare攔截器的位置,以實現賦值前將user壓入棧頂。

那麼如何操作呢?開啟prepare攔截器的原始碼可知要呼叫prepare攔截器需要實現Preparable介面並呼叫 prepare()方法。

配置Struts的配置檔案、建立表單、User類後將表單資料提交給Action:

<body>
            <form action="${pageContext.request.contextPath}/s/ActionStack">
                       使用者名稱:<input type="text" name="username"/><br>
                       <input type="submit" value="提交"/>
            </form>
 </body>
public class ActionStack extends ActionSupport implements Preparable {
    User user=new User();
    public String execute(){
        System.out.println(user);
        return "success";
    }

    @Override
    public void prepare() throws Exception {
        ValueStack valueStack=ActionContext.getContext().getValueStack();
        valueStack.push(user);
    }
}

 

 4、在struts.xml配置檔案中的使用

(1)建立兩個Action:

Action1:

public class Action1 extends ActionSupport {
    private String name;

    public String execute(){
        name="zhang";
        return "success";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Action2:

public class Action2 extends ActionSupport {
    public String execute(){
        return "success";
    }
}

(2)配置Struts.xml配置檔案,使得訪問Action1的時候能夠重定向到Action2,:

<struts>
    <package name="action" namespace="/a" extends="struts-default">
        <action name="Action2" class="pers.zhb.hello.Action2" method="execute">
            <result name="success" type="dispatcher">hello.jsp</result>
        </action>
        <action name="Action1" class="pers.zhb.hello.Action1" method="execute">
            <result name="success" type="redirectAction">
                <param name="actionName">Action2</param>
                <param name="namespace">/a</param>
                <param name="name">${name}</param>
            </result>
        </action>
    </package>
</struts>

(3)訪問Action1:

 

 

 

 也就是說在配置struts.xml配置檔案的時候,在<param>標籤內部將name屬性的值設定為屬性不能識別的值,就可以在重定向的時候將引數加到另外一個Actio