天天看點

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t0">valuestack</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t1">如何得到值棧:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t2">如何将對象存入值棧:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t3">讓值棧執行表達式來獲得值:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t4">在jsp中跳過棧頂元素直接通路第二層:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t5">在jsp中通路值棧對象本身(而不是它們的屬性)</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t6">actioncontext</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t7">valuestack與actioncontext的聯系和差別:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t8">如何獲得actioncontext:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t9">如何向actioncontext中存入值:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t10">如何從actioncontext中讀取值:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t11">httpservletrequest類或request的map</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t12">使用httpservletrequest類還是request的map</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t13">使用request的map還是actioncontext:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t14">如何獲得httpservletrequest:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t15">如何獲得request的map:</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t16">parameters,即get請求或post請求的參數</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t17">httpservletsession類和session的map</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t18">servletcontext和application的map</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t19">附錄1 actioncontext中到底有哪些資料</a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t20"></a>

<a target="_blank" href="http://blog.csdn.net/ambow_cq/article/details/7458810#t21">附錄2 struts2标簽中value屬性直接對actioncontext通路的問題</a>

筆者不知道該用哪個詞來形容valuestack、actioncontext等可以在struts2中用來存放資料的類。這些類使用的範圍不同,得到的方法也不同,下面就來一一介紹。

聲明:本文參考struts2版本為2.3.1.2,内容僅供參考,限于筆者水準有限,難免有所疏漏,望您能友善指出。本文發表于iteye,謝絕轉載。

在struts2執行一次請求的過程中,struts2會把目前的action對象自動放入值棧。這樣,在渲染jsp時,jsp裡的代碼使用&lt;s:property value="..."/&gt;之類标簽中的ognl表達式會直接作用于action對象,進而友善的讀取action的屬性。

在jsp中,直接使用标簽即可獲得值棧裡的資料,而一般不用擷取值棧本身。

struts2自動存入action:之前已經提到,struts2在執行一次請求的過程中會把目前的action對象自動存入值棧中。

在自定義的攔截器中存入值棧:得到值棧對象後調用valuestack.put(object object)方法。

在action類中存入值棧:得到值棧對象後調用valuestack.put(object object)方法。

在自定義的攔截器中,獲得值棧後,使用valuestack.findvalue(...)等方法。

在action類中,獲得值棧後,使用valuestack.findvlaue(...)等方法。

在表示式中使用top關鍵字來通路對象本身。比如,表達式“name”等價于“top.name”,表達式“[0].top”等價于“top”,表達式“[1].top.name”等價于“[1].name”。

總之,值棧主要目的是為了讓jsp内能友善的通路action的屬性。

一些例子:

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

view

code

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 此類為一個封裝資料的簡單類,在下面的例子會用到

 2 public class person {

 3 

 4     private string name;

 5 

 6     public string getname() {

 7         return name;

 8     }

 9 

10     public void setname(string name) {

11         this.name = name;

12     }

13 }

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 本類将示範攔截器中對值棧的操作   

 2 public class myinterceptor extends abstractinterceptor {   

 3   

 4     public string intercept(actioninvocation invocation) throws exception {   

 5         // 獲得值棧   

 6         valuestack valuestack = invocation.getstack();   

 7         // 存入值   

 8         person person = new person();   

 9         valuestack.push(person);   

10         // 執行表達式擷取值   

11         string name = (string) valuestack.findvalue("name");   

12         // 其他代碼   

13         return invocation.invoke();   

14     }   

15 }  

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 本類将示範在action中對值棧進行操作   

 2 public class myaction extends actionsupport {   

 4     @override  

 5     public string execute() throws exception {   

 6         // 獲得值棧   

 7         valuestack valuestack = actioncontext.getcontext().getvaluestack();   

 8         // 存入值   

 9         person person = new person();// 這是之前例子中定義的類  

10         valuestack.push(person);   

11         // 執行表達式擷取值   

12         string name = (string) valuestack.findvalue("name");   

13         // 其他代碼   

14         // ......   

15         return success;   

16     }   

17     // 以下定義的屬性供接下來的jsp例子使用   

18     private string message;   

19     private person person;   

20     private list&lt;person&gt; personlist;   

21   

22     public string getmessage() {   

23         return message;   

24     }   

25   

26     public person getperson() {   

27         return person;   

28     }   

29   

30     public list&lt;person&gt; getpersonlist() {   

31         return personlist;   

32     }   

33 }  

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 &lt;%@page contenttype="text/html" pageencoding="utf-8"%&gt;  

 2 &lt;%@taglib uri="/struts-tags" prefix="s" %&gt;  

 3 &lt;!doctype html&gt;  

 4 &lt;html&gt;  

 5     &lt;head&gt;  

 6         &lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;  

 7         &lt;title&gt;jsp page&lt;/title&gt;  

 8     &lt;/head&gt;  

 9     &lt;body&gt;  

