Struts2第九篇【OGNL、valueStack詳解】

什麼是OGNL表達式?

OGNL是Object Graphic Navigation Language 是操做對象屬性的開源表達式。 Struts2框架使用OGNL做爲默認的表達式語言。java

爲何咱們學習OGNL

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

  • 支持對象方法調用,如xxx.doSomeSpecial()
  • 支持類靜態的方法調用和值訪問,表達式的格式【例如:」@@floor(10.9)」就是調用Math.floor()的方法了】
  • 支持賦值操做和表達式串聯【這個其實EL表達式也能作】
  • 訪問OGNL上下文(OGNL context)和ActionContext
  • 操做集合對象【EL只能遍歷集合,OGNL能夠建立集合】

OGNL是Struts2的默認表達式語言,OGNL是配搭Strut2的標籤使用的..咱們學習了OGNL表達式,就能夠更好地理解Struts2標籤的運行以及Struts2內部的存儲結構.session

valueStack對象

在講解OGNL表達式以前,咱們先來看看valueStack對象…valueStack是Struts2數據存儲的核心…咱們首先要知道數據是怎麼存的,存到哪裏,而後纔講解OGNL表達式是怎麼取出數據的app

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結構..spa

爲了讓request、response等域對象能夠存儲多個值,值也是使用Map結構debug

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/>1、.構建 list集合</br>
    <s:iterator var="str" value="{'a','b'}">
        <s:property value="#str"/>
    </s:iterator>

     <br/>1、.構建 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>
相關文章
相關標籤/搜索