原文地址: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个对象作为根对象,需要加#前缀。
(2)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/>标签也适用).
因为此标签在迭代的时候,总是把当前正在迭代的元素放入到栈顶.
新闻热点
疑难解答