10         &lt;!-- 本jsp将示範在jsp中對值棧的使用 --&gt;  

11         &lt;!-- 本jsp為myaction對應的jsp --&gt;  

12   

13         &lt;!-- 由于action已經被存入的值棧,是以可以調用action的屬性  --&gt;  

14         &lt;!-- 使用下面的标簽和表達式來顯示myaction的message屬性 --&gt;  

15         &lt;s:property value="message"/&gt;  

16         &lt;!-- 使用下面的标簽和表達式來調用action的gettext(...)方法,參數為myaction的message屬性  --&gt;  

17         &lt;s:property value="gettext(message)"/&gt;  

18         &lt;!-- 預設情況下傳遞給cssclass的是字元串常量。可以使用“%{}”來啟用ognl,這樣,傳遞給cssclass的就不是字元串常量"message",而是上面所說的message的值  --&gt;  

19         &lt;s:div cssclass="%{message}"/&gt;  

20         &lt;!-- 使用s:push标簽來将對象放入值棧,如下 --&gt;  

21         &lt;s:push value="person"&gt;  

22             &lt;!-- 在此s:push标簽内,值棧的棧頂元素為person,棧頂第二層為action   

23             &lt;!-- 在标簽内直接調用person的屬性(而不是action的屬性),如下 --&gt;  

24             &lt;s:property value="name"/&gt;  

25             &lt;!-- 在标簽内也可以使用myaction的屬性,值棧會依次先查找person是否有該屬性,由于沒找到,會再myaction中再查找,如下  --&gt;  

26             &lt;s:property value="message"/&gt;  

27             &lt;!-- 可以使用“[0]”、“[1]”等指定從值棧的哪一層開始查找  --&gt;  

28             &lt;!-- 此時,使用“[0]”表示從person開始查找,當然還是找不到,值棧就接着到myaction中查找,如下  --&gt;  

29             &lt;s:property value="[0].message"/&gt;  

30             &lt;!-- 此時,使用“[1]”将從myaction開始查找,而跳過了person,如下  --&gt;  

31             &lt;s:property value="[1].message"/&gt;  

32             &lt;!-- 想要通路棧頂元素本身使用關鍵字“top”,比如,下面的top就代表棧頂的person,如下 --&gt;  

33             &lt;s:property value="top"/&gt;  

34             &lt;!-- 或者如下  --&gt;  

35             &lt;s:property value="[0].top"/&gt;  

36             &lt;!-- 想要通路myaction本身的話使用如下寫法  --&gt;  

37             &lt;s:property value="[1].top"/&gt;  

38         &lt;/s:push&gt;  

39         &lt;!-- 此時person已被移出值棧,再使用如下标簽和表達式将無法得到值 --&gt;  

40         &lt;!--&lt;s:property value="name"/&gt;--&gt;  

41         &lt;!-- iterator标簽會把list的每個元素依次存入棧頂,如下 --&gt;  

42         &lt;s:iterator value="personlist"&gt;  

43             &lt;!-- 獲得list每個元素中的name屬性  --&gt;  

44             &lt;s:property value="name"/&gt;  

45         &lt;/s:iterator&gt;  

46     &lt;/body&gt;  

