1. 程式人生 > >Struts2系統學習(16)OGNL表示式及基本原理分析

Struts2系統學習(16)OGNL表示式及基本原理分析

16. OGNL表示式

16.1 OGNL表示式語言簡介

  OGNL (Object Graph Navigation Language)物件圖導航語言。Struts2框架使用OGNL作為預設的表示式語言。
  OGNL相對其它表示式語言具有下面幾大優勢:

  • 支援物件方法呼叫,如xxx.doSomeSpecial();
  • 支援類靜態方法的呼叫和值的訪問,表示式的格式:
      @[類全名(包括包路徑)]@[方法名 | 值名],例如:
      @[email protected](‘foo %s’, ‘bar’)
      或@[email protected]_NAME;
  • 支援賦值操作和表示式串聯;
  • 訪問OGNL上下文ActionContext;
  • 操作集合物件List,Map。
      Ognl 有一個上下文(Context)概念,在 Struts2 中上下文(Context)的實現為ActionContext,ActionContext物件對應Action,可以理解為action執行相關的物件的容器,包括application,session,parameters,locale,value stack等。ActionContext中:

  • ValueStack是OGNL上下文的root元素,貫穿整個 Action 的生命週期(每個Action類的物件例項都擁有一個ValueStack 物件)。 相當於一個數據的中轉站. 在其中儲存當前Action 物件和其他相關物件。

  • private Map<String, Object> context;這個才是真正意義上的上下文。其中可以put進資料,jsp中可通過OGNL表示式通過key獲取。
      OGNL Context 實現者為 ActionContext ,它結構示意圖如下 :
    這裡寫圖片描述

      注:這裡的context map指的是ActionContext的map效果;action為相關的action包名,而不是action物件(程式碼中更清晰)。

16.2 理解Struts2中的 ValueStack和OGNL Context

  ValueStack實際是一個介面,在Struts2中利用OGNL時,實際上使用的是實現了該介面的OgnlValueStack類,這個類是Struts2利用OGNL的基礎。
  ValueStack(值棧): 貫穿整個 Action 的生命週期(每個 Action 類的物件例項都擁有一個ValueStack 物件). 相當於一個數據的中轉站. 在其中儲存當前Action 物件和其他相關物件。
  OgnlValueStack 類包含兩個重要的屬性:

    CompoundRoot root; // CompoundRoot extends ArrayList
    transient Map<String, Object> context;
  • 其中root為一個ArrayList模擬的值棧,action等相關物件就是儲存這裡:
    /**
     * 實現ValueStack介面的pop操作
     * @see com.opensymphony.xwork2.util.ValueStack#pop()
     */
    public Object pop() {
        return root.pop();
    }

    /**
     * 實現ValueStack介面的push操作
     * @see com.opensymphony.xwork2.util.ValueStack#push(java.lang.Object)
     */
    public void push(Object o) {
        root.push(o);
    }

  再檢視ActionContext類的原始碼可知:

public class ActionContext implements Serializable {

    static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();

    // 所要執行的action類名
    public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name";

    // 值棧ValueStack的類名,即上面所說的_root物件
    public static final String VALUE_STACK = ValueStack.VALUE_STACK;
    public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session";
    public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application";
    public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters";
    public static final String LOCALE = "com.opensymphony.xwork2.ActionContext.locale";
    // context map
    private Map<String, Object> context;
    ...
}

  會發現ActionContext中包含一個context,OgnlValueStack中也包含一個context,這兩個context是否為同一個物件呢??我們在action的execute方法中進行測試:

    public String execute() {
        ActionContext context = ActionContext.getContext();
        OgnlValueStack ognlValueStack = (OgnlValueStack) context.getValueStack();
        // 獲取OgnlValueStack中的context屬性
        Map<String, Object> ognlValueStack_Context = ognlValueStack.getContext();
        // 獲取ActionContext中的context屬性
        Map<String, Object> actionContext_Context = context.getContextMap();
        // 比較ActionContext中的context屬性和OgnlValueStack中的context屬性是否為同一個物件
        System.out.println(ognlValueStack_Context == actionContext_Context); // true

        return SUCCESS;
    }

  測試結果為true!所以說ActionContext中的context屬性和OgnlValueStack中的context屬性實則為同一個物件!這也就解釋了:通過ActionCOntext.getContext().put();方法放入到context(Map集合)的資料,也即OgnlValueStack中context(Map集合),所以可以通過OGNL表示式可以獲取。
  :在Ognl上下文物件(ActionContext)中,維持值棧root的包名(com.opensymphony.xwork2.util.ValueStack.ValueStack),OGNL訪問root中的元素時,是不需要#號的,直接通過元素的名稱來進行訪問;而訪問其他物件時,如application、request、session、parameters、attr等,則需要#號引用。

  當Struts2接受一個請求時,會迅速建立ActionContext,ValueStack,action等。然後把action存放進值棧OgnlValueStack的root物件中,所以在頁面上通過Struts2標籤訪問Action的屬性時,就不需要通過#號來引用。

  由於 ValueStack( 值棧 ) 是 Struts 2 中 OGNL上下文的根物件,如果使用者需要訪問值棧中的物件,在 JSP 頁面可以通過EL表示式訪問 ValueStack(值棧)中物件的屬性:

