ValueStack 与 OGNL
值栈的含义正如它的名字所表示的那样——对象所组成的栈。OGNL的全称是Object Graph Navigational Language(对象图导航语言),提供了访问值栈中对象的统一方式。
值栈中的对象构成及其排列顺序如下所示:
1. 临时对象——在执行过程中,临时对象被创建出来并放到了值栈中。举个例子来说,像JSP标签所遍历的对象容器中,当前访问到的值就是临时对象
2. 模型对象——如果模型对象正在使用,那么会放在值栈中action的上面
3. Action对象——正在被执行的action
4. 上下文中固定名称的对象(Named Objects)——这些对象包括有#application, #session, #request, #attr 和 #parameters,以及相应的servlet作用域
struts2中的OGNL上下文
struts2对OGNL上下文的概念又做了进一步扩充,在struts2中,OGNL上下文通常如下所示:
|--request
|
|--application
|
context map---|--OgnlValueStack(root) [ user, action, OgnlUtil, ... ]
|
|--session
|
|--attr
|
|--parameters
代码示例
public interface User {
public String getName();
public Date getRegisterDate();
public Customer getCustomer();
}
public interface Customer {
public String getId();
public String getName();
public boolean isVip();
}
public interface EntCustomer extends Customer {
public String getTrustId(); // 组织机构代码证号
}
那么在上面的环境中,我们可以有如下的OGNL表达式:
Java代码
#user.name // 取用户的姓名
#user.age // 取用户年龄
#user.birthday // 取用户生日
#user.customer.name // 取用户所属客户的名称
#request.parameters // 取请求参数
请注意上面表达式中的"#user"和"#request"的用法,"#"表示访问环境/上下文中的对象。
现在可以很方便地访问环境中的对象了,那么如果你比较懒惰的话(记住:在程序员群体,懒惰是褒义词!),你是否觉得访问用户的姓名,年龄,生日,等等其它属性如果全部要使用"#user"来访问会不会太麻烦了呢?OK,ONGL的设计者早就考虑了这个问题,我们可以指定user为环境中的特权对象,访问该对象可以不需要使用#user的方式,如下所示代码与上面的完全等价,当然,前提是要预先指定user为特权对象:
name // 取用户的姓名
age // 取用户年龄
birthday // 取用户生日
customer.name // 取用户所属客户的名称
#request.parameters // 取请求参数
我们上面所说的"特权对象"在OGNL中称为"根对象"(root)
我们可以使用"#requet"访问HttpServletRequest对象, "#session"访问HttpSession对象,但请注意"根对象"是什么?是ValueStack!
那么ValueStack是什么?值栈。也就是一组对象的堆栈。也就是说,在struts2中,根对象不是我们通常的一个对象,而是一组对象。我们可以push新的对象到值栈中,也可以弹出值栈的栈顶对象。如上图所示,假设我们将user对象push到值栈中,那么如下的表达式将与之前我们见过的表达式一样,具有相同的结果.
也就是说,我们使用name这个表达式的时候,ONGL会取"根对象"的name属性,但现在根对象是ValueStack!那么访问ValueStack的name属性意味着什么呢?这意味着: ValueStack会先查看栈顶元素是否有name属性,如果有就返回该属性值,否则取出栈顶下的元素,继续查看,直到栈底为止。
其实,我们可以ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");直接去访问.
//获取封装输出信息的ValueStack对象
ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");
//调用ValueStack的fineValue方法获取Action中的books属性值
String[] books = (String[])vs.findValue("books");
<%@taglib prefix="s" uri="/struts-tags"%>
通过s:iterator迭代出value
<table border="1" width="360">
<caption>
作者李刚的图书
</caption>
<!-- 迭代输出ValueStack中的books对象,其中status是迭代的序号 -->
<s:iterator value="books" status="index">
<!-- 判断序号是否为奇数 -->
<s:if test="#index.odd == true">
<tr style="background-color: #cccccc">
</s:if>
<!-- 判断迭代元素的序号是否不为偶数 -->
<s:else>
<tr>
</s:else>
<td>
书名:
</td>
<td>
<s:property />
</td>
</tr>
</s:iterator>
</table>