47 &lt;/html&gt;  

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

無論如何,actioncontext都是用來存放資料的。struts2本身會在其中放入不少資料,而使用者也可以放入自己想要的資料。actioncontext本身的資料結構是映射結構,即一個map,用key來映射value。是以使用者完全可以像使用map一樣來使用它,或者直接使用action.getcontextmap()方法來對map進行操作。

struts2本身在其中放入的資料有actioninvocation、application(即servletcontext)、conversionerrors、locale、action的name、request的參數、http的session以及值棧等。完整的清單請參考它的javadoc(本文附錄有對它包含内容的讨論)。

由于actioncontext的線程唯一和靜态方法就能獲得的特性,使得在非action類中可以直接獲得它,而不需要等待action傳入或注入。需要注意的是,它僅在由于request而建立的線程中有效(因為request時才建立對應的actioncontext),而在伺服器啟動的線程中(比如fliter的init方法)無效。由于在非action類中通路其的友善性,actioncontext也可以用來在非action類中向jsp傳遞資料(因為jsp也能很友善的通路它)。

相同點:它們都是在一次http請求的範圍内使用的,即它們的生命周期都是一次請求。

不同點:值棧是棧的結構,actioncontext是映射(map)的結構。

聯系:valuestack.getcontext()方法得到的map其實就是actioncontext的map。檢視struts2的源代碼可知(struts2.3.1.2的org.apache.struts2.dispatcher.ng.prepareoperations的第79行,createactioncontext方法),在建立actioncontext時,就是把valuestack.getcontext()作為actioncontext的構造函數的參數。是以,valuestack和actioncontext本質上可以互相獲得。

注意:在一些文檔中,會出現把對象存入“stack's context”的字樣,其實就是把值存入了actioncontext。是以在閱讀這些文檔時,要看清楚,到底是放入了棧結構(即值棧),還是映射結構(值棧的context,即actioncontext)。

在自定義的攔截器中:使用actioninvocation.getinvocationcontext()或者使用actioncontext.getcontext()。

在action類中:讓攔截器注入或者使用actioncontext.getcontext()。

在非action類中:讓action類傳遞參數、使用注入機制注入或者使用actioncontext.getcontext()。注意:隻有運作在request線程中的代碼才能調用actioncontext.getcontext(),否則傳回的是null。

在jsp中:一般不需要獲得actioncontext本身。

在攔截器、action類、非action類等java類中:使用actioncontext.put(object key, object value)方法。

在攔截器、action類、非action類等java類中:使用actioncontext.get(object key)方法。

總之,在jsp中使用actioncontext一方面是由于它是映射結構,另一方面是能讀取action的一些配置。當你需要為許多action提供通用的值的話,可以讓每個action都提供getxxx()方法,但更好的方法是在攔截器或jsp模闆中把這些通用的值存放到actioncontext中(因為攔截器或jsp模闆往往通用于多個action)。

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 本類将示範攔截器中對actioncontext的操作   

 5         // 獲得actioncontext   

 6         actioncontext actioncontext = invocation.getinvocationcontext();   

 9         actioncontext.put("person", person);   

10         // 擷取值   

11         object value = actioncontext.get("person");   

12         // 擷取httpservletrequest   

13         httpservletrequest request = (httpservletrequest) actioncontext.get(strutsstatics.http_request);   

14         // 擷取request的map,即httpservletrequest.getattribute(...)和httpservletrequest.setattribute(...)所操作的值  

15         map requestmap = (map) actioncontext.get("request");   

16         // 其他代碼   

17         // ......   

18         return invocation.invoke();   

19     }   

20 }  

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 本類将示範在action中對actioncontext進行操作   

 7         actioncontext actioncontext = actioncontext.getcontext();   

10         actioncontext.put("person", person);   

11         // 擷取值   

12         object object = actioncontext.get("person");   