${foo} // 獲得值棧中某個物件的 foo 屬性

  如果訪問其他 Context 中的物件,由於他們不是根物件,所以在訪問時,需要新增 # 字首。

  • application物件:用於訪問ServletContext,例如#application.userName或者#application[‘userName’],相當於呼叫ServletContext的getAttribute(“username”)。
  • session物件:用來訪問HttpSession ,例如#session.userName或者#session[‘userName’] ,相當於呼叫session.getAttribute(“userName”)。
  • request物件:用來訪問HttpServletRequest屬性(attribute)的Map,例如#request.userName或者#request[‘userName’] ,相當於呼叫request.getAttribute(“userName”)。
  • parameters物件:用於訪問HTTP的請求引數,例如#parameters.userName或者#parameters[‘userName’] ,相當於呼叫 request.getParameter(“username”)。
  • attr物件:用於按page->request->session->application順序訪問其屬性。

16.3 為何使用EL 表示式能夠訪問valueStack中物件的屬性

  在JSP頁面中通過${foo} 這樣的EL表示式就可以獲取值棧中某個物件的 foo 屬性。原因是Struts2對HttpServletRequest作了進一步的封裝。簡略程式碼如下:

public class StrutsRequestWrapper extends HttpServletRequestWrapper {
    public StrutsRequestWrapper(HttpServletRequest req) {
        super(req);
    }
    public Object getAttribute(String key) {
        ......
        ActionContext ctx = ActionContext.getContext();
        Object attribute = super.getAttribute(key);// 先從 request 範圍獲取屬性值
        // 如果從 request 範圍沒有找到屬性值 , 即從 ValueStack 中查詢物件的屬性值
        if (ctx != null && attribute == null) {
            ......
                    ValueStack stack = ctx.getValueStack();
                        if (stack != null) {
                             attribute = stack.findValue(key);
                        }
            ......
        }
        return attribute;
    }
}

16.4 基本案例測試

  案例需求:輸入介面通過表單輸入資料,並注入到action中,輸出介面通過Ognl表示式獲取輸入的內容中未儲存到action部分和儲存的部分,已經action中只提供get方法的屬性。(即獲取以上討論的三種類型的資料)
  (1)輸入介面input.jsp

<form action="/Ognl/day07/ognlTest.action" method="post">
    username: <input type="text" name="username"/><br>
    phone:   <input type="text" name="phone"/><br>
    <!-- 此屬性並沒有注入到action的屬性中 -->
    other:  <input type="text" name="other"/><br>
    <input type="submit" value="提交">
</form>

  (2)Action類:

package com.markliu.day07;

import org.apache.struts2.ServletActionContext;

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

public class OgnlTestAction extends ActionSupport {
    private static final long serialVersionUID = 4491003976083155453L;

    private String username;
    private String phone;
    private String message;

    public String getMessage() {
        return message;
    }

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String execute() {
        this.message = "從action獲取message!";
        return SUCCESS;
    }

}

  (3)struts.xml配置:

    <package name="day07" namespace="/day07" extends="struts-default">
            <action name="ognlTest" class="com.markliu.day07.OgnlTestAction" method="execute">
                <result name="success">/pages/day07/ognlGetInfo.jsp</result>
            </action>
    </package>

  (4)ognl獲取資料顯示:

<%@ taglib uri="/struts-tags" prefix="s" %>
 ...
<body>
輸入的值並儲存到action中的屬性:
<s:property value="username"/><br>
${phone }<br>
輸入的值沒有儲存到action中的屬性:${other }<s:property value="other"/><br>
action中只提供get方法的屬性: ${message }
</body>

  (5)執行顯示:

輸入的值並儲存到action中的屬性: wq
18212345678
輸入的值沒有儲存到action中的屬性:
action中只提供get方法的屬性: action獲取message! 

  由執行結果可知:由於action被儲存到valuestack值棧中,所以使用者輸入的資訊注入到action中的屬性,以及action本身的屬性(提供get方法)都可以通過OGNL表示式的兩種形式獲取:EL表示式或Struts2標籤。

