Struts2中的ognl标签

1、ValueStack与<s:debug>标签
Struts 2框架使用OGNL作为默认的表达式语言,先用<s:property> 标签体验一下ognl表达式和调动学习热情,例如,显示Action中的一个属性和显示一个请求参数。
OGNL表达式就是针对一个称为OGNL Context的Map对象和一个称之为OGNL根对象进行操作的语言,OGNL表达式可以寻址Context内部的对象和直接调用根对象的属性或方法。
Struts2中设置的OGNL 根对象为CompoundRoot, OGNL Context的Map对象和CompoundRoot 封装在一个ValueStack对象中。由于OGNL Context是一个Map对象,不算什么新知识,不用专门学习了,所以,学习OGNL的重要第一步就是要先了解ValueStack和CompoundRoot 。ValueStack内部封装的CompoundRoot是一个继承了ArrayList实现的堆栈,ValueStack内部还保存了ValueStack Context的引用。(见下页的关系图)
<s:debug>标签可以在jsp页面中查看ValueStack和其关联的Context对象中的信息。
如果不经过struts2的过滤器拦截就直接访问jsp页面,那么其中使用的<s:debug>,<s:text>,<s:property value="%{getText()}">等struts2标签都会报告TagUtil.getStack方法抛出的异常。
获取ValueStack对象的代码如下:
ValueStack stack = ActionContext.getContext().getValueStack();
ValueStack提供了如下一些方法管理其内部的堆栈:
push和pop方法分别对堆栈进行压栈和弹栈。
set方法用于在栈顶的Map对象中设置一个条目,如果栈顶不是一个Map对象,则创建一个Map对象并将其压入栈顶。实验结果:set方法好像不能设置栈顶不同JavaBean对象的属性。

Struts2框架为OGNL Context内部初始填充的几个重要的key:
parameters一个map对象
request 一个map对象
session 一个map对象
application 一个map对象
attr 一个map对象

2、OGNL基础与ValueStack的有关方法:
OGNL(对象图导航语言,Object Graph Navigation Language)是一种用于从ValueStack对象与其关联的Context上下文中获取的值的表达式,最基本的语法如下:
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:
setValue为ognl表达式寻址到的对象设置属性值。
findValue方法使用OGNL表达式获取结果。
findString方法对findValue方法获取的结果调用转换器转成字符串,如果该对象的类型没有相关转换器,则调用toString方法,并返回结果字符串。一个特殊之处:如果不用#前缀访问ValueStack Context中的对象,则该对象必须是String类型。

<s:property>标签用于输出某个OGNL表达式的值,可以认为其内部使用的是ValueStack对象的findString方法。
如果没有设置value属性,则输出ValueStack栈顶的对象。
特例:如果采用不加#前缀的方式输出Context中的某个对象,这个对象必须是string类型。
<s:push>标签用于将OGNL表达式的值压入栈顶。
看<s:push>标签的帮助,可以知道有一个为top的特殊OGNL表达式,表示栈顶的对象。
<s:bean>标签用于实例化一个JavaBean对象,并将其压入栈顶。
如果设置了var属性,还会将实例化的对象存储进ValueStack关联的Context中。
实验步骤:
查看<s:debug>标签的执行结果。
用<s:push>标签把Context中的一个对象压入栈顶,再查看<s:debug>标签的执行结果,注意<s:debug>标签要位于<s:push>标签对之间。
用<s:bean>标签用于实例化一个java.util.Date实例对象,查看<s:debug>标签的执行结果,注意<s:debug>标签也要位于<s:push>标签对之间;接着设置其var属性,再查看<s:debug>标签的执行结果。

<s:set>标签用于将某个值存入指定范围域中,通常用于将一个复杂的ognl表达式用一个简单的变量来进行引用。
scope属性:指定变量被放置的范围,该属性可以接受application、session、request、 page或action(context)。该属性的默认值为action,文档说即表示同时存储进request作用域和OGNL Context中,但实验结果是只存储进了OGNL Context中。
value属性:赋给变量的ognl表达式结果.如果没有设置该属性,则将ValueStack栈顶的值赋给变量。
<s:if/elseif/else>等标签用于判断test属性中指定的ognl表达式的结果是否为true,为真则执行标签体重的内容。
<s:iterator>标签用于迭代一个OGNL集合,并逐一将迭代出来的元素压入栈顶和弹栈。
status属性:创建代表当前迭代状态的IteratorStatus对象,并指定将其存储进ValueStack Context中时的key。
输出迭代后的ValueStack栈顶对象的属性并利用迭代状态的示例代码如下:
<s:iterator value="#request" status="status">
<tr class='<s:property value="#status.odd ? 'odd':'even'"/>' >
<td><s:property value="key"/>::::<s:property value="value"/></td>
</tr>

