posts - 78, comments - 34, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2010-02-21 传智播客—Struts2

Posted on 2010-02-22 16:59 長城 阅读(739) 评论(0)  编辑  收藏

Struts2第二天,大家似乎没有从年假中苏醒过来,上课显得有些疲惫。不过还好,听课效果还不错。今日的主要内容是OGNLStruts2使用OGNL访问contextMapvalueStack。老张很执着,他在研究Struts2时遇到的一些问题,一定要解决,并且要详细解决。通过他在讲课中,我们可以看出这一点。有开发经验的人都知道,我们时而被陌生技术的一个小细节搞的晕头转向,耗费了大半天的时间我们才发现这个细节性的错误。我们一般都是这么熬出来的,老张也不例外。


我们在听老师讲课时或在网上看视频时,都感觉学习起来十分容易。却很少有人能感受那些认真负责老师在课后付出的心血。老张为了准备一天的课程内容,使用了三天时间来备课并且课程内容他以前也讲过。这一点不仅体现在老张的身上,其他老师也是这样。让我们为那些认真负责的老师敬礼,并问候一声:“过年好,您辛苦了!”。


一、ActionContext

Action环境(com.opensymphony.xwork2.ActionContext),通过我们之前所学的内容。我们知道Context缓存中保存了XXX环境中所需要使用到的重要对象。Struts2中的ActionContext中就保存了Struts2中使用到的重点对象contextMapvalueStack


老张搞了一个经典的关系图:


ActionContext ac = ActionContext.getContext();

ValueStack vs = ac.getValueStack();

Map<String, Object> conMap = ac.getContextMap();

每一个访问线程具有一个ActionContext对象,它是以单例模式存在的。ActionContext为我们提供了操作valueStackcontextMap的便捷方法。例我们的程序可以与ValueStackContextMap解耦,比如:ac.put(key, value);ac.get(key);...


通过ActionContext使得我们编写的Action不必实现任何接口和继承任何超类,但我们必须在类中使用ActionContext的实例。


二、Struts2中的OGNL

OGNL不是Struts2独创的,而是Struts2中使用OGNL做为操作contextMapvalueStack的方式。OGNLObject-Graph Navigation Language的缩写,它是一种功能强大的表达式语言(Expression Language,简称为EL),通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。


OGNLl基本的语法:

  1. 可以用#key的形式访问OGNL Context对象中的各个key对应的对象,并可以采用点(.)操作符进行多级导航调用对象的属性和方法,例如,#application#session.attr1#key1.sayHello();对于map对象,map.attr不是map.getAttr()方法,而是表示map.get(“attr1”)

  2. 如果要访问根对象的属性或方法,则可以省略#key,直接访问该对象的属性和方法。 struts2修改了OGNL表达式的默认属性访问器,它不是直接访问根对象ValueStack的属性或方法,而是在ValueStack内部的堆栈中所有对象上逐一查找该属性或方法,搜索顺序是从栈顶对象开始寻找,依次往下,直到找到为止,例如,sayHello()表示调用堆栈中某个对象的sayHello()方法。

  3. 特例:如果引用名前面没有#,且valueStack中存储的各个对象没有该属性,则把该名称当作Context对象中的某个key来检索对应的对象,但这种方式不支持点(.)操作符。


ValueStack提供了如下一些方法管理其内部的堆栈和关联的Context

  1. setValueognl表达式寻址到的对象设置属性值。

  2. FindValue方法使用OGNL表达式获取结果。

  3. findString方法对findValue方法获取的结果调用转换器转成字符串,如果该对象的类型没有相关转换器,则调用toString方法,并返回结果字符串。一个特殊之处:如果不用#前缀访问ValueStack Context中的对象,则该对象必须是String类型。


三、Struts2中的struts-tagsOGNL详细

