Struts2的OGNL表達式語言

来源:http://www.cnblogs.com/ttflove/archive/2016/11/24/6098670.html
-Advertisement-
Play Games

一.OGNL的概念 OGNL是Object-Graph Navigation Language的縮寫,全稱為對象圖導航語言,是一種功能強大的表達式語言,它通過簡單一致的語法,可以任意存取對象的屬性或者調用對象的方法,能夠遍歷整個對象的結構圖,實現對象屬性類型的轉換等功能。 Struts 2支持以下幾 ...


一.OGNL的概念

OGNL是Object-Graph Navigation Language的縮寫,全稱為對象圖導航語言,是一種功能強大的表達式語言,它通過簡單一致的語法,可以任意存取對象的屬性或者調用對象的方法,能夠遍歷整個對象的結構圖,實現對象屬性類型的轉換等功能

Struts 2支持以下幾種表達式語言:

  1. OGNL(Object-Graph Navigation Language),可以方便地操作對象屬性的開源表達式語言;
  2. JSTL(JSP Standard Tag Library),JSP 2.0集成的標準的表達式語言;
  3. Groovy,基於Java平臺的動態語言,它具有時下比較流行的動態語言(如Python、Ruby和Smarttalk等)的一些起特性;
  4. Velocity,嚴格來說不是表達式語言,它是一種基於Java的模板匹配引擎,具說其性能要比JSP好。

Struts 2預設的表達式語言是OGNL,原因是它相對其它表達式語言具有下麵幾大優勢:

  • 支持對象方法調用,如xxx.doSomeSpecial();
  • 支持類靜態的方法調用和值訪問,表達式的格式為@[類全名(包括包路徑)]@[方法名 | 值名],例如:@java.lang.String@format('foo %s', 'bar')或@tutorial.MyConstant@APP_NAME;
  • 支持賦值操作和表達式串聯,如price=100, discount=0.8, calculatePrice(),這個表達式會返回80;
  • 訪問OGNL上下文(OGNL context)和ActionContext;
  • 操作集合對象。

二.OGNL的重要知識點

1.OGNL表達式的計算是圍繞OGNL上下文進行的。    OGNL上下文實際上就是一個Map對象,由ognl.OgnlContext類表示。它裡面可以存放很多個JavaBean對象。它有一個上下文根對象。    上下文中的根對象可以直接使用名來訪問或直接使用它的屬性名訪問它的屬性值。否則要加首碼“#key”。 2.Struts2的標簽庫都是使用OGNL表達式來訪問ActionContext中的對象數據的。如:<s:propertyvalue="xxx"/>。 3.Struts2將ActionContext設置為OGNL上下文,並將值棧作為OGNL的根對象放置到ActionContext中。 4.值棧(ValueStack) :    可以在值棧中放入、刪除、查詢對象。訪問值棧中的對象不用“#”。    Struts2總是把當前Action實例放置在棧頂。所以在OGNL中引用Action中的屬性也可以省略“#”。 5.調用ActionContext的put(key,value)放入的數據,需要使用#訪問。

補充:

(一)對“上下文”概念的理解

上下文, 英文是context,其完整意思應當是concatenate-text,聯繫文本,在IT行業中譯為上下文其實並不確切也不容易理解,尤其是對於初學者,把它翻譯為“引用池”或者“引用區”更加恰當。 比如在一篇15頁的部門介紹中,中華人民共和國中央廣播電視總局(以下簡稱廣電總局),這裡的以下,就是下文,在第15頁的時候,你看到廣電總局四個字就知道具體是哪個部門而不會弄混,這就是在上文做瞭解釋。 在java的JSP中的內置對象中的PageContext,事實上,它就是本頁面的一個單獨的儲存區域,裡面存放的是各個地方(各個範圍)傳過來的屬性的鍵值對的總匯。比如說,從Application裡面存儲了apptime,appname等等屬性,在Session中又存了sessionid sessionstate等等屬性,在request範圍中又存了username,password等屬性的鍵值對,那麼PageContext就會把所有能得到的屬性全部集中到一個區域里,你可以通過這個小容器,接收和調用到各個範圍傳遞過來的屬性,這就是所謂的”上下文“, 你可以把它記為”引用池“! (二)valuestack,stackContext,ActionContext之間的關係