17 }  

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 &lt;!doctype html&gt;  

 2 &lt;html&gt;  

 3     &lt;head&gt;  

 4         &lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;  

 5         &lt;title&gt;jsp page&lt;/title&gt;  

 6     &lt;/head&gt;  

 7     &lt;body&gt;  

 8         &lt;!-- 本jsp将示範在jsp中對actioncontext的使用 --&gt;  

 9         &lt;!-- 本jsp為myaction對應的jsp --&gt;  

10   

11         &lt;!-- 由于action中已經向actioncontext存入了key為"person"的值,是以可以使用“#person”來擷取它,如下  --&gt;  

12         &lt;s:property value="#person"/&gt;  

13         &lt;!-- 獲得person的name屬性,如下  --&gt;  

14         &lt;s:property value="#person.name"/&gt;  

15         &lt;!-- 獲得struts2在actioncontext中存入的值,比如request的map,如下  --&gt;  

16         &lt;s:property value="#request"/&gt;  

17         &lt;!-- 獲得struts2在actioncontext中存入的值,比如session的map,如下  --&gt;  

18         &lt;s:property value="#session"/&gt;  

19         &lt;!-- 獲得struts2在actioncontext中存入的值,request請求傳遞的get參數或post參數的map,如下  --&gt;  

20         &lt;s:property value="#parameters"/&gt;  

21            

22         &lt;!-- 以下示範在jsp中把值存入actioncontext中  --&gt;  

23         &lt;!-- 存入一個字元串"myname",key為"mykey",如下 --&gt;  

24         &lt;s:set value="%{'myname'}" var="mykey"/&gt;  

25         &lt;!-- 使用s:bean标簽來建立一個對象,并把它存入actioncontext中,key為myobject,如下  --&gt;  

26         &lt;s:bean name="com.example.person" var="myobject"/&gt;  

27         &lt;!-- 之後就可以用“#”來讀取它們,如下  --&gt;  

28         &lt;s:property value="#mykey"/&gt;  

29         &lt;s:property value="#myobject"/&gt;  

30     &lt;/body&gt;  

31 &lt;/html&gt;  

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

struts2中提供了兩種對request的操作:一種是web伺服器提供的httpservletrequest類,這和傳統java web項目中的操作request的方式相同;另一種是一個“request的map”,即封裝了httpservletrequest的attributes的映射類,操作該map相當于操作httpservletrequest的attributes。之是以提供了map的操作方式,一是友善操作,二是能友善使用ognl在jsp标簽中讀取request。無論如何,這兩個request是互通的。至于request的生命周期等概念,與其他的java

web項目沒有差別,本文不再詳述。

雖然兩者是互通的,但就讀取request的attributes而言,使用request的map要友善許多,并且不會暴露不必要的接口。當然,httpservletrequest有一些request的map沒有的方法,使用這些方法時當然還是要用前者。

兩者都是map,兩者的生命周期都是一個請求。

傳統的java web項目中,往往是通過request的attributes來向jsp傳遞值的:先在servlet裡setattribute(),然後在jsp裡getattribute()。當然在struts2的項目中,你仍然可以使用這個方法,然而抛棄了struts2提供的傳遞功能是得不償失的。雖然筆者沒有找到官方文檔說一定要用actioncontext替換request的map,也沒有發現程式中有能獲得actioncontext卻獲得不了request的map的地方,但在struts2架構下,操作actioncontext要比操作request的map更加友善。是以,筆者建議:盡量使用actioncontext而不是request的map來傳遞值。

request的map有時候會包含其他架構設定的值,比如spring架構。擷取這些值的時候就需要用request的map了,因為actioncontext裡沒有。

通過actioncontext可以獲得httpservletrequest類:“httpservletrequest request = (httpservletrequest) actioncontext.get(strutsstatics.http_request);”。

通過actioncontext也可以獲得request的map:“map requestmap = (map) actioncontext.get("request");”。是以,在jsp标簽中,使用表達式“#request”就可以獲得request的map的資料。

如果已經有actioncontext,則使用“actioncontext.get(strutsstatics.http_request)”來獲得httpservletrequest。

在自定義的攔截器中,先獲得actioncontext,再通過actioncontext來獲得。

