struts,ognl,valuestack
淺析struts2中的OGNL和 ValueStack?
?
要了解Struts2與OGNL表達式的關系,我們必須先搞清楚以下三個概念:
(1)ActionContext? 它是Action運行的上下文環境,Action的多項設置都存放在此,我們每一次Action調用都會創建一個ActionContext 。通常情況下我們可以通過靜態方法getContext()來
獲得Action上下文,進而進行其它操作,比如說可以得到request session application
(2)ValueStack? 此對象主要是由OGNL框架實現,具體的實現類是com.opensymphony.xwork2.
Util.ValueStack; 它主要包含了一個Map類型的Context對象,和最重要的getValue與findValue方法,以及peek、pop等棧所特有的方法。
Strut 2的Action類通過屬性可以獲得所有相關的值,如請求參數、Action配置參數、向其他Action傳遞屬性值(通過chain結果)等等。要獲得這些參數值,我們要做的唯一一件事就是在
Action類中聲明與參數同名的屬性,在Struts 2調用Action類的Action方法(默認是execute方法)之前,就會為相應的Action屬性賦值。
? 要完成這個功能,有很大程度上,Struts 2要依賴于ValueStack對象。這個對象貫穿整個Action的生命周期(每個Action類的對象實例會擁有一個ValueStack對象)。當Struts 2接收到一
個.action的請求后,會先建立Action類的對象實例,并且將Action類的對象實例壓入ValueStack對象中(實際上,ValueStack對于相當一個棧),而ValueStack類的setValue和findValue方
法可以設置和獲得Action對象的屬性值。Struts 2中的某些攔截器正是通過ValueStack類的setValue方法來修改Action類的屬性值的。如params攔截器用于將請求參數值映射到相應成Action
類的屬性值。在params攔截器中在獲得請求參數值后,會使用setValue方法設置相應的Action類的屬性。
? 從這一點可以看出,ValueStack對象就象一個傳送帶,當客戶端請求.action時,Struts 2在創建相應用Action對象后就將Action對象放到了ValueStack傳送帶上,然后ValueStack傳送帶會
帶著Action對象經過若干攔截器,在每一攔截器中都可以通過ValueStack對象設置和獲得Action對象中的屬性值。實際上,這些攔截器就相當于流水線作業。如果要對Action對象進行某項加
工,再加一個攔截器即可,當不需要進行這項工作時,直接將該攔截器去掉即可。
需要注意的是我們訪問這類對象時是不需要加入#的,因為它是根對象,所以不能加#,加了以后就不能訪問到了。比如我們在Action中做了如下操作ActionContext.getContext
().getVlaueStack()
.setVlaue(“MM”,”這是信息”),然后在頁面就只可以通過<s:property value=”MM” />就可以了。
(3) Stack Context(map): stack上下文,它包含一系列對象,包括request/session/attr
/application map等,也是用來存值的。struts2對OGNL上下文的概念又做了進一步擴充,在struts2中,OGNL上下文通常如下所示:
???????? |--request??
???????? |--application??
?context map---|--OgnlValueStack(root) [ user, action, OgnlUtil, ... ]??
???????? |--session??
????????? |--attr??
???????? |--parameters?
? 在Struts2中,采用標準命名的上下文(Context)來處理OGNL表達式。處理OGNL的頂級對象是一個Map(也叫context map,它實際上是ActionContext中的一個對象,也叫context),在這個
contxt屬性中我們分別放置了context.put(“常量REQUEST”,new HashMap<String,Object>()); context.put(“常量APPLICATION”,new HashMap<String,Object>()); 等等,同樣我們在其
中也放置了一個名叫vsMap的對象(自己隨便取了個名字):來看下面兩個相關的方法
???? public void setValueStack(ValueStack stack) {? put(VALUE_STACK, stack);?? }
????? public void put(String key, Object value) {??? context.put(key, value);?? }
我們可以看到這個ValueStack同樣設置到了上下文對象中[實際上使用的ValueStack中的context屬性]。 而ValueStack中除了這個Map以外,還維護一個ComponentRoot對象,它實際上用來存
放我們的一個List集合,它還要維護一個棧即Stack, 以期讓我們進行后續的操作。
Struts2框架把我們的ActionContext設置為OGNL 的上下文環境,凡是此環境中的值我們都應該通過#key的方式來進行訪問,所以request,session等需要加前綴,又因為Struts2將我們的
ValueStack作為OGNL的根對象,所以我們訪問其中的內容只能通過非#的方式來進行。
? Action的實例,總是放到value stack中。因為Action放在stack中,而stack是root(根對象),所以對Action中的屬性的訪問就可以省略#標記。但是,要訪問ActionContext中其它對象的屬
性,就必須要帶上#標記,以便讓OGNL知道,不是從根對象,而是從其它對象中去尋找。具體的代碼可以這樣理解:
??? 而我們直接通過ActionContet.getContext().put(“屬性名”,“值”);放入的數據放在了一個ActionContext 的context對象(OGNL上下文)和ValueStack對象的context對象共同引用的一
個Map對象中,所以我們既可以通過#key也可以直接通過key來進行訪問。
?
那么訪問Action中的屬性的代碼就可以這樣寫
<s:property value="postalCode"/>? 其它ActionContext中的非根對象屬性的訪問要像下面這樣寫:
<s:property value="#session.mySessionPropKey"/> or
<s:property value="#session['mySessionPropKey']"/> or
<s:property value="#request['myRequestPropKey']"/>? 對Collection的處理,內容就很簡單。
<s:select label="label" name="name" list="{'name1','name2','name3'}" value="%{'name2'}" />
??? 這是處理List。這個代碼在頁面上建立一個下拉選項,內容是list中的內容,默認值是name2.
處理map
?<s:select label="label" name="name" list="#{'foo':'foovalue', 'bar':'barvalue'}" />
?需要注意的是,判斷一個值是否在collection中。我們要使用in或者not in來處理。
<s:if test="'foo' in {'foo','bar'}">
?? muhahaha
</s:if>
<s:else>
?? boo
</s:else>
?另外,可以使用通配符來選擇collection對象的子集。
??——所有匹配選擇邏輯的元素
?^——只提取符合選擇邏輯的第一個元素
?$——只提取符合選擇邏輯的最后一個元素
person.relatives.{? #this.gender == 'male'}
`````````````````````````````````````````````````````````````````````````````````
設值計算
Struts2中使用OGNL進行設值計算,就是指View層傳遞數據到Control層,并且能夠設置到相應
的Java對象中。這個過程從邏輯上說需要分成兩步來完成:
1. 對于每個請求,都建立一個與相應Action對應的ActionContext作為OGNL的上下文環境和
ValueStack,并且把Action壓入ValueStack
2. 在請求進入Action代碼前,通過某種通用的機制,搜集頁面上傳遞過來的參數,并調用OGNL相關的??
代碼,對Action進行設值。
上面的第一個步驟,在處理URL請求時完成,而第二個步驟由struts2內置的攔截器完成。
“#”主要有三種用途:
1.?? 訪問OGNL上下文和Action上下文,#相當于ActionContext.getContext();下表有幾個ActionContext中有用的屬性:
?名稱
?作用
?例子
?
parameters
?包含當前HTTP請求參數的Map
?#parameters.id[0]作用相當于request.getParameter("id")
?
request
?包含當前HttpServletRequest的屬性(attribute)的Map
?#request.userName相當于request.getAttribute("userName")
?
session
?包含當前HttpSession的屬性(attribute)的Map
?#session.userName相當于session.getAttribute("userName")
?
application
?包含當前應用的ServletContext的屬性(attribute)的Map
?#application.userName相當于application.getAttribute("userName")
?
attr
?用于按request > session > application順序訪問其屬性(attribute)
?#attr.userName相當于按順序在以上三個范圍(scope)內讀取userName屬性,直到找到為止
?
2.?? 用于過濾和投影(projecting)集合,如books.{?#this.price<100};
3.?? 構造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。
?
“%”符號的用途是在標志的屬性為字符串類型時,計算OGNL表達式的值。[既字符串不是輸出到頁面,而是作為某個屬性的取值],如下面的url就是一個取值。
例如在Ognl.jsp中加入以下代碼:
4.?? <hr />
??? <h3>%的用途</h3>
??? <p><s:url value="#foobar['foo1']" /></p>
??? <p><s:url value="%{#foobar['foo1']}" /></p>
?
$符號?? $符號主要有兩個方面的用途。
? (1)? 在國際化資源文件中,引用OGNL表達式,例如國際化資源文件中的代碼:reg.agerange=國際化資源信息:年齡必須在${min}同${max}之間。
? (2)? 在Struts 2框架的配置文件中引用OGNL表達式,例如下面的代碼片斷所示:
???????? <validators>
??????? <field name=”intb”>
??????????? <field-validator type=”int”>
??????????????? <param name=”min”>10</param>
??????????????? <param name=”max”>100</param>
??????????????? <message>BAction-test校驗:數字必須為${min}為${max}之間!</message>
??????????????? </field-validator>
???????? </field>
???????? </validators>
?
?
總結
以上是生活随笔為你收集整理的struts,ognl,valuestack的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2018年iPhone新机有哪些亮点 软
- 下一篇: 62170022开头是什么银行