三者之間的關係如下圖所示:

relation


  1. ActionContext :一次Action調用都會創建一個ActionContext ,調用:ActionContext context = ActionContext.getContext()
  2. ValueStack :由OGNL框架實現 ,可以把它簡單的看作一個List
  3. Stack Object:放入stack中的對象,一般是action。
  4. Stack Context(map):stack上下文,它包含一些列對象,包括request/session/attr/application map等。 
  5. EL:存取對象的任意屬性,調用對象的方法,遍歷整個對象結構圖。

ActionContext是Action上下文,可以得到request session application。
ValueStack是值棧 存放表單中的值。
Stack Context 棧上下文 也是用來存值的。

個人看法,action context 是在action中通過actionSupport類來獲取到,主要作用是獲取request之類的對象,然 後valuestack和stack context都是為了使用OGNL,其中value stack 是stack context的根對象,所以我們在JSP頁面中訪問value stack的內容時,是不用加#,而如果是訪問stack context的其他對象則要加上#。

由於值棧是上下文中的 根對象,因此可以直接訪問。那麼對於值棧中的對象該如何訪問呢?Struts2提供了一個特殊的OGNLPropertyAccessor,它可以自動查找棧內的所有對象(從棧頂到棧底),直接找到一個具有你所查找的屬性的對象。也就是說,對於值棧中的任何對象都可以直接訪問,而不需要使用“#”。

Struts2框架總是把Action實例放在棧頂。因為Action在值棧中,而值棧又是OGNL中的根,所以引用Action的屬性可以省略“#”標記,這也是為什麼我們在結果頁面中可以直接訪問Action的屬性的原因。    
 OGNL的Stack Context里除了包括ValueStack這個根之外,還包括
一些命名對象,這些對象沒有保存在值棧中,而是保存在ActionContext中,因此訪問這些對象需要使用“#”標記。這些命名對象都是Map類型。 

  • parameters:用於訪問請求參數。如:#parameters['id']或#parameters.id,相當於調用了HttpServletRequest對象的getParameter()方法。註意,parameters本質上是一個使用HttpServletRequest對象中的請求參數構造的Map對象,一量對象被創建(在調用Action實例之前就已經創建好了),它和HttpServletRequest對象就沒有了任何關係。
  • request對象:用於訪問HttpServletRequest的屬性。例如#request['foo']或者#request.foo,用於返回HttpServletRequest的getAttribute("foo")方法的返回值。
  • session對象:用於訪問HttpSession的屬性。例如#rsession['foo']或者#session.foo,用於返回HttpSession的getAttribute("foo")方法的返回值。
  • application對象:用於訪問ServletContext的屬性,例如#application['foo']或者#application.foo,用於返回ServletContext的getAttribute("foo")方法的返回值。
  • attr對象:該對象將依次搜索如下對象:PageContext、HttpServletRequest、HttpSession、ServletContext中的屬性。

StackContext“根”對象和普通命名對象的區別在於:

  • 訪問StackContext里的命名對象需要在對象名之前添加#首碼。
  • 當訪問OGNL的Stack Context里的“根”對象的屬性時,可以省略對象名。

struts2對OGNL上下文的概念又做了進一步擴充,在struts2中,OGNL上下文通常如下所示:

                        |--request   

                        |   

                        |--application   

                        |   

 context map---|--OgnlValueStack(root) [ user, action, OgnlUtil, ... ]   

                        |   

                        |--session   

                        |   

                        |--attr   

                        |   

                        |--parameters   

 


    在Struts2中,採用標準命名的上下文(Context)來處理OGNL表達式。處理OGNL的頂級對象是一個Map(也叫context map),而OGNL在這個context中就是一個頂級對象(root)。在用法上,頂級對象的屬性訪問,是不需要任何標記首碼的。而其它非頂級的對象 訪問,需要使用#標記。
    Struts2框架把OGNL Context設置為我們的ActionContext。並且ValueStack作為OGNL的根對象。除value stack之外,Struts2框架還把代表application、session、request這些對象的Map對象也放到 ActionContext中去。(這也就是Struts2建議在Action類中不要直接訪問Servlet API的原因,它可以通過ActionContext對象來部分代替這些(Servlet API)功能 ,以方便對Action類進行測試!)