要使用struts-tags标签,必须先引入struts-2.1.7.dtd文档类型定义文件。

  1. <s:property>用于输出某个OGNL表达式的值,可以认为其内部使用的是ValueStack对象的findString方法。如果没有设置value属性,则输出ValueStack栈顶的对象。

    特例:如果采用不加#前缀的方式输出Context中的某个对象,这个对象必须是string类型。

    如:获取contextMap中的request对象。

    <s:property value="#request" />

  2. <s:push>用于将OGNL表达式的值压入栈顶,当遇到</s:push>标签时,从栈顶弹出。

    如:向栈顶压入了一个字符串——“你好!”。

    <s:push value="'你好!'">

    <s:property value="top" />

    </s:push>

    注意压入的字符串必须被包含在''中,否则会被OGNL当做名称到根对象中查找相应的值。

    通过查看<s:push>标签的帮助,可以知道有一个为top的特殊OGNL表达式,表示栈顶的对象。

    如:

<s:push value="'你好!'"><s:property name="top"/></s:push>


  1. <s:bean>用于实例化一个JavaBean对象,并将其压入栈顶。如果设置了var属性,还会将实例化的对象存储进ValueStack关联的Context中。

    如:实例化一个java.util.Date对象,然后将其放入ContextMap中。

    <s:bean name="java.util.Date" var="MyBean">

    <s:property value="#MyBean" />

    </s:bean>

  2. <s:set>用于将某个值存入指定范围域中,通常用于将一个复杂的ognl表达式用一个简单的变量来进行引用。

    如:向request域中添加一个名称为“TestSet”的属性。

    <s:set scope="request" value="'日期'+#MyBean" name="TestSet">

    <s:property value="#request.TestSet" />

    </s:set>

    scope属性:指定变量被放置的范围,该属性可以接受applicationsessionrequest pageaction。该属性的默认值为action,文档说即表示同时存储进request作用域和OGNL Context中,但实验结果是只存储进了OGNL Context中。

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

  3. <s:if/elseif/else>等标签用于判断test属性中指定的ognl表达式的结果是否为true,为真则执行标签体重的内容。

    如:设置一个VAL,然后判断VAL的值,并显示相应的结果。

    <s:set value="'1'" name="VAL"></s:set>

    <s:if test="1 > 2">

    <s:property value="#VAL+'>2'" />

    </s:if>

    <s:elseif test="1 < 2">

    <s:property value="#VAL+'<2'" />

    </s:elseif>

    <s:else>

    <s:property value="#VAL+'=2'" />

    </s:else>

  4. <s:iterator>用于迭代一个OGNL集合,并逐一将迭代出来的元素压入栈顶和弹栈。

    如:获取request中的所有属性,并且使表格奇数行颜色为#f3c3c3,偶数行颜色为#c3f3f3

    <table>

    <tr>

    <td>Key</td><td>Value</td>

    </tr>

    <s:iterator value="#request" status="status">

    <tr bgcolor='<s:property value="#status.odd ? '#f3c3c3':'#c3f3f3'"/>' >

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

    <td><s:property value="value"/></td>

    </tr>

    </s:iterator>

    </table>

    status属性:创建代表当前迭代状态的IteratorStatus对象,并指定将其存储进ValueStack Context中时的key。它与官方给出的帮助文档的说明不同,官方存在错误!

  5. <s:url><s:a>

    使用这两个标签可以带给我们极大的方便,使用他们的好处有:

    使用<s:url namespace=“” action=“” method=“”/>不用关心web应用程序的路径和Action映射的扩展名。<s:url>中没有指定namespace属性时,将根据浏览器当前所访问的url地址来推测包名,并与action属性指定的内容一起生成最终的url地址。

    可以自动附加jsessionid参数进行url重写。

    可以对参数信息进行url编码。 (jstl中的<c:url>标准标签也有<s:url>标签的后两个作用。)

    直接使用<s:url />标签可以获得当前地址,只有使用includeParams属性会带上原来的请求参数。大型网站的链接地址总是要带上userid之类的信息。

    如:生成一个访问我们昨天编写的HelloWorld请求超连接。

    <s:a namespace="/" action="helloWorld" method="helloWorld">HelloWorld</s:a>

