strut2ognl
然而,我认为struts2最复杂难学的是它内置的ognl表达式.这个ognl在我开始学struts2时,让我云里雾里,不知如何应对.经过几轮 的翻看书籍,与网上资料查询,还算是让我有所明白一点.在此记录,以便日后温习,同时,如果这篇文章对各位有哪怕一点帮助,那便是我最大的荣幸.
首先,要知道ognl最主要的功能就是取数据,它可以利用一段简短的表达式取出各种各样丰富的数据.其次,它还附带了一些便捷的功能,如:方法调用、 静态方法和属性调用、数值运算……我们最关心的是如何取数据,因此,接下来我将重点介绍如何取数据,至于附带功能将不做介绍。
知道了ognl最主要的功能是取数据后,那么数据从哪里取呢!ognl会从两个地方取:一个是Action的实例属性;另一个是 ValueStack(中文名叫值栈)。ognl会先从前者里面取,如果没取到再到ValueStack里取。Action的实例属性好理解,但这个 ValueStack从字面上看,着实不好理解,以致于我将struts2的源码引进eclipse里,单步调试才算有所启发。可以将 ValueStack初步理解为一个map,在这个map里存储了request、session、application、response、 action实例、parameters数组……还有很多你不知道的对象。有了这个map,还愁数据取不到吗。
注意:将ValueStack初步理解为一个map,只适于初学struts2的人,其实它内部并没这么简单。由于水平、时间有限,我并不能掌握其内 部精髓,加上表达能力不佳,怕表达不对误导大家,所以我们姑且理解ValueStack为一个map吧。如果想更深的了解的ValueStack,请查看 struts2的源码。
接下来,便是取数据。取action实例的属性数据与取ValueStack中的数据不一样,先说取action实例的属性数据吧。
action实例的属性数据可以直接在struts2的标签中通过属性名取到。如:<s:property value="name"/>、<s:property value="user.password"/>
注意:不要加#号。
再是取ValueStack中的数据。
struts2提供三种方式通过ognl表达式来取ValueStack中的数据:#、%{}、${}
#和%{}需要放到struts2提供的标签里才生效。如:<s:property value="#name"/>、<s:property value="%{'hello struts2'}"/>
一、最常用的方式是:#
1.#能取request、session、application里的attribute,但需要加前缀。如:<s:property value="#session.name2"/>、<s:property value="#application.name3"/>。如果是取request范围的attribute,那么不需要加request前缀, 加上反而取不到数据,ognl默认从request里取,如果没有取到并不会到session或application里取。 如:<s:property value="#name"/>
2.#能取request里的请求参数,但必须加parameters前缀,且取到的是一个数组,所以如果你要得到参数的第一项值,那么还要加下标。 如:<s:property value="#parameters.name[0]"/>。这相当于调用 request.getParameterValues("name")[0];
3.#加attr前缀能按request > session > application顺序获取attribute,这样当在request中取不到时,会自动向session里取,如果session里也取不到,会 再向application里取。如果取到则返回,不再向上游历。如:<s:property value="#attr.name"/>
4.#能构造Map,如:<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" /><s:property value="#foobar['foo1']" />
5.#能用于过滤和投影(projecting)集合,如:books.{?#this.price<100}
以上第4、5项功能,我没有做过多介绍,因为目前为止这两项功能我使用并不多。
二、%{}的用途是在标签的属性为字符串类型时,计算OGNL表达式的值。这个功能目前还没有深刻体会,故不介绍。
三、${}有两个主要的用途。
1.用于在国际化资源文件中,引用OGNL表达式。
2.在Struts 2配置文件中,引用OGNL表达式。如 :
<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack" />
<result type="redirect">ListPhotos.action?albumId=${albumId}</result>
</action>
以上,其实主要介绍了#的使用,大部分情况下我们只与它打交道,另外两种方式需要在以后的项目中多多使用才能有所体会。
其实,我是jstl+el的忠实粉丝,在任何项目中,只要能用上jstl标签的,我决不用其它标签。因为它是官方标准,还有它简单且已熟练,我已在众多项目中实战演练过,有了它们,我不想在使用其它标签。
说到了这里,我还是有必要再多说两句,是不是使用了struts2,就不能再用el来取数据了呢?答案是否定的,完全可以使用el来取数据。 struts2会将ValueStack里的session、application里的attribute完全复制到HttpSession、 ServletContext里,这样el表达式照样能取到这两个Scope里的数据。然而,struts2并没有将ValueStack里的 request里的attribute复制到HttpServletRequest,这是不是意味着el表达式就不能取request里的数据了呢?还是 可以,不只可以取request里的数据,还可以取action实例的属性值。神奇吧!奥秘就在struts2对request做了封装,这个封装类是 org.apache.struts2.dispatcher.StrutsRequestWrapper,它重写了getAttribute()方法, 该方法先从真实的request类里取attribute,如果取到则返回,如果没有取到则从ValueStack里取,现在明白了吧!