在jsp中,一般不需要獲得httpservletrequest。

如果已經有actioncontext,則使用“actioncontext.get("request")”來獲得。

在自定義的攔截器中,先獲得 actioncontext,再通過actioncontext來獲得。

在action中,先獲得actioncontext,再通過actioncontext來獲得。或者讓action實作requestaware接口,并使用servletconfiginterceptor攔截器,這樣這個攔截器就會注入map request。

在jsp中,用“#request”來獲得request的map,用“#request.key”或者“#request['key']”來讀取map中的值。

總之,request仍然符合java web網站的一般規律。不過筆者建議使用者應盡量避免用request傳值。

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 本類将示範攔截器中對httpservletrequest和request的map的操作   

 7         // 獲得httpservletrequest   

 8         httpservletrequest httpservletrequest=(httpservletrequest)actioncontext.get(strutsstatics.http_request);   

 9         // 獲得request的map   

10         map requestmap = (map) actioncontext.get("request");   

11         // 建立一個類作為執行個體   

12         person person = new person();   

13         // 以下兩行的語句作用相同   

14         httpservletrequest.setattribute("person", person);   

15         requestmap.put("person", person);   

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 本類将示範在action中對httpservletrequest和request的map進行操作(靜态方法獲得actioncontext)  

 6         // 獲得actioncontext   

 8         // 獲得httpservletrequest   

 9         httpservletrequest httpservletrequest=(httpservletrequest)actioncontext.get(strutsstatics.http_request);   

10         // 獲得request的map   

11         map requestmap = (map) actioncontext.get("request");   

12         // 建立一個類作為執行個體   

13         person person = new person();   

14         // 以下兩行的語句作用相同   

15         httpservletrequest.setattribute("person", person);   

16         requestmap.put("person", person);   

17         // 其他代碼   

18         // ......   

19         return success;   

20     }   