三、OGNL中的三個重要符號#、%、$

#符號

#符號的用途一般有三種:

  1. 訪問非根對象屬性,例如#session.msg表達式,由於Struts 2中值棧被視為根對象,所以訪問其他非根對象時,需要加#首碼。實際上,#相當於ActionContext. getContext();#session.msg表達式相當於ActionContext.getContext().getSession(). getAttribute("msg") 。
  2. 用於過濾和投影(projecting)集合,如persons.{?#this.age>25},persons.{?#this.name=='pla1'}.{age}[0]。
  3. 用來構造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}。

%符號

%符號的用途是在標誌的屬性為字元串類型時,計算OGNL表達式的值,這個類似js中的eval,很暴力。

$符號

$符號主要有兩個方面的用途:

  1. 在國際化資源文件中,引用OGNL表達式,例如國際化資源文件中的代碼:reg.agerange=國際化資源信息:年齡必須在${min}同${max}之間。
  2. 在Struts 2框架的配置文件中引用OGNL表達式,例如:
    1. <validators>    
    2.     <field name="intb">    
    3.             <field-validator type="int">    
    4.             <param name="min">10</param>    
    5.             <param name="max">100</param>    
    6.             <message>BAction-test校驗:數字必須為${min}為${max}之間!</message>    
    7.         </field-validator>    
    8.     </field>    
    9. </validators

四、OGNL使用方式

  • 訪問屬性

    名字屬性獲取:<s:property value="user.username"/><br>

    地址屬性獲取:<s:property value="user.address.addr"/><br>

  • 訪問方法

    調用值棧中對象的普通方法:<s:property value="user.get()"/><br>

  • 訪問靜態屬性和方法

    調用Action中的靜態方法:<s:property value="@struts.action.LoginAction@get()"/>

    調用JDK中的類的靜態方法:<s:property value="@Java.lang.Math@floor(44.56)"/><br>

    調用JDK中的類的靜態方法(同上):<s:property value="@@floor(44.56)"/><br>

    調用JDK中的類的靜態方法:<s:property value="@java.util.Calendar@getInstance()"/><br>

    調用普通類中的靜態屬性:<s:property value="@struts.vo.Address@TIPS"/><br>

  • 訪問構造方法

    調用普通類的構造方法:<s:property value="new struts.vo.Student('李曉紅' , '美女' , 3 , 25).username"/>

  • 訪問數組

    獲取List:<s:property value="testList"/><br>

    獲取List中的某一個元素(可以使用類似於數組中的下標獲取List中的內容):

    <s:property value="testList[0]"/><br>

    獲取Set:<s:property value="testSet"/><br>

    獲取Set中的某一個元素(Set由於沒有順序,所以不能使用下標獲取數據):

    <s:property value="testSet[0]"/><br> ×

    獲取Map:<s:property value="testMap"/><br>

    獲取Map中所有的鍵:<s:property value="testMap.keys"/><br>

    獲取Map中所有的值:<s:property value="testMap.values"/><br>

    獲取Map中的某一個元素(可以使用類似於數組中的下標獲取List中的內容):

    <s:property value="testMap['m1']"/><br>

    獲取List的大小:<s:property value="testSet.size"/><br>

  • 訪問集合 – 投影、選擇(? ^ $)

    利用選擇獲取List中成績及格的對象:<s:property value="stus.{?#this.grade>=60}"/><br>

    利用選擇獲取List中成績及格的對象的username:

    <s:property value="stus.{?#this.grade>=60}.{username}"/><br>

    利用選擇獲取List中成績及格的第一個對象的username:

    <s:property value="stus.{?#this.grade>=60}.{username}[0]"/><br>

    利用選擇獲取List中成績及格的第一個對象的username:

    <s:property value="stus.{^#this.grade>=60}.{username}"/><br>

    利用選擇獲取List中成績及格的最後一個對象的username:

    <s:property value="stus.{$#this.grade>=60}.{username}"/><br>

    利用選擇獲取List中成績及格的第一個對象然後求大小:

    <s:property value="stus.{^#this.grade>=600}.{username}.size"/><br>

  • 集合的偽屬性

    OGNL能夠引用集合的一些特殊的屬性,這些屬性並不是JavaBeans模式,例如size(),length()等等. 當表達式引用這些屬性時,OGNL會調用相應的方法,這就是偽屬性.

     

  •  Lambda   :[…]    格式::[…]

    使用Lambda表達式計算階乘:

    <s:property value="#f = :[#this==1?1:#this*#f(#this-1)] , #f(4)"/><br>

  • OGNL中#的使用 #可以取出堆棧上下文中的存放的對象.

       