16.5 採用 OGNL 表示式建立 List/Map 集合物件

  如果需要一個集合元素的時候(例如 List 物件或者 Map 物件),可以使用 OGNL 中同集合相關的表示式。
  使用如下程式碼直接生成一個 List 物件:

<s:set name="list" value="{'zhangming','xiaoi','liming'}" />
<!-- s:iterator會將當前迭代的物件放到值棧的棧頂中!因此才會有s:property預設輸出ValueStack棧頂的值 -->
<s:iterator value="#list" id="n">
    <s:property value="n"/><br>
</s:iterator>
<!-- s:property標籤的value屬性可選,如果沒有給定,則預設輸出ValueStack棧頂的值
     因此還可以簡寫成如下形式 -->
<s:iterator value="#list">
    <s:property/><br>
</s:iterator>

  生成一個 Map 物件:

<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" />
<s:iterator value="#foobar" >
    <!-- Map集合迭代採用了內部的Entry類,且此時迭代的Entry物件放在值棧的棧頂,
    Entry中包含key和value的屬性,因此可以通過OGNL表示式獲取棧頂物件的屬性 -->
    <s:property value="key"/>=<s:property value="value"/><br>
</s:iterator>

  <s:set>標籤用於將某個值放入指定範圍。

- scope:指定變數被放置的範圍,該屬性可以接受application、session、request、page或action。如果沒有設定該屬性,則預設放置在ActionContext(OGNL上下文)中。
- value :賦給變數的值 . 如果沒有設定該屬性 , 則將 ValueStack 棧頂的值賦給變數。

  對於集合型別, OGNL 表示式可以使用 in 和 not in 兩個元素符號。其中, in 表示式用來判斷某個元素是否在指定的集合物件中; not in 判斷某個元素是否不在指定的集合物件中。s:if標籤的test中填入OGNL表示式,如下所示。

<s:if test="'foo' in {'foo','bar'}">
</s:if>
<s:else>
</s:else>

<s:if test="'foo' not in {'foo','bar'}">
</s:if>
<s:else>
</s:else>

16.6 OGNL 表示式的投影功能

  除了 in 和 not in 之外, OGNL 還允許使用某個規則獲得集合物件的子集,常用的有以下 3 個相關操作符:
? :獲得所有符合邏輯的元素。
^ :獲得符合邏輯的第一個元素。
$ :獲得符合邏輯的最後一個元素。
例如程式碼,獲取價格大於35的所有圖書:

<s:iterator value="books.{?#this.price > 35}">
    <s:property value="title" /> - $<s:property value="price" /><br>
</s:iterator>

相關推薦

Struts2系統學習16OGNL表示式基本原理分析

16. OGNL表示式 16.1 OGNL表示式語言簡介   OGNL (Object Graph Navigation Language)物件圖導航語言。Struts2框架使用OGNL作為預設

Struts2學習———— ognl表示式、值棧、actionContext之間的關係

一、什麼是Ognl?       通過百度百科查詢到的解釋,其中詳細的說明了OGNL的作用。                  下面我們就對OGNL這5個作用進行講解       1、存取物件的任意屬性,簡單說就是對javabean進行操作(重要)       2、呼叫物件方法。       3、

Struts2框架與頁面的資料互動2--OGNL表示式&ValueStack

3、Struts2框架與頁面的資料互動(2)--OGNL表示式&ValueStack 上接Struts2礦街與頁面的資料互動(1)--資料封裝:https://blog.csdn.net/biggerchong/article/details/84564912 目錄

Struts2學習———— ognl表達式、值棧、actionContext之間的關系

需要 三種 查詢 哪些 tac 一次 詳細講解 大堆 存儲對象 一、什麽是Ognl?       通過百度百科查詢到的解釋,其中詳細的說明了OGNL的作用。                  下面我們就對OGNL這5個作用進行講解       1、存取對象的任意屬性,簡單說

ext2文件系統學習—— 目錄磁盤結構

echo free 文件格式 htm file 目錄結構 bitmap 點號 name 創建鏡像、mount等操作和上一篇一樣,測試目錄結構如下: 一些文件系統信息如下: Block size: 1024 Inodes per group: 1

Shiro學習16綜合實例

字符 autowire 驗證 load nsh view 公司 bytes quest 簡單的實體關系圖 簡單數據字典 用戶(sys_user) 名稱 類型 長度 描述 id bigint 編號 主鍵

