Struts2框架--------OGNL和valueStack

OGNL简介

OGNL的全称是ObjectGraph Navigation Language(对象图导航语言),它是一种强大的表达式语言,让你通过简单一致的表达式语法来读取和设置Java对象的属性值,调用对象的方法,遍历整个对象的结构图,实现字段类型转换等功能。
OGNL先在WebWork项目中得到应用,也是Struts 2框架视图默认的表达式语言,可以说,OGNL表达式是Struts2框架的特点之一。
OGNL表达式的计算都是围绕OGNL上下文来进行的,OGNL上下文实际上就是一个Map对象。
OGNL上下文可以包含一个或多个JavaBean对象,在这些对象中有一个是特殊的,这个对象就是上下文的 (root) 对象。如果在写表达式的时候,没有指定使用上下文中的哪一个对象,那么根对象将被假定为表达式所依据的对象

OGNL的优势
OGNL是将视图元素(例如textfield、combobox等)同模型对象绑定在一起的一种语言(数据绑定)。
使用OGNL的类型转换功能,会使类型转换变得更加简单(例如将一个字符串类型转换为一个整数类型)。
可以将Web页面元素同后台服务器业务对象对应起来。
比JSTL(JSP标准标签库)表达更加丰富

OGNL基本语法
基本的OGNL语法是十分简单的,当然OGNL支持丰富的表达式。例如有一个man对象,该对象有一个name属性,那么使用OGNL来获得该name属性可以使用如下表达式:
–man.name
OGNL表达式的基础单元称为导航链,简称为链。一个最简单的链由如下部分组成。
 —  属性名称:如上述示例中的name。
 —  方法调用:hashCode()返回当前对象的hashcode。
 —  数组元素:listeners[0]返回当前对象的监听器列表中第     一个元素。
Root(根对象):所谓对象图,即以任意一个对象为根,通过OGNL可以访问与这个对象关联的其它对象,该对象就称为根对象(root)

OGNL基础语法—导航链
OGNL表达式基于OGNL上下文中的当前对象,一个“链”将使用上一个“链”的处理结果,开发者可以任意扩展该链的长度,OGNL没有限制。

  例如,一个OGNL表达式如下:

 user.profile.address[0].detailAddr 
该表达式将按照如下步骤求值。
(1)获得OGNL Context中根对象(root对象)的user对象。
(2)调用getProfile()方法,返回一个Profile类型对象。
(3)获得该Profile对象的第一个地址属性对象。
(4)获得该Address对象的detailAddr属性


Struts 2的OGNL
OGNL是Struts 2框架的默认表达式语言,增强了Struts 2的数据访问能力,同时简化了代码。
Struts 2中的OGNL Context实现者为ActionContext
当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action 。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。

Struts2中的OGNL上下文
struts2对OGNL上下文的概念又做了进一步扩充,在struts2中,OGNL上下文通常如下所示:

                 |-- application
                  |
                 |-- session
                  |

 context map---|--OgnlValueStack(root) [action,... ]
                  |
                 |-- request
                  |
                 |--parameters

                   |
                 |-- attr   

            在struts2中,根对象不是我们通常的一个对象,可以是一组对象。我们可以push新的对象到值栈中(压栈),也可以弹出值栈的栈顶对象(pop出栈)。


ValueStack实际上就是对OGNL的封装,OGNL主要的功能就是赋值与取值,Struts2正是通过ValueStack来进行赋值与取值的!

Struts2 值栈(valueStack)
使用OGNL是非常简单的,如果要访问的对象不是根对象,则需要使用命名空间,用“#”来标识,如“#request”;如果访问一个根对象,则不用指定命名空间,可以直接访问根对象的属性。
在Struts 2框架中, Struts2将OGNL上下文设置为Struts2中的ActionContext,并将值栈设为OGNL的根对象。
值栈。也就是一组对象的堆栈。也就是说,在struts2中,根对象不是我们通常的一个对象,而是一组对象。我们可以push新的对象到值栈中,也可以弹出值栈的栈顶对象
Struts2提供了一个特殊的OGNLPropertyAccessor,它可以自动查找栈内的所有对象(从栈顶到栈底),直接找到一个具有你所查找的属性的对象。也就是说,对于值栈中的任何对象都可以直接访问,而不需要使用“#”。
OGNL不支持多个root对象,而struts2能够支持多个root对象
在Struts2中,一个请求在最终到达Action的方法之前,Action对象本身会被压入ValueStack(实际上就是放到ValueStack的CompoundRoot中),所以Action对象是Action Context中的第一个元素 

细说valueStack
ValueStack(值栈)贯穿整个 Action 的生命周期每个 Action 类的对象实例都拥有一个

  ValueStack 对象. 相当于一个数据的中转站. 在其中保存当前Action 对象和其他相关对象.

Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性(request)中
当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action 。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。 

Value Stack举例
假设值栈中有两个对象:student和employee,两个对象都有name属性,student有学号属性number,而 employee有薪水属性salary。employee先入栈,student后入栈,位于栈顶,那么对于表达式name,访问的就是student 的name属性,因为student对象位于栈顶;表达式salary,访问的就是employee的salary属性。正如你所见,访问值栈中的对象属性或方法,无须指明对象,也不用“#”,就好像值栈中的对象都是OGNL上下文中的根对象一样。这就是Struts2在OGNL基础上做出的改进。

