值栈 OGNL

值栈 OGNL

OGNL是一种功能强大的表达式语言,能自动导航对象的结构并访问和设置对象数据。OGNL表达式中,它的核心对象是OGNL上下文。

OGNL上下文相当于一个Map容器Struts2中:OGNL上下文=Struts2中的ActionContext=值栈+Session+其他值栈是OGNL的根对象,可以被直接访问。

 

 Strut 2Action类通过属性可以获得所有相关的值,如请求参数、Action 配置参数、向其他Action传递属性值(通过chain结果)等等。要获得这些参数值,我 们要做的唯一一件事就是在Action类中声明与参数同名的属性,在Struts 2调用Action 类的Action方法(默认是execute方法)之前,就会为相应的Action属性赋值。 要完成这个功能,有很大程度上,Struts 2要依赖于ValueStack对象。这个对象贯 穿整个Action的生命周期(每个Action类的对象实例会拥有一个ValueStack对象)。当 Struts 2接收到一个.action的请求后,会先建立Action类的对象实例,但并不会调用 Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点 ValueStack对象相当于一个栈)。只是所有的属性值都是默认的值,如String类型的 属性值为nullint类型的属性值为0等。 在处理完上述工作后,Struts 2就会调用拦截器链中的拦截器,当调用完所有的拦 截器后,最后会调用Action类的Action方法,在调用Action方法之前,会将ValueStack 对象顶层节点中的属性值赋给Action类中相应的属性。大家要注意,在这里就给我们带 来了很大的灵活性。也就是说,在Struts 2调用拦截器的过程中,可以改变ValueStack 对象中属性的值,当改变某个属性值后,Action类的相应属性值就会变成在拦截器中最 后改变该属性的这个值。 

 从上面的描述很容易知道,在Struts 2的的Action类可以获得与属性同名的参数值 就是通过不同的拦截器来处理的,如获得请求参数的拦截器是params,获得Action的配 置参数的拦截器是staticParams等。在这些拦截器内部读取相应的值,并更新 ValueStack对象顶层节点的相应属性的值。而ValueStack对象就象一个传送带,将属性 值从一个拦截器传到了另一个拦截器(当然,在这其间,属性值可能改变),最后会传 Action对象,并将ValueStack对象中的属性的值终值赋给Action类的相应属性 无意中发现,属性没有写set get 方法,依然会注入值和取到值

 甚是不解,求助于网上依然没有得到解决

 花了点时间看了下源码 

发现

struts2 参数拦载器在注入值的时候,有两种机制,(调用ognl) 

这是OgnlRuntime 类中一段源码 hasSetMethod( context, target, targetClass, name ) || hasField( context, target, targetClass, name ); 

 

他会先查看你的action 中有没有对应的方法,如果发现无此方法,他会利用第二种方法 

直接给属性覆值,而无需对应的set方法!(当然都是通过反射机制实现的

如果action 中属性过多的话,我觉得就不用写set get 方法了!(不知道这个会不会给以 

 后维护带来问题). 

 个人总结:OGNL中的值栈相当于一个数据的中转站,或者叫数据的缓冲存储中心。另外,OGNL除了有值栈(value stack)这个特别的对象外,它的表达式语言也自成一派。 

 值栈和session都是在ActionContext的全局领域内的,按我个人通俗的说法就是ActionContext最大,并且ActionContext中包含值栈和session这些全局的容器,因为actioncontext是线程级的,那么session就是线程安全的。 

 

下面介绍如何引用值栈中的对象(又称属性或者值,什么叫法不重要,重要的是知道我们是引用值栈内的东西):

我们在jsp页面是直接面向值栈操作,所以值栈的内容可以直接用名字来引用。值栈外的如session就要用OGNL语法中的#来操作。 

对于值栈来说,struts2有专门的tag<s:property >来引用值栈内容,如下例: 

<s:property value="artist.bio" /> 

session是值栈外的(全局的,或称根级别),所以要用OGNL#符号表达式来引用session里的对象,如 

<s:property value="#session['artistBio']" /> 

可以先把一个变量级别升高成为全局,然后用#符号来引用值,那么用s:set标签来做,如 

<s:set name="artistName" value="artist.name" /> =====》级别提高了哦,YEAH!! 

<s:set name="artistBio" value="artist.bio" /> ======》老子级别也高了,YEAH!! 

<b>Album Title :</b> <s:property value="title" /> <br> 

<b>Artist Name :</b> <s:property value="#artistName" /> 

<br> <b>Artist Bio :</b> <s:property value="#artistBio" /> ===》级别高了,不在值栈内就不能直接引用了。。。。。需要加# 

假如想让对象不但级别高了(全局的)在整个session周期内持久,就要加上scope,如 

<s:set name="artistName" value="artist.name" scope="session" /> 

<s:set name="artistBio" value="artist.bio" scope="session" /> 

<b>Album Title :</b> <s:property value="title" /> <br> 

<b>Artist Name :</b> <s:property value="#session['artistName']" /> <br> 

<b>Artist Bio :</b> <s:property value="#session['artistBio']" /> <br> 

下面还有push标签,用来把对象放到值栈顶端: 

<b>Album Title :</b> <s:property value="title" /> <br> 

<s:push value="artist"> 

<b>Artist Name :</b> <s:property value="name" /> <br> 

<b>Artist Bio :</b> <s:property value="bio" /> <br> 

</s:push> 

那么<s:bean>这个标签,用来在页面实例化一个bean放在值栈中,它的生存周期就是到了</s:bean>为止就结束了,所以说假如要用<s:property>这个标签来引用该bean的属性的话,一定要在<s:bean></s:bean>标签之中用。如下面例子: 

<s:bean name="vaannila.CurrencyConverter"> 

    <s:param name="dollars" value="100" /> 

100Dollars = 

<s:property value="rupees" /> 

Rupees 

</s:bean> 

那么假如在bean标签之外引用呢,因为这时候这个bean的生命周期结束了,已经不在值栈内了,所以要用的话,需要事先在前面bean的声明地方加上一个变量声明,使其成为全局的对象,然后再像引用session变量那样的方式来引用它,如下例: 

<s:bean name="vaannila.CurrencyConverter" var="converter"> 

<s:param name="dollars" value="100"></s:param> 

</s:bean> 

100 Dollars = 

<s:property value="#converter.rupees" /> 

 

源文档 <http://mizhihua.iteye.com/blog/1297184> 

你可能感兴趣的:(值栈 OGNL)