3、OGNL的语法细节:
参看ognl的参考手册
类似EL表达式的JavaBean属性访问和索引访问,例如,可以用”#parameter.id[0]”或”#parameter[‘id’][0]”访问名称为id的请求参数。
问题:ValueStack Context有一个名称为com.opensymphony.xwork2.ActionContext.locale的key,使用一个怎样的OGNL表达式可引用这个key对应的值对象呢?答:可以先从request中得到valueStack,再从ValueStack获得context,再从context中用[]的方式获取。
支持类静态方法调用和属性访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@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 …..)部分相当于定义了一个匿名方法,并调用这个匿名方法,方法的代码就是()里面的内容。
Struts2扩展的特殊功能
[n]表示从原来堆栈中截取一个子堆栈并对这个子堆栈进行操作,子堆栈为原始堆栈的栈顶开始的索引号为n的元素一直到栈底,例如,[1].age表示从原始堆栈中的索引号为1的对象(即第二个对象)开始查找age属性,以找到的第一个为准。
top表示ValueStack栈顶的对象,[0].top和top表示同一个对象。

{}用于创建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集合对象,其中的各个元素之间用逗号分隔,元素的key和value之间采用冒号分隔。另外,还可以指定Map实例对象的类型。
<s:set value=“#{‘lhm’:96,’zxx’:93,’xpc’:97}”
<s:set value=“#@java.util.LinkedHashMap@{‘lhm’:96,’zxx’:93,’xpc’:97}”
in与not in操作符用于判断某个值是否位于某个集合中。
集合伪属性:size/isEmpty/iterator/keys/values/next/hasNext