Value Stack配合标签示例1
UserAction
userAction_result.jsp
上述JSP页面将能正确将它们的值取出。<s:property value=”ognl表达式”/>。在s:property标签中的OGNL表达式,最终会交给ValueStack来解释。username就 是一个OGNL表达式,意思是调用root对象的getUsername()方法。Struts2将自动搜索CompoundRoot中有哪些元素(从第 0个元素开始搜索),检测这些元素是否有getUsername()方法,如果第0个元素没有getUsername()方法,将继续搜索第1、2、 3……个元素是否有getUsername()方法。
CompoundRoot中只有一个对象,就是userAction对象,而这个对象中正好有getUsername()方法,所以,上述JSP代码将能够将值正确取出 

改变默认栈顶元素
可以主动push新的对象到值栈中,也可以主动pop值栈的栈顶对象, 通过压栈和出栈操作,可以改变valueStack的结构
示例UserAction2.java
在上面这个UserAction的代码中,我们直接调用 ActionContext.getContext().getValueStack().push()方法,把一个User对象(这个对象拥有 getUsername()和setUsername()方法)直接压入到ValueStack中,这时候,在ValueStack的 CompoundRoot中将有两个元素:第0个元素是刚刚压入的user对象[李四],而第1个元素是userAction对象[张三]。

Struts的ONGL
栈中的 Action 实例

        Struts2框架默认总是把Action实例放在栈顶。因为Action在值栈中,而值栈又是OGNL中的根,所以引用Action的属性可以省略“#”标记,这也是为什么我们在结果页面中可以直接访问Action的属性的原因。

Struts2 中的非 root 对象

  如果访问Context其他对象,由于他们不是根对象,所以在访问时,需要添加#前缀;这些对象是直接保存在ActionContext中的,与valueStack平级;这些对象本质上都是Map  

parameters

         用于访问请求参数。如:#parameters[‘id’]或#parameters.id,相当于调用了     HttpServletRequest对象的getParameter()方法。

request

         用于访问请求属性。如:#request['user']或#request.user,相当于调用了HttpServletRequest对象的getAttribute()方法。

session

用于访问session属性。如:#session[‘user’]或#session.user,相当于调用了HttpSession对象的getAttribute()方法。

application

用于访问application属性。如:#application['user']或#application.user,相当于调用了ServletContext的getAttribute()方法。

attr

如果PageContext可用,则访问PageContext,否则依次搜索request、session和application对象。例如,#session[‘user’]=“zhangsan”,假定pageContext不可用,#attr[‘user’](或attr.user)将依次搜索request、session、application对象,最终在session中找到user属性。


采用OGNL表达式创建List/Map集合对象

果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式。

使用如下代码直接生成一个List对象:

 <s:setname="list" value="{'zhangming','xiaoi','liming'}" />

<s:iteratorvalue="#list" id="n">

  <s:property value="n"/><br>

</s:iterator>

生成一个Map对象:

<s:setname="foobar" value="#{'foo1':'bar1','foo2':'bar2'}" />

<s:iteratorvalue="#foobar" >

  <s:property value="key"/>=<s:property value="value"/><br>

</s:iterator>

Set标签用于将某个值放入指定范围

scope:指定变量被放置的范围,该属性可以接受applicationsessionrequest pageaction。如果没有设置该属性,则默认放置在valueStack中。

value:赋给变量的值.如果没有设置该属性,则将ValueStack栈顶的值赋给变量。


集合操作示例

UserAction3.java  userAction_list.jsp

iterator标签将循环访问users这个List中的User对象,并把当 前循环的user对象压入到CompoundRoot中


向Action属性自动赋值实质

Strut2的Action类通过属性可以获得所有相关的值,如请求参数、Action配置参数、向其他Action传递属性值(通过chain结果)等等。

要获得这些参数值,我们要做的唯一一件事就是在Action类中声明与参数同名的属性

实现该特性就是依靠valueStack配合拦截器共同完成的

每个Action类的对象实例会拥有一个自己的ValueStack对象,这个值栈贯穿整个Action的生命周期

该过程本质上是这样的:


当Struts2接收到一个.action的请求后,会先建立Action类的对象实例,但并不会调用Action方法,而是先将Action类的相应属性放到ValueStack对象中,这时候所有的属性值都是默认的值,如String类型的属性值为null,int类型的属性值为0等
在处理完上述工作后,Struts 2就会调用拦截器链中的拦截器,当调用完所有的拦截器后,最后会调用Action类的相应方法。
在调用Action方法之前,会将ValueStack对象顶层节点中的属性值赋给Action类中相应的属性。也就是说,在Struts2调用拦截器的过程中,可以改变ValueStack对象中属性的值
在Struts2的的Action类可以获得与属性同名的参数值就是通过不同的拦截器来处理的,如获得请求参数的拦截器是params,获得Action的配置参数的拦截器是staticParams等。在这些拦截器内部读取相应的值,并更新ValueStack对象顶层节点的相应属性的值。而ValueStack对象就象一个传送带,将属性值从一个拦截器传到了另一个拦截器(当然,在这其间,属性值可能改变),最后会传到Action对象,并将ValueStack对象中的属性的值终值赋给Action类的相应属性。
这就是一种AOP的思想的体现,通过一些代理类来透明地完成一些公用功能



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值