原文地址:http://blog.csdn.net/wyply115/article/details/8257140
一、OGNL表達式
1.ognl是struts2中使用的一種表達式語言,可用于jsp的標簽庫中,以方便訪問各種對象的屬性。它用于把界面的參數傳遞到Action中(并進行類型轉換),它還可以用于struts2的配置文件中。
2. Root對象。
OGNL稱為對象圖導航語言,所謂對象圖,即以任意一個對象為根,通過OGNL可以訪問與這個對象關聯的其它對象,例如:
public class User{ PRivate String username; private Group group; //省略setter,getter方法 } public class Group{ private String name; private Organization org; //省略setter,getter方法 } public class Organization{ private String orgId; //省略setter,getter方法 }
以上三個類,描述了通過User對象可以導航到Group對象,進而導航到Organization對象。以User為根,通過基本的getters方法,可以訪問到此根對象的其它關聯對象.【對象圖的導航,必須通過getters方法導航】。
注意:
* 導航的目的,就是為了獲取某個對象的值或設置某個對象的值或調用某個對象的方法.
* OGNL表達式語言的真正目的,是為了在那些不能寫java代碼的地方執行java代碼,或者是為了更方便的執行java代碼.
3.Context對象
* 在OGNL表達式中,有可能需要訪問到多個毫不相干的對象,這時候,我們需要給OGNL傳遞一個Map類型的對象,把表達式中需要用到的對象放到Map中即可.而這個Map對象稱為Context。
* 要在表達式訪問到context中的對象,需要使用"#對象名稱"的語法規則
* 存在context的主要原因就是在OGNL中,不支持多個root對象,而如果需要在表達式中訪問多個毫不相關的對象時,只能通過一個Map來把這些對象統一傳遞給OGNL。
二、ValueStack
1.ValueStack是一個接口,在struts2中使用OGNL(Object-Graph Navigation Language)表達式實際上是使用實現了ValueStack接口的類OgnlValueStack.它ValueStack的默認實現類.
2.ValueStack貫穿整個action的生命周期,每一個action實例都擁有一個ValueStack對象,其中保存了當前action對象和其他相關對象.
3.struts2把ValueStack對象保存在名為:struts.valueStack的request域中.即ValueStack作用域為request.當action創建的時候,ValueStack就創建了,action被銷毀的時候,ValueStack就銷毀了
4.ValueStack中的數據分兩部分存放:root(棧結構,CompoundRoot)和context(map形式,OgnlContext)
(1)
* 其中的root對象是CompoundRoot,CompoundRoot繼承了ArrayList,提供了額外的方法:push(),和pop()方法,用來對root對象中所包含的數據進行存取.正是由于這兩個方法,CompoundRoot變成了一個棧結構.
* struts2中,一個請求在最終到達Action的方法之前,Action對象本身會被壓入ValueStack(實際上就是放到ValueStack 的CompoundRoot中),所以action對象是CompoundRoot中的一個元素.
(2)
* 其中的context對象是OgnlContext,它實現了map接口,在valuestack的默認實現類中,即OgnlValueStack類中,調用ongl中的方法:Ognl.createDefaultContext(..)給context賦值,查看源代碼可知,此方法返回的是一個OgnlContext對象.
5.獲取ValueStack的三種方式
(1)ValueStack valueStack = ActionContext.getContext().getValueStack();
ActionContext為Action的上下文,其中有重要的6大對象valueStack,parameters,request,session,application,attr。而ognl表達式必須選擇AcitonContext中的一個對象作為根對象(root),默認為valueStack,因此訪問valueStack中的數據不加#,而如果要使用另外5個對象作為根對象,需要加#前綴。
?。?)ValueStack valueStack = ServletActionContext.getValueStack(ServletActionContext.getRequest());
ServletActionContext繼承了ActionContext,它與web容器耦合,可以獲取web容器的一些信息.
(3)ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
因為ValueStack被置于Request域中。
6.ValueStack內存結構圖
原博文圖涉及底層實現細節,該圖是我簡化后,原博文圖片(http://img.my.csdn.net/uploads/201212/04/1354620065_9013.png)
7.常用的存儲數據的方法
(1)向Map棧中存數據,即ValueStack中的context中存儲數據。
通過request, session等向map中存儲數據:
ServletActionContext.getRuquest().setAttribute("username","xxx") ;
ServletActionContext.getSession().put("pwd","123");
直接向Map棧中存放數據:
ActionContext.getContext().put("msg","hello") ;
(2)向對象棧中存數據,即ValueStack中的root(CompoundRoot)對象
* 先得到root,再把數據壓入到root中,這中方式是放入到棧底
ValueStack valueStack =ActionContext.getContext().getValueStack(); valueStack.getRoot().add(new Person());
* 先得到root,利用add(index,Object)把一個對象壓入到root中指定位置.
ValueStack valueStack =ActionContext.getContext().getValueStack(); valueStack.getRoot().add(0,new Person());//這里0,表示壓入棧頂.
* 存放一個map到對象棧中
ValueStack valueStack =ActionContext.getContext().getValueStack(); valueStack.set("msg","dude"); //先封裝成Map,在把Map放入到對象棧中,且放入棧頂.
* 利用valueStack的push方法把一個對象直接壓入棧頂
ValueStack valueStack =ActionContext.getContext().getValueStack();valueStack.push(new Person());
8.利用OGNL表達式取ValueStack中的數據
(1)<s:property />:取棧頂的元素.
(2)<s:iterator />:取棧頂的元素.
注意:此標簽的value屬性值無論來自對象棧還是Map棧,都可以不加#前綴(<s:select/>標簽也適用).
因為此標簽在迭代的時候,總是把當前正在迭代的元素放入到棧頂.
新聞熱點
疑難解答