投影就是拿着集合中的每个元素去进行运算,各个元素运算的结果组成一个新集合,新集合中的元素个数与原始集合中的元素个数相同。
<s:property value=“persons.{name}”/>
<s:property value=“{5,3,2}.{#this*2}”/>
过滤就是拿着集合中的每个元素去进行布尔运算,运算的结果为true,则将该元素保存到新集合中去。
?:获得所有符合逻辑的元素。
<s:property value=“{5,3,2}.{? #this }”/>
^:获得符合逻辑的第一个元素。
<s:property value=“{5,3,2}.{^ #this>3 }”/>
$:获得符合逻辑的最后一个元素。
<s:property value=“{5,3,2}.{$ #this>2 }”/>

转换成boolean类型
整数0转换为false
值为0的字符转化为false
Null对象转化为false
投影和选择操作符(e1.{e2} and e1.{?e2})前面的内容会被转换成集合
Map会被转化成其values属性返回的集合
数字会被转换成从0开始到比该数字小1的所有数字的集合。
单个对象被转换成仅仅只含有该对象的集合。

4、在配置文件中使用OGNL:
在struts2的各种配置文件中也可以使用OGNL,只需要将OGNL表达式套在${}中,即${ognl表达式}。
总结列表:对${ognl}的总结涉及一些大家暂时还没学习到的内容,大家可以在学完相关知识后再来看这个总结列表
在struts.xml文件的<result>元素中,经常需要使用${属性名}表达式访问action中的属性,表达式里的属性名对应action中的属性。如下:
<result type="redirect">view.jsp?id=${id}</result>
在校验配置文件的<message>元素中,可能需要使用${getText(‘key’)}表达式访问国际资源包的消息。
在国际化资源文件中,也可以使用${ognl表达式},例如,使用${getText(‘key’)}表达式来获取国际化消息填充另一个资源的占位符。
在jsp页面中可以使用${获取属性的ognl表达式},但不能在${}使用调用方法的ognl表达式,否则,会把它当作el表达式的自定义函数。

<s:url>和<s:a>标签的四个好处:
使用<s:url action=“” namespace=“” method=“”/>不用关心web应用程序的路径和Action映射的扩展名。<s:url>中没有指定namespace属性时,将根据浏览器当前所访问的url地址来推测包名,并与action属性指定的内容一起生成最终的url地址。
可以自动附加jsessionid参数进行url重写。
可以对参数信息进行url编码。 备注:jstl中的<c:url>标准标签也有<s:url>标签的后两个作用。
直接使用<s:url />标签可以获得当前地址,只有使用includeParams属性会带上原来的请求参数。大型网站的链接地址总是要带上userid之类的信息。
实验步骤:
启动一个新浏览器访问第一个Action,查看<s:url>生成的超链接地址,刷新的访问,再查看<s:url>生成的超链接地址,比较差异说明<s:url>标签的url重写功能。
在<s:url>的action属性值的路径后也可以直接加参数,但不能对其中的中文进行编码。使用<s:param>子标签设置一个或多个参数,可以完成中文参数的url编码。
再写一个<s:url>标签,其中不带任何属性,并在访问地址中增加一些参数,查看其生成的url地址;接着设置其includeParams属性,再查看结果。这里应该打开标签的帮助文档进行讲解。
为上面的<s:url>标签增加var属性,并用<s:property>标签输出var属性指定的变量。
问题:使用s:url>标签的value属性时,其中的值不会当作OGNL表达式处理,而是当作普通字符串处理,如果value的内容要根据表达式运算,如何做?
在value属性值中使用%{},struts2就会把其中内容当作ognl表达式处理。

1.<%@page import="com.opensymphony.xwork2.ActionContext"%>  
2.<%@page import="java.util.List"%>  
3.<%@page import="java.util.Arrays"%>  
4.<%@page import="cn.itcast.struts2valuestack.domain.User"%>  
5.<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
6.<%@ taglib uri="/struts-tags" prefix="s" %>  
7.<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
8.<html>  
9.<head>  
10.<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
11.<title>Ognl标签应用</title>  
12.</head>  
13.<bodys>  
14.    <!--  
15.         value : ognl表达式  
16.         default : 默认值  
17.         escapeHtml : true 如果文本中有标签,那么转义  
18.     -->  
19.    <s:property value="name" default="表达式没有找值" escapeHtml="true"/><br/>  
20.      
21.    获取map中值:<s:property value="#name"/><br/>  
22.      
23.    <!-- #context Ongl内置的命令 -->  
24.    获取map中特殊key的值:<s:property value="#context.get('com.opensymphony.xwork2.ActionContext.locale')"/><br/>  
25.    获取map中特殊key的值:<s:property value="#context['com.opensymphony.xwork2.ActionContext.locale']"/><br/>  
26.      
27.    获取ValueStack栈:<s:property/><br/>  
28.      
29.    <!-- 不加#在栈中查找属性,如果没有找到,它在下面Map中查找,并且强行转为String类型 -->  
30.    获取map中的值:<s:property value="haha"/><br/>  
31.      
32.      
33.    <!--  
34.        value : ognl表达式  
35.        通过ognl表达式获取值,并把值压入栈顶 ,标签结束弹栈  
36.     -->  
37.    <s:push value="#currentDate">  
38.        当前毫秒数:<s:property value="time"/><br/>  
39.    </s:push>  
40.      
41.      
42.    <!--  
43.        var : 存储在map中变量的名字  
44.        name : 需要创建对象的类全名   
45.     -->  
46.    <s:bean var="myDate" name="java.util.Date"></s:bean>  
47.      
48.      
49.    <!--  
50.         var : 存储在作用域中变量的名字  
51.         value : ognl表达式  
52.         scope : application, session, request, page, or action(map),默认是action  
53.     -->  
54.    <s:set var="varxxx" value="name" scope="action"/>  
55.      
56.    <!-- 
57.         把ognl强行当初一个字符串处理,%{'字符串'} 
58.     -->  
59.    <s:set var="varyyy" value="%{'你好啊'}" scope="action"/>  
60.      
61.    <!-- if elseif esle -->  
62.    <!-- test:ognl表达式 -->  
63.    <s:if test="1<0">  
64.        1<0(if)  
65.    </s:if>  
66.    <s:elseif test="1!=1">  
67.        1!=1(elseif)  
68.    </s:elseif>  
69.    <s:else>  
70.        1==1(else)  
71.    </s:else>  
72.      
73.      
74.    <%  
75.        User user1 = new User("张三","123456");  
76.        User user2 = new User("李四","123456");  
77.        User user3 = new User("王五","123456");  
78.        User user4 = new User("赵六","123456");  
79.        User user5 = new User("田七","123456");  
80.        List<User> users = Arrays.asList(user1,user2,user3,user4,user5);  
81.        ActionContext.getContext().put("users",users);  
82.    %>  
83.      
84.    <%-- <s:iterator >迭代器 --%>  
85.    <h3>第一种迭代(可以使用)</h3>  
86.    <table border="1">  
87.        <tr>  
88.            <th>用户名</th>  
89.            <th>密码</th>  
90.        </tr>  
91.        <!--  
92.             var : 没迭代一次,每个对象名字  
93.             value : ognl表达式  
94.         -->  
95.        <s:iterator var="item" value="#users">  
96.            <tr>  
97.                <td>  
98.                    <s:property value="#item.userName"/>  
99.                </td>  
100.                <td>  
101.                    <s:property value="#item.password"/>  
102.                </td>  
103.            </tr>  
104.        </s:iterator>  
105.    </table>  
106.      
107.    <h3>第二种迭代(推荐使用)</h3>  
108.    <table border="1">  
109.        <tr>  
110.            <th>序号</th>  
111.            <th>用户名</th>  
112.            <th>密码</th>  
113.        </tr>  
114.        <!--  
115.             var : 没迭代一次,每个对象名字  
116.             value : ognl表达式  
117.             status : 迭代器状态对象,比如:index,count....,对应org.apache.struts2.views.jsp.IteratorStatus类  
118.             "把当前迭代出来的对象,压入栈顶,迭代完后,弹栈"  
119.         -->  
120.        <s:iterator value="#users" status="mystatus">  
121.            <tr>  
122.                <td>  
123.                    <s:property value="#mystatus.count"/>  
124.                </td>  
125.                <td>  
126.                    <s:property value="userName"/>  
127.                </td>  
128.                <td>  
129.                    <s:property value="password"/>  
130.                </td>  
131.            </tr>  
132.        </s:iterator>  
133.    </table>  
134.      
135.    <%  
136.        //request.setAttribute("userName","我是request中东东....");  
137.        //System.out.println(request);  
138.    %>  
139.      
140.    <h3>第三种迭代(不推荐使用)</h3>  
141.    <table border="1">  
142.        <tr>  
143.            <th>用户名</th>  
144.            <th>密码</th>  
145.        </tr>  
146.        <!--  
147.             var : 每迭代一次,每个对象名字  
148.             value : ognl表达式  
149.             "把当前迭代出来的对象,压入栈顶,迭代完后,弹栈"  
150.         -->  
151.        <s:iterator value="#users">  
152.            <tr>  
153.                <td>  
154.                    ${userName}  
155.                </td>  
156.                <td>  
157.                    ${password}  
158.                </td>  
159.            </tr>  
160.        </s:iterator>  
161.    </table>  
162.      
163.    <h3>OGNL的语法细节</h3>  
164.      
165.    <%--  
166.        String.format("hello %s !","张三");  
167.         支持类静态方法调用和属性访问 ,需要加入配置  
168.           
169.         <!-- ognl表达式执行静态方法调用 -->  
170.        <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>  
171.    --%>  
172.    <s:property value="@java.lang.String@format('hello %s','张三')"/><br/>  
173.      
174.    <%--  
175.        Struts2扩展的特殊功能  
176.     --%>  
177.     获取栈顶:<s:property/><br/>  
178.     获取栈顶:<s:property value="top"/><br/>  
179.    [n(number)]:<s:property value="[1].top"/><br/>  
180.      
181.    <h3>OGNL的语法细节——集合对象与操作</h3>  
182.      
183.    <%--{}用于创建List集合对象,其中的各个元素之间用逗号分隔 --%>  
184.    <s:set var="myList" value="{1,2,3,4,5,6,7,8}"/>  
185.    <s:property value="#myList[0]"/><br/>  
186.      
187.    <!-- 采用类似Java的语法创建数组 -->  
188.    <s:set value="new int[]{1,3,5,7}" var="array1"/>  
189.    <s:property value="#array1"/><br/>  
190.    <s:set value="new int[4]" var="array2"/>  
191.    <s:property value="#array2"/><br/>  
192.      
193.    <%--  
194.        #{}用于创建Map集合对象,其中的各个元素之间用逗号分隔,元素的key和value之间采用冒号分隔。  
195.        另外,还可以指定Map实例对象的类型。  
196.    --%>  
197.    <s:set value="#{'key1':'value1','key2':123456}" var="myMap"/>  
198.    <s:property value="#myMap"/><br/>  
199.       
200.    <!-- in与not in操作符用于判断某个值是否位于某个集合中。 -->  
201.    in:<s:property value="5 in #myList"/><br/>  
202.    not in:<s:property value="5 not in #myList"/><br/>  
203.      
204.    <!-- 集合伪属性:size/isEmpty/iterator/keys/values/next/hasNext -->  
205.     集合伪属性:<s:property value="#myList.size"/><br/>  
206.       
207.       
208.      
209.    <h3>OGNL的语法细节——集合的投影与过滤</h3>  
210.    <%  
211.        User user11 = new User("张三","123456");  
212.        User user12 = new User("李四","123456");  
213.        User user13 = new User("王五","123456");  
214.        User user14 = new User("赵六","123456");  
215.        User user15 = new User("田七","123456");  
216.        List<User> myusers = Arrays.asList(user11,user12,user13,user14,user15);  
217.        ActionContext.getContext().put("myusers",myusers);  
218.    %>  
219.    <%-- 投影就是拿着集合中的每个元素去进行运算,各个元素运算的结果组成一个新集合,新集合中的元素个数与原始集合中的元素个数相同。--%>  
220.    <s:property value="#myusers.{userName}"/><br/>  
221.      
222.    <%-- #this集合中的每一个元素 --%>  
223.    <s:property value="{5,3,2}.{#this*2}"/><br/>  
224.      
225.    <%--过滤就是拿着集合中的每个元素去进行布尔运算,运算的结果为true --%>  
226.      
227.    <!-- ?:获得所有符合逻辑的元素 -->  
228.    <s:property value="{5,3,2}.{? #this>0}"/><br/>  
229.      
230.    <!-- ^:获得符合逻辑的第一个元素 -->  
231.    <s:property value="{-1,5,3,2}.{^ #this>0}"/><br/>  
232.      
233.    <!-- $:获得符合逻辑的第一个元素 -->  
234.    <s:property value="{5,3,2}.{$ #this>0}"/><br/>  
235.      
236.    <a href="testOgnl">在配置文件中使用OGNL</a>  
237.      
238.      
239.    <%--<s:url>与<s:a>标签  --%>  
240.    <!--  
241.        action : struts2中action的名字  
242.        namespace : struts2package的命名空间   
243.          
244.        url 它会自动加上appPath(<Context path="/xxx"/>)  
245.     -->  
246.    <br/>   
247.    <a href="<s:url action="testOgnl" namespace="/xxx"></s:url>">  
248.        testOgnl  
249.    </a>   
250.    <br/>  
251.    <%ActionContext.getContext().put("id","010");%>  
252.    <%--  
253.        把ognl当成一个字符串执行 %{'字符串'}  
254.        把一个字符串当成ognl表达式执行 %{表达式}  
255.          
256.        includeParams : 把"get"请求参数,加载url后面  
257.        includeParams : 把"get"和"post"请求参数,加载url后面  
258.     --%>  
259.    <s:a action="testOgnl?username=009&id=%{#id}" namespace="/xxx" includeParams="all">  
260.        testOgnl  
261.        <%--value : ognl表达式 ,如果使用<s:param>配置请求参数,名字不能一样--%>  
262.        <s:param name="username">007</s:param>  
263.        <%--value : ognl表达式 --%>  
264.        <s:param name="username" value="%{'008'}"></s:param>  
265.    </s:a>  
266.      
267.    <s:debug/>  
268.</body>  
269.</html>

你可能感兴趣的:(struts2,Ognl)