7.1 值棧7.1.1 值棧是什么簡單的說:值棧是對應(yīng)每一個請求對象的輕量級的內(nèi)存數(shù)據(jù)中心,。 Struts2中一個很激動人心的特性就是引入了值棧,,在這里統(tǒng)一管理著數(shù)據(jù),供Action,、Result,、Interceptor等Struts2的其他部分使用,這樣一來,,數(shù)據(jù)被集中管理起來而不會凌亂,,大大方便了程序編寫,。 Struts2中關(guān)于值棧的另外一個很激動人心的特性就是:大多數(shù)情況下,你根本無需關(guān)心值棧,,你不用管它在哪里,,不用管它里面有什么,你只需要去獲取自己需要的數(shù)據(jù)就可以了,。也就是說,你可以隱式的使用值棧,。 當然,,如果編寫自定義的Result或攔截器等較復(fù)雜功能的時候,還是需要顯示訪問值棧的,,因此,,還是需要你掌握值棧的知識。 7.1.2 值棧能干什么簡單的說,,值棧能夠線程安全的為每個請求提供公共的數(shù)據(jù)存取服務(wù),。 當有請求到達的時候,Struts2會為每個請求創(chuàng)建一個新的值棧,,也就是說,,值棧和請求是一一對應(yīng)的,不同的請求,,值棧也不一樣,,而值棧封裝了一次請求所有需要操作的相關(guān)的數(shù)據(jù)。 正是因為值棧和請求的對應(yīng)關(guān)系,,因而值棧能保證線程安全的為每個請求提供公共的數(shù)據(jù)存取服務(wù),。 7.1.3 值棧有什么事實上,到現(xiàn)在為止,,我們一直在講“值?!保@種說法其實是不夠準確的,。為什么呢,?因為在Struts2中,值棧又有廣義和狹義之分: 1:狹義值棧 通常指的是實現(xiàn)com.opensymphony.xwork2.util.ValueStack接口的對象,,目前就是com.opensymphony.xwork2.ognl.OgnlValueStack對象,。 狹義值棧主要用來存取動態(tài)EL(表達式語言)運算需要的值和結(jié)果,當然OgnlValueStack對象主要是用來支持OGNL(對象圖導(dǎo)航語言)運算的,。 狹義值棧里面存放著一些OGNL可以存取訪問的數(shù)據(jù),,典型如: - Action的實例,這樣就可以通過OGNL來訪問Action實例中的屬性的值了
- OGNL表達式運算的值,,可以設(shè)置到值棧中,,可以主動訪問值棧對象,,強行設(shè)置
- OGNL表達式產(chǎn)生的中間變量,比如在后面使用Struts2的標簽的時候,,使用循環(huán)標簽,,自然會有循環(huán)的變量,這些都存放在值棧中
2:廣義值棧 通常指的是ActionContext對象,,ActionContext是Action運行的上下文,,每個ActionContext是一個基本的容器,包含著Action運行需要的數(shù)據(jù),,比如請求參數(shù),、會話等。 ActionContext是線程安全的,,每個線程有一個獨立的ActionContext,,這樣你就不用擔(dān)心值棧中值的線程安全問題了。 ActionContext里面存放有很多的值,,典型如: - Request的parameters:請求中的參數(shù),,要注意這里的數(shù)據(jù)是從請求對象里面拷貝出來的,因此這里數(shù)據(jù)的變化是不會影響到請求對象里面的參數(shù)的值的
- Request的Attribute:請求中的屬性,,這里其實就是個Map,,存放著請求對象的屬性數(shù)據(jù),這些數(shù)據(jù)和請求對象的Attribute是連動的
- Session的Attribute:會話中的屬性,,這里其實就是個Map,,存放著會話對象的屬性數(shù)據(jù),這些數(shù)據(jù)和會話對象的Attribute是連動的
- Application的Attribute:應(yīng)用中的屬性,,這里其實就是個Map,,存放著應(yīng)用對象的屬性數(shù)據(jù),這些數(shù)據(jù)和應(yīng)用對象的Attribute是連動的
- Value stack:也就是狹義值棧,,ActionContext以value stack作為被OGNL訪問的根,,簡單點說,OGNL在沒有特別指明的情況下,,訪問的就是value stack里面的數(shù)據(jù)
- attr:在所有的屬性范圍中獲取值,,依次搜索page、request,、session和application,。
前面已經(jīng)了解到Xwork與Web是無關(guān)的,因此Action不用去依賴于任何Web容器,,不用和Servlet 的API去交互,,但是Action需要能訪問到Web應(yīng)用的數(shù)據(jù),不僅僅是取得請求參數(shù)的值,,往往也需要在Action里直接獲取請求或會話的一些數(shù)據(jù),,對于這些數(shù)據(jù),,現(xiàn)在都可以通過ActionContext來獲取到。 3:關(guān)于廣義和狹義 你會看到,,在ActionContext里面其實是包含著狹義值棧的,,正是因為這個原因,再加上ActionContext還包含其他的數(shù)據(jù),,因此把ActionContext稱為廣義值棧,。 今后在說值棧的時候,沒有特別指明的情況下,,多數(shù)就是指的廣義值棧,,反正開發(fā)的時候都是說從值棧中獲取值。當然,,有一種情況除外,就是在頁面上使用OGNL的時候,,沒有特殊標識的情況下,,默認是從value statck中取值的。 7.1.4 ActionContext的基本使用前面學(xué)習(xí)了值棧的基本知識,,接下來,,看看在程序中具體如何使用值棧。 1:如何獲取 要獲取ActionContext有兩個基本的方法,,如果在不能獲取到ActionInvocation的地方,,可以直接使用ActionContext一個靜態(tài)的getContext方法,就可以訪問到當前的ActionContext了,,示例如下: java代碼:- ActionContext ctx = ActionContext.getContext();
如果在能獲取到ActionInvocation的地方,,比如在攔截器里面、自定義的Result里面等,,可以通過ActionInvocation來獲取到ActionContext,,示例如下: java代碼:- ActionContext ctx = actionInvocation.getInvocationContext();
2:獲取過后,如何使用 ActionContext主要的功能是用來存放數(shù)據(jù)的,,典型的方法如下: - get(String key):根據(jù)key從ActionContext當前的存儲空間里面獲取相應(yīng)的值
- put(String key, Object value):把值存儲在ActionContext的存儲空間里面
- Map<String,Object> getApplication():返回ServletContext中存儲的值
- Map<String,Object> getSession():返回HttpSession中存儲的值
- Map<String,Object> getContextMap():返回當前context存儲的值
- Map<String,Object> getParameters():返回HttpServletRequest對象里面存儲的,,客戶端提交的參數(shù)
- ValueStack getValueStack():獲取OGNL的值棧
對于getXXX的方法,都有對應(yīng)的setXXX方法,,這里就不去贅述了,,具體的請參看Struts2的API文檔。 3:應(yīng)用示例 可以參看上一章的兩個有用的攔截器這一小節(jié),,兩個攔截器都使用了ActionContext對象,,因此這里就不去贅述了。 7.1.5 ValueStack的基本使用在上一小節(jié)中,,看到了ValueStack被包含在ActionContext中,,ValueStack也是用來存儲對象的,,但是它主要是通過OGNL表達式來訪問,也就是說,,在Struts2里面主要是通過標簽來訪問的,。 ValueStack有一個特點,如果訪問的值棧里有多個對象,,且相同的屬性在多個對象中同時出現(xiàn),,則值棧會按照從棧頂?shù)綏5椎捻樞颍瑢ふ业谝粋€匹配的對象,。 1:如何獲取 直接由ActionContext對象的getValueStack()方法即可獲取 2:如何使用 ValueStack主要的功能也是用來存放數(shù)據(jù)的,,典型的方法如下: - Object findValue(String expr):根據(jù)表達式在value stack中,按照缺省的訪問順序去獲取表達式對應(yīng)的值
- void setValue(String expr, Object value):根據(jù)表達式,,按照缺省的訪問順序,,向value stack中設(shè)置值
- Object peek():獲取value stack中的頂層對象,不修改value stack對象
- Object pop():獲取value stack中的頂層對象,,并把這個對象從value stack中移走
- void push(Object o):把對象加入到value stack對象中,,并設(shè)置成為頂層對象
3:應(yīng)用示例 前面的示例中,歡迎頁面顯示的賬號,,是從登錄頁面填寫并傳遞到后臺的數(shù)據(jù),,假如現(xiàn)在想要修改在歡迎頁面顯示的賬號數(shù)據(jù),但是前面從登錄頁面填寫并傳遞到后臺的數(shù)據(jù)不需要變化,,那么該怎么實現(xiàn)呢,? 先來分析一下,要想修改result頁面顯示的值,,肯定需要在Result處理之前修改這個值,,否則等Result處理完成過后再改就沒有意義了。因此,,可以選用PreResultListener的技術(shù),,在里面把值修改好,然后再進行Result處理,。 另外一點,,在歡迎頁面是通過標簽來獲取賬號的數(shù)據(jù)并展示的,也就是說值的來源是value stack,,因此,,在PreResultListener里面要修改的就是value stack里面的值。 好了,,清楚該干什么過后,,來具體看看示例。 (1)先來實現(xiàn)PreResultListener,在里面修改value stack里面的值,,示例如下: java代碼:- public class MyPreResult implements PreResultListener{
- public void beforeResult(ActionInvocation actionInvocation, String result) {
- System.out.println("現(xiàn)在處理Result執(zhí)行前的功能,,result="+result);
- actionInvocation.getInvocationContext().getValueStack().setValue("account", "被修改了");
- }
- }
(2)實現(xiàn)了PreResultListener,還需要在運行之前注冊,,這里選擇在Action里面來注冊這個監(jiān)聽器,,示例如下: java代碼:- public class HelloWorldAction extends ActionSupport {
- private String account;
- private String password;
- private String submitFlag;
- public String execute() throws Exception {
- this.businessExecute();
- ActionContext c = ActionContext.getContext();
- MyPreResult pr = new MyPreResult();
- c.getActionInvocation().addPreResultListener(pr);
- return "toWelcome";
- }
-
-
-
- public void businessExecute(){
- System.out.println("用戶輸入的參數(shù)為==="+"account="+account+",password="+password+",submitFlag="+submitFlag);
- }
-
- }
(3)相應(yīng)的struts.xml就比較簡單了,示例如下: java代碼:- <package name="helloworld" extends="struts-default">
- <action name="helloworldAction" class="cn.javass.action.action.HelloWorldAction">
- <result name="toWelcome">/s2impl/welcome.jsp</result>
- </action>
- </package>
(4)登錄頁面沒有變動,,示例如下: java代碼:- <form action="/helloworld/helloworldAction.action" method="post">
- <input type="hidden" name="submitFlag" value="login"/>
- 賬號:<input type="text" name="account"><br>
- 密碼:<input type="password" name="password"><br>
- <input type="submit" value="提交">
- </form>
(5)再看看歡迎頁面,,也沒有變動,示例如下: java代碼:- <%@ taglib prefix="s" uri="/struts-tags"%>
- 歡迎賬號為<s:property value="account"/>的朋友來訪
(6)去運行測試看看,,歡迎頁面顯示出來的就應(yīng)該是修改過后的值了,,如下圖所示: 圖7.1 修改result數(shù)據(jù)的歡迎頁面 由于通常情況下,向value stack里面壓入值都是由Struts2去完成,,而訪問value stack多是通過標簽中的OGNL表達式,,因而直接使用ValueStack的機會并不是很多。
|