Struts2中OGNL,valueStack,stackContext的学习
http://jwx0925.iteye.com/blog/630335
[/color]學(xué)習(xí)Struts2,一直不明白表單中的值是怎么傳給Action的,上網(wǎng)查了些資料,基本了解了!下面基本是從幾個人的BOLG轉(zhuǎn)載過來,以后記不清了再來看~[color=red]先看看我做的實驗jsp頁面
Java代碼 <s:form action="hello/converter.action" method="post"><s:textfield name="point" label="點"></s:textfield><s:textfield name="point2" label="2"></s:textfield><s:textfield name="point3" label="3"></s:textfield><s:textfield name="age" label="年齡"></s:textfield><s:textfield name="date" label="日期"></s:textfield><s:submit name="提交"></s:submit></s:form>
結(jié)果圖(是通過<s:debug></s:debug>得到的)
value stack:
Stack context:
通過圖中我們可以看到
valuestack中包括我傳遞的值(point,point2,point3,age,date)
stack context中包括了 request application OgnlValueStack(root) session parameters 等屬性
值棧(ValueStack)
Struts2將OGNL上下文設(shè)置為Struts2中的ActionContext(內(nèi)部使用的仍然是OgnlContext),并將值棧設(shè)為OGNL的根對象。
我們知道,OGNL上下文中的根對象可以直接訪問,不需要使用任何特殊的“標(biāo)記”,而引用上下文中的其他對象則需要使用“#”來標(biāo)記。由于值棧是上下文中的根對象,因此可以直接訪問。那么對于值棧中的對象該如何訪問呢?Struts2提供了一個特殊的OGNLPropertyAccessor,它可以自動查找棧內(nèi)的所有對象(從棧頂?shù)綏5?,直接找到一個具有你所查找的屬性的對象。也就是說,對于值棧中的任何對象都可以直接訪問,而不需要使用“#”。
假設(shè)值棧中有兩個對象:student和employee,兩個對象都有name屬性,student有學(xué)號屬性number,而employee有薪水屬性salary。employee先入棧,student后入棧,位于棧頂,那么對于表達(dá)式name,訪問的就是student的name屬性,因為student對象位于棧頂;表達(dá)式salary,訪問的就是employee的salary屬性。正如你所見,訪問值棧中的對象屬性或方法,無須指明對象,也不用“#”,就好像值棧中的對象都是OGNL上下文中的根對象一樣。這就是Struts2在OGNL基礎(chǔ)上做出的改進(jìn)。
值棧中的Action實例
Struts2框架總是把Action實例放在棧頂。因為Action在值棧中,而值棧又是OGNL中的根,所以引用Action的屬性可以省略“#”標(biāo)記,這也是為什么我們在結(jié)果頁面中可以直接訪問Action的屬性的原因。
Struts2中的命名對象
Struts2還提供了一些命名對象,這些對象沒有保存在值棧中,而是保存在ActionContext中,因此訪問這些對象需要使用“#”標(biāo)記。這些命名對象都是Map類型。
parameters
用于訪問請求參數(shù)。如:#parameters['id']或#parameters.id,相當(dāng)于調(diào)用了HttpServletRequest對象的getParameter()方法。
注意,parameters本質(zhì)上是一個使用HttpServletRequest對象中的請求參數(shù)構(gòu)造的Map對象,一量對象被創(chuàng)建(在調(diào)用Action實例之前就已經(jīng)創(chuàng)建好了),它和HttpServletRequest對象就沒有了任何關(guān)系。
request
用于訪問請求屬性。如:#request['user']或#request.user,相當(dāng)于調(diào)用了HttpServletRequest對象的getAttribute()方法。
session
用于訪問session屬性。如:#session['user']或#session.user,相當(dāng)于調(diào)用了HttpSession對象的getAttribute()方法。
application
用于訪問application屬性。如:#application['user']或#application.user,相當(dāng)于調(diào)用了ServletContext的getAttribute()方法。
attr
如果PageContext可用,則訪問PageContext,否則依次搜索request、session和application對象。
以下是轉(zhuǎn)過來的:先分清楚下ActionContext 、ValueStack 、Stack Context三者
ActionContext
一次Action調(diào)用都會創(chuàng)建一個ActionContext
調(diào)用:ActionContext context = ActionContext.getContext()
ValueStack
由OGNL框架實現(xiàn)
可以把它簡單的看作一個棧(List) 。
Stack Object:放入stack中的對象,一般是action。
Stack Context(map):stack上下文,它包含一系列對象,包括request/session/attr/application map等。
EL:存取對象的任意屬性,調(diào)用對象的方法,遍歷整個對象結(jié)…
ActionContext是Action上下文,可以得到request session application
ValueStack是值棧 存放表單中的值
Stack Context 棧上下文 也是用來存值的
struts2對OGNL上下文的概念又做了進(jìn)一步擴充,在struts2中,OGNL上下文通常如下所示:
??????????????????????? |--request??
??????????????????????? |??
??????????????????????? |--application??
??????????????????????? |??
context map---|--OgnlValueStack(root) [ user, action, OgnlUtil, ... ]??
??????????????????????? |??
??????????????????????? |--session??
??????????????????????? |??
??????????????????????? |--attr??
??????????????????????? |??
??????????????????????? |--parameters?
??? 在Struts2中,采用標(biāo)準(zhǔn)命名的上下文(Context)來處理OGNL表達(dá)式。處理OGNL的頂級對象是一個Map(也叫context map),而OGNL在這個context中就是一個頂級對象(root)。在用法上,頂級對象的屬性訪問,是不需要任何標(biāo)記前綴的。而其它非頂級的對象訪問,需要使用#標(biāo)記。
??? Struts2框架把OGNL Context設(shè)置為我們的ActionContext。并且ValueStack作為OGNL的根對象。除value stack之外,Struts2框架還把代表application、session、request這些對象的Map對象也放到ActionContext中去。(這也就是Struts2建議在Action類中不要直接訪問Servlet API的原因,他可以通過ActionContext對象來部分代替這些(Servlet API)功能,以方便對Action類進(jìn)行測試!)
??? Action的實例,總是放到value stack中。因為Action放在stack中,而stack是root(根對象),所以對Action中的屬性的訪問就可以省略#標(biāo)記。但是,要訪問ActionContext中其它對象的屬性,就必須要帶上#標(biāo)記,以便讓OGNL知道,不是從根對象,而是從其它對象中去尋找。
??? 那么訪問Action中的屬性的代碼就可以這樣寫
<s:property value="postalCode"/>
??? 其它ActionContext中的非根對象屬性的訪問要像下面這樣寫:
<s:property value="#session.mySessionPropKey"/> or
<s:property value="#session['mySessionPropKey']"/> or
<s:property value="#request['myRequestPropKey']"/>
??? 對Collection的處理,內(nèi)容就很簡單。
<s:select label="label" name="name" list="{'name1','name2','name3'}" value="%{'name2'}" />
??? 這是處理List。這個代碼在頁面上建立一個下拉選項,內(nèi)容是list中的內(nèi)容,默認(rèn)值是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中,如何使用自身的Tag讀取Action中的變量?
Struts2自身的Tag會根據(jù)value中的OGNL表達(dá)式,在ValueStack中尋找相應(yīng)的對象。因為action在ValueStack的頂部,所以默認(rèn)情況下,Struts2的Tag中的OGNL表達(dá)式將查找action中的變量。請注意,value中的內(nèi)容直接是OGNL表達(dá)式,無需任何el的標(biāo)簽包裝。
例如:<s:property value="user.name" />
提問:在Struts2中,如何使用自身的Tag讀取HttpServletRequest,HttpSession中的變量?
在上面的知識中,我們知道,Struts2中OGNL的上下文環(huán)境中,包含request,session,application等servlet對象的Map封裝。既然這些對象都在OGNL的上下文中,那么根據(jù)OGNL的基本知識,我們可以通過在表達(dá)式前面加上#符號來對這些變量的值進(jìn)行訪問。
例如:<s:property value="%{#application.myApplicationAttribute}" />
<s:property value="%{#session.mySessionAttribute}" />
<s:property value="%{#request.myRequestAttribute}" />
<s:property value="%{#parameters.myParameter}" />
提問:在Struts2中,如何使用JSTL來讀取Action中的變量?
這是一個歷史悠久的問題。因為事實上,很多朋友(包括我在內(nèi))是不使用Struts2自身的標(biāo)簽庫,而是使用JSTL的,可能因為JSTL標(biāo)簽庫比較少,簡單易用的原因吧。
我們知道,JSTL默認(rèn)是從page,request,session,application這四個Scope逐次查找相應(yīng)的EL表達(dá)式所對應(yīng)的對象的值。那么如果要使用JSTL來讀取Action中的變量,就需要把Action中的變量,放到request域中才行。所以,早在Webwork2.1.X的年代,我們會編寫一個攔截器來做這個事情的。大致的原理是:在Action執(zhí)行完返回之前,依次讀取Action中的所有的變量,并依次調(diào)用request.setAttribute()來進(jìn)行設(shè)置。具體的整合方式,請參考以下這篇文檔:http://wiki.opensymphony.com/display/WW/Using+WebWork+and+XWork+with+JSP+2.0+and+JSTL+1.1
不過隨著時代的發(fā)展,上面的這種方式,已經(jīng)不再被推薦使用了。(雖然如此,我們依然可以學(xué)習(xí)它的一個解決問題的思路)目前來說,自從Webwork2.2以后,包括Struts2,都使用另外一種整合方式:對HttpServletRequest進(jìn)行裝飾。讓我們來看一下源碼:
Java代碼 public class StrutsRequestWrapper extends HttpServletRequestWrapper { /** * The constructor * @param req The request */ public StrutsRequestWrapper(HttpServletRequest req) { super(req); } /** * Gets the object, looking in the value stack if not found * * @param s The attribute key */ public Object getAttribute(String s) { if (s != null && s.startsWith("javax.servlet")) { // don't bother with the standard javax.servlet attributes, we can short-circuit this // see WW-953 and the forums post linked in that issue for more info return super.getAttribute(s); } ActionContext ctx = ActionContext.getContext(); Object attribute = super.getAttribute(s); boolean alreadyIn = false; Boolean b = (Boolean) ctx.get("__requestWrapper.getAttribute"); if (b != null) { alreadyIn = b.booleanValue(); } // note: we don't let # come through or else a request for // #attr.foo or #request.foo could cause an endless loop if (!alreadyIn && attribute == null && s.indexOf("#") == -1) { try { // If not found, then try the ValueStack ctx.put("__requestWrapper.getAttribute", Boolean.TRUE); ValueStack stack = ctx.getValueStack(); if (stack != null) { attribute = stack.findValue(s); } } finally { ctx.put("__requestWrapper.getAttribute", Boolean.FALSE); } } return attribute; } }
看到了嘛?這個類會在Struts2初始化的時候,替換HttpServletRequest,運行于整個Struts2的運行過程中,當(dāng)我們試圖調(diào)用request.getAttribute()的時候,就會執(zhí)行上面的這個方法。(這是一個典型的裝飾器模式)在執(zhí)行上面的方法時,會首先調(diào)用HttpServletRequest中原本的request.getAttribute(),如果沒有找到,它會繼續(xù)到ValueStack中去查找,而action在ValueStack中,所以action中的變量通過OGNL表達(dá)式,就能找到對應(yīng)的值了。
在這里,在el表達(dá)式廣泛使用的今天,JSTL1.1以后,也支持直接使用el表達(dá)式。注意與直接使用struts2的tag的區(qū)別,這里需要使用el的表示符號:${}
例如:${user.name}, <c:out value="${department.name}" />
提問:在Struts2中,如何使用Freemarker等模板來讀取Action中的變量以及HttpServletRequest和HttpSession中的變量?
Freemarker等模板在Struts2中有對應(yīng)的Result,而在這些Result中,Freemarker等模板會根據(jù)ValueStack和ActionContext中的內(nèi)容,構(gòu)造這些模板可識別的Model,從而使得模板可以以他們各自的語法對ValueStack和ActionContext中的內(nèi)容進(jìn)行讀取。
有關(guān)Freemarker對于變量的讀取,可以參考Struts2的官方文檔,非常詳細(xì):http://struts.apache.org/2.0.14/docs/freemarker.html
設(shè)值計算
Struts2中使用OGNL進(jìn)行設(shè)值計算,就是指View層傳遞數(shù)據(jù)到Control層,并且能夠設(shè)置到相應(yīng)的Java對象中。這個過程從邏輯上說需要分成兩步來完成:
1. 對于每個請求,都建立一個與相應(yīng)Action對應(yīng)的ActionContext作為OGNL的上下文環(huán)境和ValueStack,并且把Action壓入ValueStack
2. 在請求進(jìn)入Action代碼前,通過某種通用的機制,搜集頁面上傳遞過來的參數(shù),并調(diào)用OGNL相關(guān)的代碼,對Action進(jìn)行設(shè)值。
上面的第一個步驟,在處理URL請求時完成,而第二個步驟由struts2內(nèi)置的攔截器完成。
由于瀏覽了過多的文章,,具體的源地址未能記錄。。但還是感謝網(wǎng)上的原作者。。。
?
?
http://kang36897.blog.163.com/blog/static/1704737320104144194505/
struts2:關(guān)于EL能夠獲得action的屬性??
2010-05-14 16:19:04|??分類: J2EE |??標(biāo)簽: |舉報 |字號大中小?訂閱
今天一個哥們學(xué)習(xí)struts2,嘗試使用OGNL,由于關(guān)聯(lián)性吧,就又跳到EL上面,結(jié)果神奇的事情發(fā)生,他用EL表達(dá)式從request域里面居然拿到了action鐘的屬性,這個天崩地裂的,大家都知道struts2中存值對象都放在actioncontext中,如下圖:這幅截圖來自于STURTS2 IN ACTIN一書中,由于action是放到valuestack中的,但是valuestack與request貌似沒有交集吧。
他居然拿到了,疑惑開始了,通過在頁面中添加<S:DEBUG/>標(biāo)簽發(fā)現(xiàn)了一個問題,居然在request里面有struts2.valuestack這么個變量吧,疑團(tuán)沒有散去,卻變得更加大了,怎么搞的?
?? 最后從網(wǎng)上發(fā)現(xiàn)了一篇相似的帖子:
原文鏈接:http://i.laoer.com/struts2-use-el-jstl.html
最近在公司里做一些Java Web開發(fā)的培訓(xùn),同時對已經(jīng)做的一些工程做一些ReView,現(xiàn)在的工程里,工程師直接使用JSTL取得Action里的屬性,這個用法我以前到真的沒 有用過,因為在我印象中,Struts2的這些Action屬性,應(yīng)該是在ValueStack中,而在某些情況下,從ValueStack取值是件挺麻 煩的事情,在做天乙社區(qū)8時, 我就參考Struts2的標(biāo)記庫,自己擴展標(biāo)記庫,從而取得ValueStack里的值,而JSTL應(yīng)該是從Page、Request、Session和 Application里順序取值,莫非Struts2將ValueStack里的值也放入了Request?同時我們直接用EL標(biāo)簽也直接取出了 Action的屬性值,莫非真的放入了Request?但是打開Struts2的Debug,發(fā)現(xiàn)Request里并沒有值。
帶著這個疑問,我Google了一下,很快找到答案:
提問:在Struts2中,如 何使用JSTL來讀取Action中的變量?
這是一個歷史悠久的問題。因為事實上,很多朋友(包括我在內(nèi))是不使用Struts2自身的標(biāo)簽庫,而是使用JSTL的,可能因為JSTL標(biāo)簽庫比 較少,簡單易用的原因吧。
我們知道,JSTL默認(rèn)是從page,request,session,application這四個Scope逐次查找相應(yīng)的EL表達(dá)式所對應(yīng) 的對象的值。那么如果要使用JSTL來讀取Action中的變量,就需要把Action中的變量,放到request域中才行。所以,早在 Webwork2.1.X的年代,我們會編寫一個攔截器來做這個事情的。大致的原理是:在Action執(zhí)行完返回之前,依次讀取Action中的所有的變 量,并依次調(diào)用request.setAttribute()來進(jìn)行設(shè)置。具體的整合方式,請參考以下這篇文檔:http://wiki.opensymphony.com/display/WW/Using+WebWork+and+XWork+with+JSP+2.0+and+JSTL+1.1
不過隨著時代的發(fā)展,上面的這種方式,已經(jīng)不再被推薦使用了。(雖然如此,我們依然可以學(xué)習(xí)它的一個解決問題的思路)目前來說,自從 Webwork2.2以后,包括Struts2,都使用另外一種整合方式:對HttpServletRequest進(jìn)行裝飾。讓我們來看一下源碼:
 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | public class StrutsRequestWrapper extends HttpServletRequestWrapper {/*** The constructor* @param req The request*/public StrutsRequestWrapper(HttpServletRequest req) {super(req);}/*** Gets the object, looking in the value stack if not found** @param s The attribute key*/public Object getAttribute(String s) {if (s != null && s.startsWith("javax.servlet")) {// don't bother with the standard javax.servlet attributes, we can short-circuit this// see WW-953 and the forums post linked in that issue for more inforeturn super.getAttribute(s);}ActionContext ctx = ActionContext.getContext();Object attribute = super.getAttribute(s);boolean alreadyIn = false;Boolean b = (Boolean) ctx.get("__requestWrapper.getAttribute");if (b != null) {alreadyIn = b.booleanValue();}// note: we don't let # come through or else a request for// #attr.foo or #request.foo could cause an endless loopif (!alreadyIn && attribute == null && s.indexOf("#") == -1) {try {// If not found, then try the ValueStackctx.put("__requestWrapper.getAttribute", Boolean.TRUE);ValueStack stack = ctx.getValueStack();if (stack != null) {attribute = stack.findValue(s);}} finally {ctx.put("__requestWrapper.getAttribute", Boolean.FALSE);}}return attribute;} } | 
看到了嘛?這個類會在Struts2初始化的時候,替換HttpServletRequest,運行于整個Struts2的運行過程中,當(dāng)我們試 圖調(diào)用request.getAttribute()的時候,就會執(zhí)行上面的這個方法。(這是一個典型的裝飾器模式)在執(zhí)行上面的方法時,會首先調(diào)用 HttpServletRequest中原本的request.getAttribute(),如果沒有找到,它會繼續(xù)到ValueStack中去查找, 而action在ValueStack中,所以action中的變量通過OGNL表達(dá)式,就能找到對應(yīng)的值了。
在這里,在el表達(dá)式廣泛使用的今天,JSTL1.1以后,也支持直接使用el表達(dá)式。注意與直接使用struts2的tag的區(qū)別,這里需要使用 el的表示符號:${}
例如:${user.name}, <c:out value=”${department.name}” />
?
總結(jié)
以上是生活随笔為你收集整理的Struts2中OGNL,valueStack,stackContext的学习的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: OGNL表达式struts2标签“%,#
- 下一篇: Struts2技术详解