21 }  

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 本類将示範在action中使用servletrequestaware獲得httpservletrequest(注意:要使用servletconfiginterceptor攔截器)  

 2 public class myaction extends actionsupport implements servletrequestaware {   

 4     private httpservletrequest request;   

 5        

 6     //此方法是接口servletrequestaware的方法   

 7     public void setservletrequest(httpservletrequest request) {   

 8         this.request = request;   

 9     }   

11     @override  

12     public string execute() throws exception {   

13         // httpservletrequest已在該類的字段中準備好,可直接使用  

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 &lt;!doctype html&gt;   

 2 &lt;html&gt;   

 3     &lt;head&gt;   

 4         &lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;   

 5         &lt;title&gt;jsp page&lt;/title&gt;   

 6     &lt;/head&gt;   

 7     &lt;body&gt;   

 8         &lt;!-- 本jsp将示範在jsp中對request的map的使用 --&gt;   

 9         &lt;!-- 本jsp為myaction對應的jsp --&gt;   

11         &lt;!-- request的map是struts2自動在actioncontext中存入的值(key為request),是以使用“#”來通路actioncontext,從中讀取request  --&gt;   

12         &lt;s:property value="#request"/&gt;   

13         &lt;!-- 以下兩行均是通路request的map中key為“name”的值  --&gt;   

14         &lt;s:property value="#request.name"/&gt;   

15         &lt;s:property value="#request['name']"/&gt;   

16     &lt;/body&gt;   

17 &lt;/html&gt;  

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 本類将示範在action中使用servletrequestaware獲得request的map(注意:要使用servletconfiginterceptor攔截器)  

 2 public class myaction extends actionsupport implements requestaware {   

 4     map&lt;string, object&gt; request;   

 5   

 6     // 該方法是接口requestaware的方法   

 7     public void setrequest(map&lt;string, object&gt; request) {   

13         // request的map已在該類的字段中準備好,可直接使用   

parameters為get或post等請求時浏覽器向伺服器傳遞而來的參數。在傳統的java web項目中,使用httpservletrequest.getparameter()等方法來擷取參數,并且可以直接使用httpservletrequest.getparametermap()來獲得一個封裝了參數的map。而在struts2中,struts2直接把上述map存放到了actioncontext中,key為“parameters”。另外,actioncontext還直接提供了actioncontext.getparameters()方法來獲得這個map。是以,在struts2的各個部件中操作parameters的方法和操作request的map的方法十分相似,本段不再詳述。

傳統java web項目中的session是我們都熟悉的,我們用它來記錄一個使用者的會話狀态。struts2把httpservletsession封裝到了一個map中,即“session的map”,這類似對request的處理。然而為了節省系統資源,我們在不需要session的時候不會建立session。可能正是因為這個緣故,struts2中沒有把httpservletsession放入actioncontext中,如果你的程式需要使用httpservletsession,應該先獲得httpservletrequest,然後使用getsession()或getsession(boolean

b)來獲得它,同時決定是否需要建立session。對于session的map,struts2仍然把它放入了actioncontext中(key為"session"),但是不要擔心,這個map的機制使得隻有put新值時才會建立session。總之,struts2中對httpservletsession的操作要先通過httpservletrequest來獲得它,而對session的map的操作與對request的map的操作如出一轍,本段不再詳述。

傳統的java web項目中,servletcontext用來存放全局變量,每個java虛拟機每個web項目隻有一個servletcontext。這個servletcontext是由web伺服器建立的,來保證它的唯一性。servletcontext有一些方法能操作它的attributes,這些操作方法和操作一個map類似。于是,struts2又來封裝了:它把servletcontext的attributes封裝到了一個map中,即“application的map”,并且也放入的actioncontext中(key為application),是以,對application的map的操作就如果對request的map操作,本段不再詳述。

至于對servletcontext的操作,與httpservletrequest的操作類似:struts2将servletcontext放到了 actioncontext中,并且servletconfiginterceptor提供了對servletcontext的注入接口servletcontextaware。是以,本段不再詳述。

注意:在ognl表達式中使用“#application”可以得到application的map,而不是servletcontext。然而在jsp嵌入的java代碼中(比如“&lt;% application.getattribute(""); %&gt;”),application為servletcontext,而不是map。

用一張表格來總結:

變量

從actioncontext中獲得

生命周期

用ongl來讀取值

actioncontext類

靜态方法actioncontext. getcontext()

一次http請求

使用“#”加上key,如“#name”

無法注入

valuestack類

actioncontext. getvaluestack()

直接填寫來通路棧中對象的方法,或者使用top來直接獲得棧中對象

httpservletrequest類

actioncontext. get( strutsstatics. http_request)

無友善的方法

request的map

actioncontext. get("request")

使用“#request”再加上key,如“#request.name”或者“#request['name']”

parameters的map

actioncontext. get( "parameters")

使用“# parameters”再加上key,如“#parameters .name”或者“#parameters ['name']”

httpservletsession類

無(需通過httpservletrequest來獲得)

一次http session會話

session的map

actioncontext. get("session")

每次請求建立,但在一次http session會話中資料都是一樣的

使用“#session”再加上key,如“# session.name”或者“#session ['name']”

servletcontext類

actioncontext. get( strutsstatics. servlet_context)

網站項目啟動後一直存在且唯一

application的map

actioncontext.get( "application")

每次請求時建立,但其中的資料是網站項目啟動後一直存在且共享

使用“# application”再加上key,如“#application .name”或者“#application ['name']”

key

key的聲明處

value的類型

value.tostring()

com. opensymphony. xwork2. dispatcher.

httpservletrequest

strutsstatics. http_request

org. apache. struts2. dispatcher. strutsrequestwrapper

org. apache. struts2. dispatcher. strutsrequestwrapper @10984e0

application

org. apache. struts2. dispatcher. applicationmap

com. opensymphony. xwork2. actioncontext. locale

actioncontext. locale

java. util. locale

zh_cn

com. opensymphony. xwork2. dispatcher. httpservletresponse

strutsstatics. http_response

org. apache. catalina. connector. responsefacade

org. apache. catalina. connector. responsefacade @14ecfe8

xwork. nullhandler.

createnullobjects

boolean

false

com. opensymphony. xwork2. actioncontext. name

actioncontext. action_name

string

index

com.opensymphony. xwork2.actioncontext.

conversionerrors

actioncontext.

conversion_errors

java. util. hashmap

{}

com. opensymphony. xwork2. actioncontext. application

actioncontext. application

attr

org. apache. struts2. util. attributemap

org. apache. struts2. util. attributemap @133a2a8

com. opensymphony. xwork2. actioncontext. container

actioncontext. container

com. opensymphony. xwork2. inject. containerimpl

com. opensymphony. xwork2. inject. containerimpl @fc02c8

com. opensymphony. xwork2. dispatcher. servletcontext

strutsstatics. servlet_context

org. apache. catalina. core. applicationcontextfacade

org. apache. catalina. core. applicationcontextfacade @11ad78c

com. opensymphony. xwork2. actioncontext. session

actioncontext. session

org.apache.struts2. dispatcher.sessionmap

actioninvocation

actioncontext. action_invocation

com. opensymphony. xwork2. defaultactioninvocation

com. opensymphony. xwork2. defaultactioninvocation @13d4497

xwork. methodaccessor. denymethodexecution

筆者很懶,沒有找

report. conversion. errors

session

org. apache. struts2. dispatcher. sessionmap

com. opensymphony. xwork2. util. valuestack. valuestack

valuestack.value_stack

com. opensymphony. xwork2. ognl. ognlvaluestack

com. opensymphony. xwork2. ognl. ognlvaluestack @16237fd

request

org. apache. struts2. dispatcher. requestmap

action

com. example. myaction

struts. actionmapping

org. apache. struts2. dispatcher. mapper. actionmapping

org. apache. struts2. dispatcher. mapper. actionmapping @892cc5

parameters

com. opensymphony. xwork2. actioncontext. parameters

actioncontext.parameters

java. util. treemap

注意:該表格為了排版在某些地方加了空格。

可以看出,有些相同的對象被以不同的key多次設定到actioncontext中。如果想看看建立actioncontext的源代碼,請看org.apache.struts2.dispatcher.dispatcher的serviceaction方法和兩個createcontextmap方法。

<a target="_blank"></a>

經試驗并檢視相關源代碼後發現,在使用&lt;s:property value="..."/&gt;時,該标簽的執行類會先根據value中表達式到值棧中執行表達式來查找值。如果在值棧中找到值,就傳回該值;如果沒有找到,則把該表達式作為actioncontext的key,到actioncontext中去找值。比如&lt;s:property value="request"/&gt;也會得到actioncontext中的request,等價于&lt;s:property value="#request"/&gt;。但是,由于标簽的執行類會認為該值時string類型的,并且會直接進行類型轉換。于是,如果直接使用&lt;s:property

value="request"/&gt;的話其實會讓頁面抛出異常:request類型不能轉換成string類型。是以,隻能用如果不帶#的話隻能成功讀取actioncontext中string類型的值。這種機制使得某些時候棧頂的屬性可以覆寫actioncontext中的key,或許你正需要它。然而,鑒于這種機制的不确定性,筆者建議通路actioncontext中的資料一定要帶上“#”,可以免去一些麻煩。

關于這種轉型異常,筆者認為是struts2的bug,源代碼如下,當“value = getvalue(expr, astype);”時,是考慮了astype的,但從context中讀取時“value = findincontext(expr);”,就沒有考慮astype,并且沒有在其他地方看到類型檢查操作:

在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等

 1 // 本代碼截取struts2.3.1.2版本com.opensymphony.xwork2.ognl.ognlvaluestack類的第340行-352行   

 2     private object tryfindvalue(string expr, class astype) throws ognlexception {  

 3         object value = null;  

 4         try {  

 5             expr = lookupforoverrides(expr);  

 6             value = getvalue(expr, astype);  

 7             if (value == null) {  

 8                 value = findincontext(expr);  

 9             }  

10         } finally {  

11             context.remove(throw_exception_on_failure);  

12         }  

13         return value;  

14     }