學習Struts2,一直不明白表單中的值是怎麼傳給Action的,上網查了些資料,基本了解了!下面基本是從幾個人的BOLG轉載過來,以後記不清了再來看~先看看我做的實驗jsp頁面Java代碼

<s:formaction="hello/converter.action"method="post"> <s:textfieldname="point"label="點"></s:textfield> <s:textfieldname="point2"label="2"></s:textfield> <s:textfieldname="point3"label="3"></s:textfield> <s:textfieldname="age"label="年齡"></s:textfield> <s:textfieldname="date"label="日期"></s:textfield> <s:submitname="提交"></s:submit> </s:form>結果圖(是通過<s:debug></s:debug>得到的)value stack:。。自己去看。。通過圖中我們可以看到valuestack中包括我傳遞的值(point,point2,point3,age,date)stack context中包括了 request application OgnlValueStack(root) session parameters 等屬性值棧(ValueStack)Struts2將OGNL上下文設置為Struts2中的ActionContext(內部使用的仍然是OgnlContext),並將值棧設為OGNL的根對象。我們知道,OGNL上下文中的根對象可以直接訪問,不需要使用任何特殊的「標記」,而引用上下文中的其他對象則需要使用「#」來標記。由於值棧是上下文中的根對象,因此可以直接訪問。那麼對於值棧中的對象該如何訪問呢?Struts2提供了一個特殊的OGNLPropertyAccessor,它可以自動查找棧內的所有對象(從棧頂到棧底),直接找到一個具有你所查找的屬性的對象。也就是說,對於值棧中的任何對象都可以直接訪問,而不需要使用「#」。假設值棧中有兩個對象:student和employee,兩個對象都有name屬性,student有學號屬性number,而employee有薪水屬性salary。employee先入棧,student後入棧,位於棧頂,那麼對於表達式name,訪問的就是student的name屬性,因為student對象位於棧頂;表達式salary,訪問的就是employee的salary屬性。正如你所見,訪問值棧中的對象屬性或方法,無須指明對象,也不用「#」,就好像值棧中的對象都是OGNL上下文中的根對象一樣。這就是Struts2在OGNL基礎上做出的改進。值棧中的Action實例Struts2框架總是把Action實例放在棧頂。因為Action在值棧中,而值棧又是OGNL中的根,所以引用Action的屬性可以省略「#」標記,這也是為什麼我們在結果頁面中可以直接訪問Action的屬性的原因。Struts2中的命名對象Struts2還提供了一些命名對象,這些對象沒有保存在值棧中,而是保存在ActionContext中,因此訪問這些對象需要使用「#」標記。這些命名對象都是Map類型。parameters用於訪問請求參數。如:#parameters["id"]或#parameters.id,相當於調用了HttpServletRequest對象的getParameter()方法。注意,parameters本質上是一個使用HttpServletRequest對象中的請求參數構造的Map對象,一量對象被創建(在調用Action實例之前就已經創建好了),它和HttpServletRequest對象就沒有了任何關係。request用於訪問請求屬性。如:#request["user"]或#request.user,相當於調用了HttpServletRequest對象的getAttribute()方法。session用於訪問session屬性。如:#session["user"]或#session.user,相當於調用了HttpSession對象的getAttribute()方法。application用於訪問application屬性。如:#application["user"]或#application.user,相當於調用了ServletContext的getAttribute()方法。attr如果PageContext可用,則訪問PageContext,否則依次搜索request、session和application對象。以下是轉過來的:先分清楚下ActionContext 、ValueStack 、Stack Context三者ActionContext一次Action調用都會創建一個ActionContext調用:ActionContext context = ActionContext.getContext()ValueStack由OGNL框架實現可以把它簡單的看作一個棧(List) 。Stack Object:放入stack中的對象,一般是action。Stack Context(map):stack上下文,它包含一系列對象,包括request/session/attr/application map等。EL:存取對象的任意屬性,調用對象的方法,遍歷整個對象結…ActionContext是Action上下文,可以得到request session applicationValueStack是值棧 存放表單中的值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類進行測試!)Action的實例,總是放到value stack中。因為Action放在stack中,而stack是root(根對象),所以對Action中的屬性的訪問就可以省略#標記。但是,要訪問ActionContext中其它對象的屬性,就必須要帶上#標記,以便讓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的處理,內容就很簡單。<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中,如何使用自身的Tag讀取Action中的變數?Struts2自身的Tag會根據value中的OGNL表達式,在ValueStack中尋找相應的對象。因為action在ValueStack的頂部,所以默認情況下,Struts2的Tag中的OGNL表達式將查找action中的變數。請注意,value中的內容直接是OGNL表達式,無需任何el的標籤包裝。例如:<s:property value="user.name" />提問:在Struts2中,如何使用自身的Tag讀取HttpServletRequest,HttpSession中的變數?在上面的知識中,我們知道,Struts2中OGNL的上下文環境中,包含request,session,application等servlet對象的Map封裝。既然這些對象都在OGNL的上下文中,那麼根據OGNL的基本知識,我們可以通過在表達式前面加上#符號來對這些變數的值進行訪問。例如:<s:property value="%{#application.myApplicationAttribute}" /><s:property value="%{#session.mySessionAttribute}" /><s:property value="%{#request.myRequestAttribute}" /><s:property value="%{#parameters.myParameter}" />提問:在Struts2中,如何使用JSTL來讀取Action中的變數?這是一個歷史悠久的問題。因為事實上,很多朋友(包括我在內)是不使用Struts2自身的標籤庫,而是使用JSTL的,可能因為JSTL標籤庫比較少,簡單易用的原因吧。我們知道,JSTL默認是從page,request,session,application這四個Scope逐次查找相應的EL表達式所對應的對象的值。那麼如果要使用JSTL來讀取Action中的變數,就需要把Action中的變數,放到request域中才行。所以,早在Webwork2.1.X的年代,我們會編寫一個攔截器來做這個事情的。大致的原理是:在Action執行完返回之前,依次讀取Action中的所有的變數,並依次調用request.setAttribute()來進行設置。具體的整合方式,請參考以下這篇文檔:http://wiki.opensymphony.com/display/WW/Using+WebWork+and+XWork+with+JSP+2.0+and+JSTL+1.1不過隨著時代的發展,上面的這種方式,已經不再被推薦使用了。(雖然如此,我們依然可以學習它的一個解決問題的思路)目前來說,自從Webwork2.2以後,包括Struts2,都使用另外一種整合方式:對HttpServletRequest進行裝飾。讓我們來看一下源碼:Java代碼