獲取Paraments對象的屬性:<s:property value="#parameters.username"/>

  •  OGNL中%的使用 

     用%{}可以取出存在值堆棧中的Action對象,直接調用它的方法.

     例如你的Action如果繼承了ActionSupport .那麼在頁面標簽中,用%{getText('key')}的方式可以拿出國際化信息.

     OGNL中$的使用

    “$”有兩個主要的用途

     用於在國際化資源文件中,引用OGNL表達式

     在Struts 2配置文件中,引用OGNL表達式

 

 值棧

ValueStack對象。這個對象貫穿整個Action的生命周期(每個Action類的對象實例會擁有一個ValueStack對象)。當Struts 2接收到一個.action的請求後,會先建立Action類的對象實例,但並不會調用Action方法,而是先將Action類的相應屬性放到ValueStack對象的頂層節點(ValueStack對象相當於一個棧)。

在Action中獲得ValueStack對象:ActionContext.getContext().getValueStack()

Top語法:使用Top獲取值棧中的第二個對象:<s:property value="[1].top.對象"/>

N語法:使用N獲取值棧中的第二個對象:<s:property value="[1].對象"/>

@語法:調用action中的靜態方法:<s:property value="@vs1@靜態方法"/> vs:值棧 1:表示第一個。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 》題目要求 》》隨機輸入一個網址 》》截取出該網址的功能變數名稱並顯示 》程式實現 1 package cn.fury.test; 2 3 import java.util.Scanner; 4 5 public class Test{ 6 public static void main(String[] ...
  • 按排序位置的獲取單個欄目的鏈接信息 >>dede>> {dede:autochannel partsort='' typeid=''}{/dede:autochannel} >>dede>> partsort = '0' 欄目所在的排序位置 typeid = '0' 指定的父欄目—>等於0的時候,上... ...
  • 》題目要求: 》》編寫一個收銀櫃臺收款程式。 》》》要求:接收用戶輸入的商品單價、購買數量以及用戶付款的金額 》》》計算並輸出八折以後的商品金額和找零 》程式實現 1 package cn.fury.test; 2 3 import java.util.Scanner; 4 5 public cla ...
  • 1.成員變數的繼承 1.1要點 子類用extends關鍵字繼承父類。子類中可以提供新的方法覆蓋父類中的方法。子類中的方法不能直接訪問父類中的私有域,子類可以用super關鍵字調用父類中的方法。在子類中可以增加域,增加方法或者覆蓋超類的方法,然而絕對不能刪除繼承的任何域和方法。 在一個子類被創建的時候 ...
  • spring squertz是一個強大的定時任務處理方式 1、需要的Jar quartz-1.8.5.jar commons-logging.jar spring-core-3.0.5.RELEASE.jar spring-beans-3.0.5.RELEASE.jar spring-context ...
  • 本文地址 1 程式開發語言綜述 2 iOS開發工程師必備技能 3 運維工程師必備技能 4 前端工程師必備技能 5 大數據工程師必備技能 6 雲計算工程師必備技能 7 安全工程師必備技能 8 移動無線測試工程師必備技能 9 嵌入式開發必備技能 10 微服務架構技能圖譜 11 Hadoop家族技能圖譜 ...
  • 分頁查詢: 首先我們要明確什麼是分頁?為什麼要去分頁? 分頁就是將數據以多頁去展示,使用分頁可以提高客戶的感受。 分頁的分類: 1.物理分頁:只從資料庫中查詢當前頁的數據 優點:不占用很多記憶體 缺點:效率比價低(相比於邏輯分頁) 2.邏輯分頁:從資料庫將所有記錄查詢出來,存儲到記憶體中,展示當前頁,然 ...
  • [1]文件類型 [2]文件屬性 [3]目錄路徑 [4]目錄遍歷 [5]目錄統計 [6]目錄增刪 [7]目錄複製 [8]文件操作 [9]文件內容 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...