值棧的含義正如它的名字所表示的那樣——對象所組成的棧。OGNL的全稱是Object Graph Navigational Language(對象圖導航語言),提供了訪問值棧中對象的統一方式。它是一種功能強大的運算式語言(Expression Language,簡稱為EL),通過它簡單一致的運算式文法,可以存取對象的任意屬性,調用對象的方法,遍曆整個對象的結構圖,實現欄位類型轉化等功能。它使用相同的運算式去存取對象的屬性。
值棧中的對象構成及其排列順序如下所示:
1. 臨時對象——在執行過程中,臨時對象被建立出來並放到了值棧中。舉個例子來說,像JSP標籤所遍曆的對象容器中,當前訪問到的值就是臨時對象
2. 模型對象——如果模型對象正在使用,那麼會放在值棧中action的上面
3. Action對象——正在被執行的action
4. 固定名稱的對象(Named Objects)——這些對象包括有#application, #session, #request, #attr 和 #parameters,以及相應的servlet範圍
訪問值棧可以有很多方法,其中最常用的一種就是使用JSP,Velocity或者Freemarker提供的標籤。還有就是使用HTML標籤訪問值棧中對象的屬性;結合運算式使用控制標籤(例如if,elseif和iterator);使用data標籤(set和push)來控制值棧本身。
在使用值棧時,我們無須關心目標對象的範圍。如果要使用名為“name”的屬性,直接從值棧中進行查詢就可以了。值棧中的每一個元素,都會按照排列順序依次檢查是否擁有該屬性。如果有的話,那麼就返回對應的值,查詢結束。如果沒有的話,那麼下一個元素就會被訪問……直到到達值棧的末尾。這個功能非常強大,我們根本不需要知道所需要的值在什麼地方——存在於Action,模型或是HTTP請求中——只要這個值存在,它就會被返回。
但它也有個缺點。如果所請求的是很常見的屬性(例如“id”),而你想要從某個特定的對象中(例如action)擷取該屬性的值,這時候值棧中第一個滿足條件的對象返回的屬性值就可能不是所想要的結果了。返回結果的確是“id”屬性的值,但它可能來自JSP標籤,臨時對象或者模型對象。這時候就需要用到OGNL來增強值棧的功能了。OSGL並不僅限於訪問對象屬性,如果我們知道某個action在值棧中的深度,那麼就可以用“[2].id”來替換掉“id”。
實際上OGNL是一套完整的運算式語言。在OGNL裡面,可以用“.”來遍曆對象圖(比如說,使用“person.address”而不是“getPerson().getAddress()”),它還提供了類型轉換,方法調用,集合的操作與產生,集合間的映射,運算式運算和lambda運算式。OGNL的網站上提供了一套完整的指南,地址為
http://www.ognl.org/2.6.9/Documentation/html/LanguageGuide/index.html。