publicclassStrutsRequestWrapperextendsHttpServletRequestWrapper{ /** *Theconstructor *@paramreqTherequest */ publicStrutsRequestWrapper(HttpServletRequestreq){ super(req); } /** *Getstheobject,lookinginthevaluestackifnotfound * *@paramsTheattributekey */ publicObjectgetAttribute(Strings){ if(s!=null&&s.startsWith("javax.servlet")){ //don"tbotherwiththestandardjavax.servletattributes,wecanshort-circuitthis //seeWW-953andtheforumspostlinkedinthatissueformoreinfo returnsuper.getAttribute(s); } ActionContextctx=ActionContext.getContext(); Objectattribute=super.getAttribute(s); booleanalreadyIn=false; Booleanb=(Boolean)ctx.get("__requestWrapper.getAttribute"); if(b!=null){ alreadyIn=b.booleanValue(); } //note:wedon"tlet#comethroughorelsearequestfor //#attr.fooor#request.foocouldcauseanendlessloop if(!alreadyIn&&attribute==null&&s.indexOf("#")==-1){ try{ //Ifnotfound,thentrytheValueStack ctx.put("__requestWrapper.getAttribute",Boolean.TRUE); ValueStackstack=ctx.getValueStack(); if(stack!=null){ attribute=stack.findValue(s); } }finally{ ctx.put("__requestWrapper.getAttribute",Boolean.FALSE); } } returnattribute; } }看到了嘛?這個類會在Struts2初始化的時候,替換HttpServletRequest,運行於整個Struts2的運行過程中,當我們試圖調用request.getAttribute()的時候,就會執行上面的這個方法。(這是一個典型的裝飾器模式)在執行上面的方法時,會首先調用HttpServletRequest中原本的request.getAttribute(),如果沒有找到,它會繼續到ValueStack中去查找,而action在ValueStack中,所以action中的變數通過OGNL表達式,就能找到對應的值了。在這裡,在el表達式廣泛使用的今天,JSTL1.1以後,也支持直接使用el表達式。注意與直接使用struts2的tag的區別,這裡需要使用el的表示符號:${}例如:${user.name}, <c:out value="${department.name}" />提問:在Struts2中,如何使用Freemarker等模板來讀取Action中的變數以及HttpServletRequest和HttpSession中的變數?Freemarker等模板在Struts2中有對應的Result,而在這些Result中,Freemarker等模板會根據ValueStack和ActionContext中的內容,構造這些模板可識別的Model,從而使得模板可以以他們各自的語法對ValueStack和ActionContext中的內容進行讀取。有關Freemarker對於變數的讀取,可以參考Struts2的官方文檔,非常詳細:http://struts.apache.org/2.0.14/docs/freemarker.html設值計算Struts2中使用OGNL進行設值計算,就是指View層傳遞數據到Control層,並且能夠設置到相應的Java對象中。這個過程從邏輯上說需要分成兩步來完成:1. 對於每個請求,都建立一個與相應Action對應的ActionContext作為OGNL的上下文環境和ValueStack,並且把Action壓入ValueStack2. 在請求進入Action代碼前,通過某種通用的機制,搜集頁面上傳遞過來的參數,並調用OGNL相關的代碼,對Action進行設值。上面的第一個步驟,在處理URL請求時完成,而第二個步驟由struts2內置的攔截器完成。由於瀏覽了過多的文章,,具體的源地址未能記錄。。但還是感謝網上的原作者。。。
推薦閱讀:

查看原文 >>
相关文章