操作系統學習、80x86保護模式內存管理

分享 共享棧 問題 代碼 就會 空間 階段 logs ima 整理的不好,湊合著看吧 目錄 1.內存及尋址 2.地址變換 3.分段機制 4.分頁機制 5.保護 6.去到底部 一、內存及尋址 返回目錄 二、地址變換 80X86 從 邏輯地址 到 物理地址 的轉換

操作系統學習、分頁機制

x86 頁面 管理機 技術 由於 映射 空間 pos 邏輯地址 目錄 1.分頁機制介紹 2.頁表結構 3.頁表項格式 4.虛擬存儲 5.直達底部 分頁機制介紹 分頁機制是 80x86 內存管理機制的第二部分。它在分段機制的基礎上完成虛擬地址到物理地址的轉換過程。分段

Linux文件系統學習之相關概念???

正是 range 不同的 struct pan 根據 inode 存在 opera “一切皆是文件”是 Unix/Linux 的基本哲學之一。不僅普通的文件,目錄、字符設備、塊設備、套接字等在 Unix/Linux 中都是以文件被對待;它們雖然類型不同,但是對其提供的卻是同

操作系統學習系統啟動過程

中斷向量 初始化 地址 I/O 向量 錯誤 cpu 系統初始 系統初始化 一、操作系統啟動部分主要執行流程 當PC電源打開後,80x86結構的CPU將自動進入實時模式。並從地址0xFFFF0 (FFFF:0) 開始自動執行程序代碼,這個地址通常是是ROM-BIOS中的地址

操作系統學習 、保護機制概述

長度 發的 之間 軟件開發 軟件 內存空間 工作 尋找 超級用戶 保護機制是可靠運行多任務環境所必須的。它可以用於保護各個任務免受互相之間的幹擾。在軟件開發的任何階段都可以使用段級和頁級保護來協助尋找和檢測設計問題和錯誤。當程序對錯誤內存空間執行了一次非期望的引用,保護機制

操作系統學習 、訪問數據段時的特權級檢查

區域 系統 才會 使用 執行 有效 以及 選擇 改變 為了訪問數據段中的操作數,數據段的段選擇符必須被加載進數據段寄存器(DS,ES,FS或GS)或堆棧段寄存器(SS)中。可以使用指令MOV、POP、LDS、LES、LFS、lGS和LSS來加載段寄存器。 在把一個段選擇符加

操作系統學習十三 、中斷和異常

中斷控制器 外部 兩種 它的 恢復 條件 事件 內部錯誤 範圍 一、中斷和異常 中斷何和異常是指明系統、處理器或當前執行程序(或任務)的某處出現一個事件,該事件需要處理器進行處理。通常,這種事情會導致執行控制器被強迫從當前運行程序轉移到被稱為終端處理程序或異常處理程序的特殊

Linux文件系統學習之重要數據結構1

class targe html evel 系統結構 會有 集合 spec lan 轉載自:https://blog.csdn.net/wudongxu/article/details/6436894 《Linux內核設計與實現》 http://www.ibm.com/

MariaDb資料庫管理系統學習使用HeidiSQL資料庫圖形化介面管理工具

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

JAVAWEB學習10 - EL表示式和JSTL

EL表示式和JSTL 一、EL表示式 1.1. EL表示式是什麼 是一套簡單的運算規則,用於給jsp標籤的屬性賦值,也可以脫離jsp標籤,直接使用。 1.2. EL表示式的使用 1.2.1. 讀取bean的屬性值 javabean指的是一個符合如下要求的Java類:

rabbitmq系統學習

各種mq activemq,kafka使用zookeeper做管理 rocketmq自己實現nameserver broke管理 AMQP核心概念 高階訊息佇列協議 publisher application->Server->Virtual host->Exc

4天--Struts2相關學習day01

Struts2課程安排 第一天:struct2 入門 第二天:strcut2 資料操作 第三天:struct2 值棧 第四天:struct2 攔截器 今天內容 1 struts2概述 (1)應用在web層 2 stru

Struts2入門學習

Struts2的前身是Opensymphony的Webwork2,實際上Strut和Webwork2合併後形成Struts2。 3.建立控制類HelloWord package com.yyq.action; import com.opensymphon

推薦系統學習——協同過濾

一、協同過濾推薦演算法的原理及實現 見連結詳細介紹 https://blog.csdn.net/yimingsilence/article/details/54934302 1.基於使用者的協同過濾 如上述連結例題未看懂看此例題: 2.基於專案的協同過濾 二、協同