/color]學習Struts2,一直不明白表單中的值是怎麼傳給Action的,上網查了些資料...

/color]學習Struts2,一直不明白表單中的值是怎麼傳給Action的,上網查了些資料,基本瞭解了!下面基本是從幾我的的BOLG轉載過來,之後記不清了再來看~

[color=red]先看看我作的實驗
jsp頁面
Java代碼   收藏代碼
  1. <s:form action="hello/converter.action" method="post">  
  2.         <s:textfield name="point" label="點"></s:textfield>  
  3.         <s:textfield name="point2" label="2"></s:textfield>  
  4.         <s:textfield name="point3" label="3"></s:textfield>  
  5.         <s:textfield name="age" label="年齡"></s:textfield>  
  6.         <s:textfield name="date" label="日期"></s:textfield>  
  7.         <s:submit name="提交"></s:submit>  
  8.     </s:form>  

結果圖(是經過<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上下文設置爲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 application
ValueStack是值棧 存放表單中的值
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代碼   收藏代碼
  1. public class StrutsRequestWrapper extends HttpServletRequestWrapper {     
  2.     
  3.     /**   
  4.      * The constructor   
  5.      * @param req The request   
  6.      */    
  7.     public StrutsRequestWrapper(HttpServletRequest req) {     
  8.         super(req);     
  9.     }     
  10.     
  11.     /**   
  12.      * Gets the object, looking in the value stack if not found   
  13.      *   
  14.      * @param s The attribute key   
  15.      */    
  16.     public Object getAttribute(String s) {     
  17.         if (s != null && s.startsWith("javax.servlet")) {     
  18.             // don't bother with the standard javax.servlet attributes, we can short-circuit this     
  19.             // see WW-953 and the forums post linked in that issue for more info     
  20.             return super.getAttribute(s);     
  21.         }     
  22.     
  23.         ActionContext ctx = ActionContext.getContext();     
  24.         Object attribute = super.getAttribute(s);     
  25.     
  26.         boolean alreadyIn = false;     
  27.         Boolean b = (Boolean) ctx.get("__requestWrapper.getAttribute");     
  28.         if (b != null) {     
  29.             alreadyIn = b.booleanValue();     
  30.         }     
  31.     
  32.         // note: we don't let # come through or else a request for     
  33.         // #attr.foo or #request.foo could cause an endless loop     
  34.         if (!alreadyIn && attribute == null && s.indexOf("#") == -1) {     
  35.             try {     
  36.                 // If not found, then try the ValueStack     
  37.                 ctx.put("__requestWrapper.getAttribute", Boolean.TRUE);     
  38.                 ValueStack stack = ctx.getValueStack();     
  39.                 if (stack != null) {     
  40.                     attribute = stack.findValue(s);     
  41.                 }     
  42.             } finally {     
  43.                 ctx.put("__requestWrapper.getAttribute", Boolean.FALSE);     
  44.             }     
  45.         }     
  46.         return attribute;     
  47.     }     
  48. }    

看到了嘛?這個類會在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壓入ValueStack 2. 在請求進入Action代碼前,經過某種通用的機制,蒐集頁面上傳遞過來的參數,並調用OGNL相關的代碼,對Action進行設值。 上面的第一個步驟,在處理URL請求時完成,而第二個步驟由struts2內置的攔截器完成。
相關文章
相關標籤/搜索