四、OGNL中的语法细节

1.参看ognl的参考手册

类似EL表达式的JavaBean属性访问和索引访问,例如,可以用”#parameter.id[0]”或”#parameter[‘id’][0]”访问名称为id的请求参数。

支持类静态方法调用和属性访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format(‘foo %s’, ‘bar’)@cn.itcast.Constant@APP_NAME

session.attribute[“foo”]等效于session.getAttribute(“foo”)方法。

OGNL中可以写很大的整数,例如,<s:property value="%{1111111111111111111111H.bitLength()}"/>,而在java中则不能直接写1111111111111111111111这么大的整数。

对当前值可以进一步操作,<s:property value=“110H.intValue().(#this<112?#this*2:#this/2)”/>,其中.(#this …..)部分相当于定义了一个匿名方法,并调用这个匿名方法,方法的代码就是()里面的内容。


2.Struts2扩展的特殊功能

[n]表示从原来堆栈中截取一个子堆栈并对这个子堆栈进行操作,子堆栈为原始堆栈的栈顶开始的索引号为n的元素一直到栈底,例如,[1].age表示从原始堆栈中的索引号为1的对象(即第二个对象)开始查找age属性,以找到的第一个为准。

top表示ValueStack栈顶的对象,[0].toptop表示同一个对象。


3.集合对象与操作

{}用于创建List集合对象,其中的各个元素之间用逗号分隔:

<s:set value="{1,3,5,7}" var="list"/>


采用类似Java的语法创建数组:

<s:set value="new int[]{1,3,5,7}" var="array"/>

<s:set value="new int[4]" var="array"/>

#{}用于创建Map集合对象,其中的各个元素之间用逗号分隔,元素的keyvalue之间采用冒号分隔。另外,还可以指定Map实例对象的类型:

<s:set value="#{'lhm':96,'zxx':93,'xpc':97}" />

<s:set value="#@java.util.LinkedHashMap@{'lhm':96,'zxx':93,'xpc':97}" />

innot in操作符用于判断某个值是否位于某个集合中。

<s:set value="new int[]{1,3,5,7}" var="array"/>

<s:if test="1 in #array">

<s:property value="#array"/>

</s:if>

集合伪属性:size/isEmpty/iterator/keys/values/next/hasNext

<s:set value="#{'lhm':96,'zxx':93,'xpc':97}" var="map"/>

<s:if test="#map.size > 0">

<s:property value="#map"/>

</s:if>


4.集合的投影与过滤

投影就是拿着集合中的每个元素去进行运算,各个元素运算的结果组成一个新集合,新集合中的元素个数与原始集合中的元素个数相同。

<s:property value="persons.{name}"/>

<s:property value="{5,3,2}.{#this*2}"/>

过滤就是拿着集合中的每个元素去进行布尔运算,运算的结果为true,则将该元素保存到新集合中去。

?:获得所有符合逻辑的元素。

<s:property value="{5,3,2,0}.{? #this }"/>

^:获得符合逻辑的第一个元素。

<s:property value="{5,3,2,0}.{^ #this>3 }"/>

$:获得符合逻辑的最后一个元素。

<s:property value="{5,3,2,0}.{$ #this>2 }"/>


5.类型转换

转换成boolean类型:

  • 整数0转换为fals

  • 值为0的字符转化为false

  • Null对象转化为false

投影和选择操作符(e1.{e2} and e1.{?e2})里面的内容会被转换成集合

Map会被转化成其values属性返回的集合

数字会被转换成从0开始到比该数字小1的所有数字的集合。

单个对象被转换成仅仅只含有该对象的集合。


五、在配置文件中使用OGNL

在下堂课中会做总结!



只有注册用户登录后才能发表评论。


网站导航: