1. 程式人生 > 其它 >Struts2【OGNL、ValueStack】

Struts2【OGNL、ValueStack】

什麼是OGNL表示式?

OGNL是Object Graphic Navigation Language 是操作物件屬性的開源表示式。 Struts2框架使用OGNL作為預設的表示式語言。

為什麼我們學習OGNL

在學習JSP的時候,我們已經學習過了EL表示式。EL表示式用起來也十分簡單…我們在Struts2框架中也是可以使用EL表示式的…那麼OGNL表示式好在哪裡呢??

  • 支援物件方法呼叫,如xxx.doSomeSpecial()
  • 支援類靜態的方法呼叫和值訪問,表示式的格式【例如:"@@floor(10.9)"就是呼叫Math.floor()的方法了】
  • 支援賦值操作和表示式串聯【這個其實EL表示式也能做】
  • 訪問OGNL上下文(OGNL context)和ActionContext
  • 操作集合物件【EL只能遍歷集合,OGNL可以建立集合】

OGNL是Struts2的預設表示式語言,OGNL是配搭Strut2的標籤使用的..我們學習了OGNL表示式,就可以更好地理解Struts2標籤的執行以及Struts2內部的儲存結構.

valueStack物件

在講解OGNL表示式之前,我們先來看看valueStack物件…valueStack是Struts2資料儲存的核心…我們首先要知道資料是怎麼存的,存到哪裡,然後才講解OGNL表示式是怎麼取出資料的

valueStack也被稱作值棧物件..

  • 當用戶訪問Action,都會建立一個Action物件,ActionContext物件、valueStack物件
    ..
  • Struts2把Action物件放進valueStack物件之中
  • 將valueStack放進request域中,傳入JSP頁面(key: struts.valueStack)
  • JSP頁面就可以使用OGNL表示式獲取值棧中的資料了

獲取valueStack物件

  • 在Action中我們可以手動獲取值棧物件,有兩種方式獲取
    //獲取值棧物件的2種方式
    private void getVs() {
        // 獲取值棧物件,方式1:
        HttpServletRequest request = ServletActionContext.getRequest();
        ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");

        // 獲取值棧物件,方式2: 
        ActionContext ac = ActionContext.getContext();
        ValueStack vs2 = ac.getValueStack();

        System.out.println(vs1 == vs2);//true
    }

valueStack內部儲存結構

上面已經說了,使用者訪問Action時,會建立Action物件,valueStack物件。Struts2內部會將Action物件存到valueStack物件之中…那麼valueStack的儲存結構是什麼樣的呢???我們來看看

這裡寫圖片描述

CompoundRoot

Action物件和Action的成員屬性等值都是存到CompoundRoot下的.該CompoundRoot繼承著ArrayList,因此它是List結構的

    public class CompoundRoot extends ArrayList {}

OgnlContext

OgnlContext物件儲存著相關的域物件:request、response、session等資料,實現Map集合,是Map結構..

為了讓request、response等域物件可以儲存多個值,值也是使用Map結構

public class OgnlContext implements Map {}

小總結

這裡寫圖片描述

CompoundRoot儲存著這樣的資料:

  • Action物件以及Action物件的成員屬性資料
  • 使用ValueStack物件.push()進去的資料
  • 使用ValueStack物件.set()進去的資料
  • 其他代理物件的資料

OgnlContext儲存著這樣的資料:

  • 維護了CompoundRoot中所有的資料
  • request、response等域物件所有的資料

OGNL表示式取值

  • Struts2會將valueStack物件封裝進request物件域中,傳入JSP頁面。
  • valueStack儲存著OgnlContext物件。
  • OgnlContext物件維護了CompoundRoot物件的資料
  • CompoundRoot儲存著Action等資料

也就是說通過OgnlContext物件可以獲取大部分我們需要的資料了。

那麼OGNL表示式是怎麼取出OgnlContext物件中資料的呢??下面我們通過硬編碼的方式來講解

    /**
     * 1. Ognl表示式語言語言取值,取非根元素的值,必須用#號
     * @throws Exception
     */
    @Test
    public void testOgnl() throws Exception {
        // 建立一個Ognl上下文物件
        OgnlContext context = new OgnlContext();
        // 放入資料
        User user = new User();
        user.setId(100);
        user.setName("Jack");
        // 【往非根元素放入資料, 取值的時候表示式要用"#"】
        context.put("user", user);

        // 獲取資料(map)
        // 先構建一個Ognl表示式, 再解析表示式
        Object ognl = Ognl.parseExpression("#user.name");
        Object value = Ognl.getValue(ognl, context, context.getRoot());

        System.out.println(value);
    }

    /**
     * 2. Ognl表示式語言語言取值,取根元素的值,不用帶#號
     * @throws Exception
     */
    @Test
    public void testOgn2() throws Exception {
        // 建立一個Ognl上下文物件
        OgnlContext context = new OgnlContext();
        // 放入資料
        User user = new User();
        user.setId(100);
        user.setName("Jack");
        // 【往根元素放入資料】
        context.setRoot(user);

        // 獲取資料(map)
        // 先構建一個Ognl表示式, 再解析表示式
        Object ognl = Ognl.parseExpression("address.province");
        Object value = Ognl.getValue(ognl, context, context.getRoot());

        System.out.println(value);
    }

也就是說,JSP頁面中取出資料的時候,它會先構建一個OGNL表示式,再解析表示式

  • 如果是CompoundRoot類的資料,表示式不需要帶#號
  • 如果不是CompoundRoot類的資料,表示式需要帶#號

這裡寫圖片描述

例子:

      <!-- 頁面: 必須要拿到ValueStack -->
     <br/>1. 取根元素的值<br/>
     <s:property value="user.id"/> 
     <s:property value="user.name"/> 
     <s:property value="user.address"/> 
     <s:property value="user.address.city"/> 
     <s:property value="user.address.province"/> 

      <br/>2. 取非根元素的值<br/>
      <s:property value="#request.cn"/>
      <s:property value="#session.Session_data"/>
      <s:property value="#application.Application_data"/>    <br/>

      <!-- 自動找request/session/application,找到後立刻返回 -->
      <s:property value="#request_data"/>
      <s:property value="#attr.Session_data"/>
      <s:property value="#attr.Application_data"/>  <br/>

      <!-- 獲取請求的引數資料 -->
      <s:property value="#parameters.userName"/>

     <!-- struts的除錯標籤:可以觀測值棧資料 -->
     <s:debug></s:debug>

OGNL對靜態方法的呼叫

    /**
     * 3.Ognl對 靜態方法呼叫的支援
     * @throws Exception
     */
    @Test
    public void testOgn3() throws Exception {
        // 建立一個Ognl上下文物件
        OgnlContext context = new OgnlContext();

        // Ognl表單式語言,呼叫類的靜態方法
        //Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
        // 由於Math類在開發中比較常用,所以也可以這樣寫
        Object ognl = Ognl.parseExpression("@@floor(10.9)");
        Object value = Ognl.getValue(ognl, context, context.getRoot());
        System.out.println(value);
    }

OGNL建立集合

    <br/>一、.構建 list集合</br>
    <s:iterator var="str" value="{'a','b'}">
        <s:property value="#str"/>
    </s:iterator>

     <br/>一、.構建 map集合</br>
     <s:iterator var="en" value="#{'cn':'China','usa':'America'}">
         <s:property value="#en.key"/>
         <s:property value="#en.value"/>  <br/>
     </s:iterator>

構建Map集合的時候,需要使用#號


OGNL 幾個特殊的符號

#獲取非根元素值 、 動態都建map集合 $ 在配置檔案取值 % 提供一個ognl表示式執行環境

<body>
       <br/>獲取request域資料<br/>
       <!-- property 標籤是物件型別的標籤,預設支援ognl表示式, 會從根元素去China名稱對應的值 -->
       <s:property value="China"/>        <br/>
       <!-- 如果直接賦值,需要用單引號 -->
       <s:property value="'China'"/>      <br/>
       <s:property value="%{#request.cn}"/>       <br/>

       <!-- 值型別的標籤,value值預設就是值型別,不支援ognl表示式 -->
       國家:<s:textfield name="txtCountry" value="%{#request.cn}"></s:textfield>
  </body>