OGNL是Object-Graph Navigation Language的縮寫,全稱為對象圖導航語言,是一種功能強大的表達式語言,它通過簡單一致的語法,可以任意存取對象的屬性或者調用對象的方法,能夠遍歷整個對象的結構圖,實現對象屬性類型的轉換等功能。
Struts 2支持以下幾種表達式語言:
Struts 2默認的表達式語言是OGNL,原因是它相對其它表達式語言具有下面幾大優勢:
補充:
(一)對“上下文”概念的理解
上下文, 英文是context,其完整意思應當是concatenate-text,聯系文本,在IT行業中譯為上下文其實並不確切也不容易理解,尤其是對於初學者,把它翻譯為“引用池”或者“引用區”更加恰當。 比如在一篇15頁的部門介紹中,中華人民共和國中央廣播電視總局(以下簡稱廣電總局),這裡的以下,就是下文,在第15頁的時候,你看到廣電總局四個字就知道具體是哪個部門而不會弄混,這就是在上文做了解釋。 在java的JSP中的內置對象中的PageContext,事實上,它就是本頁面的一個單獨的儲存區域,裡面存放的是各個地方(各個范圍)傳過來的屬性的鍵值對的總匯。比如說,從Application裡面存儲了apptime,appname等等屬性,在Session中又存了sessionid sessionstate等等屬性,在request范圍中又存了username,password等屬性的鍵值對,那麼PageContext就會把所有能得到的屬性全部集中到一個區域裡,你可以通過這個小容器,接收和調用到各個范圍傳遞過來的屬性,這就是所謂的”上下文“, 你可以把它記為”引用池“! (二)valuestack,stackContext,ActionContext之間的關系三者之間的關系如下圖所示:
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類型。
StackContext“根”對象和普通命名對象的區別在於:
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表達式的值,這個類似js中的eval,很暴力。
$符號
$符號主要有兩個方面的用途:
名字屬性獲取:<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表達式計算階乘:
<s:property value="#f = :[#this==1?1:#this*#f(#this-1)] , #f(4)"/><br>
獲取Paraments對象的屬性:<s:property value="#parameters.username"/>
用%{}可以取出存在值堆棧中的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:表示第一個。