值栈(Value Stack)是Struts 2框架的核心概念。所有核心组件都以某种方式与之进行交互,它提供对上下文信息和执行环境中元素的访问机制。
正如它名字显示的那样,值栈在它底层实现了一个栈。但是,值栈与传统栈的实现有所不同。第一个不同之处在于值栈的内容由如下4个层级组成。
临时对象(temporary object):这些对象在请求处理过程中需要临时保存,比如集合中当前正在被迭代的元素。
模型对象(model object):当action实现了ModelDriven接口时,模型对象就会被存放在栈中正在被执行的action前面。如果action没有实现该接口,这个级别内容将不存在。
action对象(action object):此对象是当前正在执行的action。
命名对象(named object):任何对象都可以被赋予一个标识符而成为命名对象。命名对象可以由开发人员创建,除此之外还包括#application、 #session、#request、#attr和#parameters等Struts 2提供的对象,上述对象与HTTP同等作用域内的对象集合相对应。
另一个不同之处在于栈的使用方式。栈的传统使用方式是:将对象压入栈内,然后需要使用时就弹出对象。对于值栈,则是通过那些使用OGNL (Object Graph Navigational Language,对象图导航语言)语法所编写的特定表达式来查找,或者是在该表达式之上求值。
与诸如JSTL(JSP Standard Tag Library,JSP标准标签库)或者MVEL(MVFLEX Expression Language,MVFLEX表达式语言)等其他表达式语言一样,OGNL提供导航对象图机制,该机制使用圆点符号和表达式求值,以及调用被检索对象的方法等。表3-3列出了一些在OGNL中可能使用到的具体例子。
表3-3 OGNL表达式例子
OGNL示例 | 描 述 |
address.postcode | 调用getAddress().getPostcode()时返回的值。这种存取模式就是圆点符号,通过这个方式,用句点将每个属性名分开以提供对象图内部的导航机制 |
#session['user'] | 从HTTP会话中获得用户对象 |
!required | 如果调用isRequired()方法的返回值为false,则本表达式返回true |
required && result.size()>1 | 先调用isRequired()方法,然后执行result集合的元素个数是否大于1的逻辑运算,然后返回两个调用结果进行逻辑“与”运算后的结果 |
hasActionErrors() | 返回hasActionErrors()方法的调用结果 |
[2].id | 调用值栈里第3个元素(栈最上面的索引是0)的getId()方法。当你知道值栈里的准确内容时,该方法非常有用。使用该方法寻找属性对象比通过索引在值栈中查找对象更加有效和准确 |
top | 返回值栈最顶层对象 |
results.{name} | 调用结果集合中所有元素的getName()方法,所有方法返回值构成一个返回集合。这种操作称为投影(projection) |
role in {'admin','user'} role not in {'admin','user'} | 确定getRole()方法返回的值是否在'admin'和'user'构成的集合中 |
@com.static.Constants@getRoles() | 调用Constants类的静态方法getRoles(),返回其值 |
@com.static.Constants@USER_NAME | 返回Constants类的静态属性USER_NAME的值 |
说明 尽管OGNL是专为Struts 2开发的表达式语言,但是正在进行一些方面的工作以消除Struts 2对OGNL的依赖,从而允许Struts 2使用其他不同的表达式语言。更多关于OGNL的信息请查看http://www.ognl.org。
查询也与栈没有多大关联。对于值栈,OGNL表达式会在每个层级测试,层级测试顺序按照本节开头列举的顺序进行。如果表达式能够求值,则返回结果。否则,就会测试下面一个层级。如果所有层级都测试了,仍然没有求出结果,那么将返回null值。
在我们开发应用的过程中将讨论更多的OGNL的特性。