Struts2中的OGNL表达式

141 阅读10分钟

| 基础知识(三)  Struts2中的OGNL表达式  浅析值栈ValueStack对象相当于一个栈,它贯穿整个Action的生命周期,每个Action类的对象实例都会拥有一个ValueStack对象 当Struts2接收到一个*.action请求后,并不是直接调用Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点 值栈也位于内存中,它也是和parameters、request、session、application、attr对象放在一起的 值栈属于ONGL Context里面的根对象。也就是说它位于整个内存中最最重要的地方,所以叫根对象 根对象和另外五个对象是有区别的,根对象可以省写#号,比如<s:property value="user.username"/> 值栈的生命周期与request请求相关,每次请求产生一个值栈。默认所有的Action会被自动放到值栈里服务器跳转时共用值栈 假设从一个Action11通过服务器跳转到Action22的话,就意味着这两个Action是共享一个值栈的,因为一次请求只使用一个值栈 这时内存中情况是这样的:首先接收到Action11请求后,会产生一个值栈,在栈顶存放Action11对象以及它所有的属性 然后经过服务器跳转到Action22,这时就会把Action22对象压入值栈的栈顶位置,此时Action11对象以及它的所有属性就位于栈底了取值过程 栈的特征是后进先出。于是首先到栈顶的对象里查找是否存在这个属性,如果栈顶的Action22对象中不存在这个属性的话 它就会继续向下寻找直至栈底对象,一直查找是否存在这个属性 如果最后找到该属性的话,那么就会在JSP页面中通过<s:property value="username"/>输出属性值 如果在Action22和Action11都有一个同名的同类型的username属性的话,那么将输出Action22中的属性值 因为它是先从栈顶开始寻找属性的,值栈的特征就是后进先出,但有个前提:请求过程是通过服务器跳转的三个语法 假设此时想要获取Action11中的username属性的话,就可以使用值栈的Top语法或者N语法 使用Top语法获取值栈中的第二个对象的属性:<s:property value="[1].top.username"/> 使用 N 语法获取值栈中的第二个对象的属性:<s:property value="[1].username"/> 另外值栈还有一个@语法,例如使用@语法调用Action中的静态方法:<s:property value="@vs@getVOMethod()"/> @vs@get()等价于@vs1@getVOMethod(),指的是栈顶对象的静态getVOMethod()方法 同理@vs2@getVOMethod()就是取值栈中第二个对象的静态getVOMethod()方法客户端跳转时使用各自的值栈 假如中间某一个步骤中出现了客户端跳转的话,那么两个Action所使用的就是两个不同的值栈了 所以在Action22中就不能再使用Action11中的属性了,在最后跳转到的JSP页面中也就无法获取Action11的属性了 也即从Action22跳转到JSP页面时使用的是redirect的话,那么最后值栈中是没有任何的Action对象的 这个时候我们可以通过链接传参,比如<result type="redirect">test.jsp?netname=${username}</result> 意思就是取出Action22中的username属性作为参数,通过浏览器地址栏传递到JSP页面中 然后使用OGNL中的#号获取Paraments对象的属性,即<s:property value="#parameters.netname"/>就可以取到值了 辅助参考:blog.csdn.net/jadyer/arch…手工向值栈中压入对象 正常情况下值栈保存的是Action对象,而我们也可以直接往值栈中添加其它对象,这时可以在Action中添加如下代码 向值栈中添加对象:ActionContext.getContext.getValueStack().push(new Student("沈浪",22)); 而且我们手工往值栈中添加的Student对象会位于栈顶。这是因为Struts2会首先初始化Action,然后才能调用它的方法 初始化Action的时候,便把Action放到值栈中了,然后在执行它的execute()方法时,就又往值栈中添加了Student对象浅析OGNL OGNL是Object-Graph Navigation Language的缩写,是一种功能强大的表达式语言 通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能 OGNL用得最多的地方就是和Struts2的标签绑定,也可以在配置文件中通过${}使用OGNL表达式OGNL中$号的使用 1..在国际化资源文件中,引用OGNL表达式 2..在struts.xml文件中,引用OGNL表达式OGNL中%号的使用 1..使用%{}可以取出保存在值堆栈中的Action对象,直接调用它的方法 2..如果Action继承了ActionSupport,那么在页面标签中可以使用%{getText('key')}获取国际化信息 辅助参考:blog.csdn.net/jadyer/arch…OGNL中#号的使用 OGNL中的#号可以取出堆栈上下文中存放的对象| 名称 | 作用 | 例子 | | ----------- | --------------------------------------- | ------------------------------------------------------------ | | attr | 用于按request>>session>>application顺序访问其属性 | #attr.userName相当于按顺序从三个范围读取userName属性直到找到为止 | | request | 包含当前HttpServletRequest的属性的Map | #request.userName相当于request.getAttribute("userName") | | session | 包含当前HttpSession的属性的Map | #session.userName相当于session.getAttribute("userName") | | application | 包含当前应用的ServletContext的属性的Map | #application.userName相当于application.getAttribute("userName") | | parameters | 包含当前HTTP请求参数的Map | #parameters.id[0]相当于request.getParameter("id") |获取Action中的属性值或者Action中的对象的某某属性值 利用<s:property/>标签可以直接获取Action中的引用类型user里面的username属性 同样可以通过user.address.addr获取user中引用类型address中的addr属性的值 像这种一层一层往下传递的访问方式,即所谓的导航,也就是一步步的往下调用调用Action的对象里面的普通方法 默认的会把Action放到值栈里面,而值栈在访问的时候,并不需要值栈的名字 当我们调用<s:property value="user.getVOMethod()"/>的时候 它会自动到值栈里面查找Action对象里面有没有user对象,然后它就发现有user 然后它就再找user里面有没有getVOMethod()方法,然后它发现有,于是调用getVOMethod() 实际上调用User中的getVOMethod()方法的过程与获取表单中的姓名密码的方式都是相同的 都是到值栈里面查找,找是否存在user对象,如果存在,接着查找user中是否存在某某属性或方法调用Action中的静态方法 同样我们也可以在JSP页面中写一个OGNL表达式调用Action中的静态方法 调用Action中的静态方法时,与调用user对象的getVOMethod()方法的过程,是截然不同的 此时value的写法是固定的,以@开头,后面跟上具体的包名,然后@加上静态方法 比如<s:property value="@com.jadyer.action.LoginAction@getStatic()"/> 另外user对象是LoginAction中的一个属性,这个属性会自动的放到值栈里面 而值栈调用的时候,不用加上@或者包名等等,所以直接user.getVOMethod()就可以了调用JDK类中的静态方法 可以使用<s:property value="@@floor(46.58)"/>输出floor()的执行结果 这就意味着如果不在@@中指定类的话,默认的就表示java.lang.Math类 当前大多数情况下,我们都不会省略这个类,都会写全了的,然后在后面加上静态方法集合的伪属性 OGNL能够引用集合的一些特殊的属性,这些属性并不是JavaBean模式,例如size()、length() 当表达式引用这些属性时,OGNL会调用相应的方法,这就是伪属性 比如获取List的大小:<s:property value="testList.size"/>       List的伪属性:size、isEmpty、iterator        Set的伪属性:size、isEmpty、iterator        Map的伪属性:size、isEmpty、keys、values   Iterator的伪属性:next、hasNext Enumeration伪属性:next、hasNext、nextElement、hasMoreElements获取集合中元素的实质就是调用它的toString()方法 它还可以直接获取集合中的元素,事实上是在调用集合的toString()方法 所以我们可以根据实际情况通过重写集合的toString()方法来实现个性  化输出 甚至它还可以像访问数组那样,直接testList[2]获取集合中的元素 但这种方法只适用于List,不适用于Map。因为Map的索引是key,不是数值 另外,由于HashSet中的元素是没有顺序的,所以也不能用下标获取单个元素Lambda表达式 补充一下:使用Lambda表达式可以在OGNL中书写递归式子,在帮助中对它有很详细的说明 打开帮助中的//struts-2.0.14-all//struts-2.0.14//docs//index.html页面 在左侧的Documentation下面点击Guides链接,然后在这个页面中点击OGNL 最后跳转到//struts-2.0.14-all//struts-2.0.14//docs//docs//ognl.html 将这个页面右侧的下拉条拖放到最下面,就会看到它的说明了,它举的例子如下所示 <s:property value="#fib =:[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(11)" /> Lambda表达式的语法是:[...] ,中括号前面有一个冒号,所有东西都在中括号里面写 也就是说我们只要看到一个冒号跟着一个中括号,就表示这里使用的是Lambda表达式 #this指的是表达式的参数 所以这个例子可以这样理解:先判断这个参数是否等于零,如果等于零,那么它的值最后就是零 如果参数不等于零,就再判断它是否等于壹。如果参数等于壹,那么它的值最后就是壹 如果参数不等于壹,就继续调用#fib。注意这里已经用中括号将整体的值赋给了fib 实际上很少能够用得到Lambda表达式利用投影获取属性 利用投影获取List中对象的username属性时,其中{}表示的是一个集合 stus.{username}就表示将suts中所有的username属性取出组成一个新的列表利用选择获取属性 OGNL表达式是很灵活的,可以同时使用选择技术与投影技术获取属性 使用选择技术时,#this代表当前元素,问号?是把所有满足条件的元素都取出来 上箭头^是开始的意思,所以stus.{^#this.grade>=60}.{username}输出的是[张三] 注意,此时输出文本中包含中括号,这表示它是一个列表 而stus.{?#this.grade>=60}.{username}[0]输出的是张三,是字符串,二者是不同的 美元符号$是结束的意思,所以stus.{$#this.grade>=60}.{username}输出的是[王五] 这三个符合:问号、上箭头、美元符所返回的都是List补充 1..当OGNL取不到值的时候,它不会报错,而是什么都不显示 2..<s:property value="[0]"/>返回的是ValueStack中从上至下的所有的Object     <s:property value="[1]"/>返回的是ValueStack中从上至下的第二个Object 3..<s:property value="[0].username"/>返回的是成员变量username的值     假设ValueStack中存在两个Action的话,如果第一个Action如果没有username变量     那么它会继续找第二个Action。那么在什么情况下ValueStack中会存在两个Action呢     答案是在struts.xml中配置的是从一个Action通过<result type="chain">跳转到另一个Action 4..<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>     在Struts2.1.6中必须设置struts.ognl.allowStaticMethodAccess为true之后     才允许使用OGNL访问静态方法。而在Struts2.0.11则无需设置,即可直接访问***下面是OGNL测试的工程代码,这是一个Struts2.0.11应用首先是web.xml文件[xhtml]  view plain copy1. <?xmlversion="1.0"encoding="UTF-8"?>  2. <web-app version="2.5"   3.     xmlns="java.sun.com/xml/ns/java…"   4.     xmlns:xsi="www.w3.org/2001/XMLSch…"   5.     xsi:schemaLocation="java.sun.com/xml/ns/java…; 6.     java.sun.com/xml/ns/java…">  7.     <filter>  8.         <filter-name>struts2</filter-name>  9.         <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>  10.     </filter>  11.     <filter-mapping>  12.         <filter-name>struts2</filter-name>  13.         <url-pattern>/*</url-pattern>  14.     </filter-mapping>  15.     <welcome-file-list>  16.         <welcome-file>login.jsp</welcome-file>  17.     </welcome-file-list>    18. </web-app> [xhtml]  view plain copy1. <?xml version="1.0" encoding="UTF-8"?>   2. <web-app version="2.5"    3.     xmlns="java.sun.com/xml/ns/java…"    4.     xmlns:xsi="www.w3.org/2001/XMLSch…"    5.     xsi:schemaLocation="java.sun.com/xml/ns/java…; 6.     java.sun.com/xml/ns/java…">   7.     <filter>   8.         <filter-name>struts2</filter-name>   9.         <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>   10.     </filter>   11.     <filter-mapping>   12.         <filter-name>struts2</filter-name>   13.         <url-pattern>/*</url-pattern>   14.     </filter-mapping>   15.     <welcome-file-list>   16.         <welcome-file>login.jsp</welcome-file>   17.     </welcome-file-list>     18. </web-app>  然后是用于输入用户名和密码等信息的测试页面login.jsp [xhtml]  view plain copy1. <%@ page language="java"pageEncoding="UTF-8"%>  2. <h1>这是测试OGNL使用的登录页面</h1>  3. <h3><fontcolor="red">提示:</font>程序设定的用户名和密码各为<fontcolor="blue"><strong>admin</strong></font>和<fontcolor="blue"><strong>jadyer</strong></font></h3>  4. <h3><fontcolor="red">注意:</font>用户名和密码不正确时将停留在页面不动</h3>  5. <formaction="<%=request.getContextPath()%>/login.action"method="POST">  6.     <%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%>  7.     <%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%>  8.     姓名:<inputtype="text"name="user.username"><br>  9.     密码:<inputtype="text"name="user.password"><br>  10.     地址:<inputtype="text"name="user.address.addr"><br>  11.     <inputtype="submit"value="测试OGNL的输出">  12. </form> [xhtml]  view plain copy1. <%@ page language="java" pageEncoding="UTF-8"%>   2. <h1>这是测试OGNL使用的登录页面</h1>   3. <h3><font color="red">提示:</font>程序设定的用户名和密码各为<font color="blue"><strong>admin</strong></font>和<font color="blue"><strong>jadyer</strong></font></h3>   4. <h3><font color="red">注意:</font>用户名和密码不正确时将停留在页面不动</h3>   5. <form action="<%=request.getContextPath()%>/login.action" method="POST">   6.     <%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%>   7.     <%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%>   8.     姓名:<input type="text" name="user.username"><br>   9.     密码:<input type="text" name="user.password"><br>   10.     地址:<input type="text" name="user.address.addr"><br>   11.     <input type="submit" value="测试OGNL的输出">   12. </form>  然后是用于显示OGNL处理结果的loginSuc.jsp页面 [xhtml]  view plain copy1. <%@ page language="java"pageEncoding="UTF-8"%>  2. <%@ taglib prefix="s"uri="/struts-tags"%>  3. <h1>这是使用OGNL输出的结果页面</h1>  4. <table border="9">  5.     <tr>  6.         <tdalign="right">获取姓名属性:</td>  7.         <tdalign="left"><s:propertyvalue="user.username"/></td>  8.         <%-- 另外还有两种写法也是可以正常输出值栈中对象的普通属性的 --%>  9.         <%-- <s:propertyvalue="user['username']"/> --%>  10.         <%-- <s:propertyvalue="user[/"username/"]"/> --%>  11.         <%-- 但是如果写成下面这种形式的话,就什么都不会输出了 --%>  12.         <%-- <s:propertyvalue="user[username]"/> --%>  13.     </tr>  14.     <tr>  15.         <tdalign="right">获取地址属性:</td>  16.         <tdalign="left"><s:propertyvalue="user.address.addr"/></td>  17.     </tr>  18.     <tr>  19.         <tdalign="right">调用值栈中的对象的普通方法:</td>  20.         <tdalign="left"><s:propertyvalue="user.getVOMethod()"/></td>  21.     </tr>  22.     <tr>  23.         <tdalign="right">调用值栈中Action的普通方法:</td>  24.         <tdalign="left"><s:propertyvalue="getCommon()"/></td>  25.     </tr>  26. </table>  27. <hr/>  28. <table border="9">  29.     <tr>  30.         <tdalign="right">获取普通类的静态属性:</td>  31.         <tdalign="left"><s:propertyvalue="@com.jadyer.vo.Address@TIPS"/></td>  32.     </tr>  33.     <tr>  34.         <tdalign="right">访问普通类的构造方法:</td>  35.         <tdalign="left"><s:propertyvalue="new com.jadyer.vo.Student('张小三',22).username"/></td>  36.     </tr>  37.     <tr>  38.         <tdalign="right">调用Action中的静态方法:</td>  39.         <tdalign="left"><s:propertyvalue="@com.jadyer.action.LoginAction@getStatic()"/></td>  40.     </tr>  41.     <tr>  42.         <tdalign="right">调用JDK中的类的静态方法:</td>  43.         <tdalign="left"><s:propertyvalue="@java.util.Calendar@getInstance().time"/></td>  44.     </tr>  45.     <tr>  46.         <tdalign="right">调用JDK中的类的静态方法:</td>  47.         <tdalign="left"><s:propertyvalue="@java.lang.Math@floor(46.58)"/></td>  48.     </tr>  49.     <tr>  50.         <tdalign="right">调用JDK中的类的静态方法:</td>  51.         <tdalign="left"><s:propertyvalue="@@floor(46.58)"/></td>  52.     </tr>  53. </table>  54. <hr/>  55. <tableborder="9">  56.     <tr>  57.         <tdalign="right">获取List中的所有元素:</td>  58.         <tdalign="left"><s:propertyvalue="testList"/></td>  59.     </tr>  60.     <tr>  61.         <tdalign="right">获取Set中的所有元素:</td>  62.         <tdalign="left"><s:propertyvalue="testSet"/></td>  63.     </tr>  64.     <tr>  65.         <tdalign="right">获取Map中的所有元素:</td>  66.         <tdalign="left"><s:propertyvalue="testMap"/></td>  67.     </tr>  68.     <tr>  69.         <tdalign="right">获取Map中的某个元素:</td>  70.         <tdalign="left"><s:propertyvalue="testMap['m22']"/></td>  71.         <%-- 另外还有两种写法也是可以正常获取Map中的某个具体元素的 --%>  72.         <%-- <s:propertyvalue="testMap.m22"/> --%>  73.         <%-- <s:propertyvalue="testMap[/"m22/"]"/> --%>  74.     </tr>  75.     <tr>  76.         <tdalign="right">获取Set中的某个元素:</td>  77.         <%-- 由于Set中的元素是无顺序的,所以不能使用下标获取数据,所以这里什么也得不到 --%>  78.         <tdalign="left"><s:propertyvalue="testSet[2]"/></td>  79.     </tr>  80.     <tr>  81.         <tdalign="right">获取List中的某个元素:</td>  82.         <tdalign="left"><s:propertyvalue="testList[2]"/></td>  83.     </tr>  84. </table>  85. <hr/>  86. <table border="9">  87.     <tr>  88.         <tdalign="right">获取List的大小:</td>  89.         <tdalign="left"><s:propertyvalue="testList.size"/></td>  90.     </tr>  91.     <tr>  92.         <tdalign="right">获取Set的大小:</td>  93.         <tdalign="left"><s:propertyvalue="testSet.size"/></td>  94.     </tr>  95.     <tr>  96.         <tdalign="right">获取Map的大小:</td>  97.         <tdalign="left"><s:propertyvalue="testMap.size"/></td>  98.     </tr>  99.     <tr>  100.         <tdalign="right">获取Map中所有的键:</td>  101.         <tdalign="left"><s:propertyvalue="testMap.keys"/></td>  102.     </tr>  103.     <tr>  104.         <tdalign="right">获取Map中所有的值:</td>  105.         <tdalign="left"><s:propertyvalue="testMap.values"/></td>  106.     </tr>  107.     <tr>  108.         <tdalign="right">Lambda计算4的阶乘:</td>  109.         <tdalign="left"><s:propertyvalue="#f= :[#this==1?1 : #this*#f(#this-1)],#f(4)"/></td>  110.     </tr>  111. </table>  112. <hr/>  113. <tableborder="9">  114.     <tr>  115.         <tdalign="right">获取List中的所有对象:</td>  116.         <tdalign="left"><s:propertyvalue="stus"/></td>  117.     </tr>  118.     <tr>  119.         <tdalign="right">利用投影获取List中对象的名字:</td>  120.         <tdalign="left"><s:propertyvalue="stus.{username}"/></td>  121.     </tr>  122.     <tr>  123.         <tdalign="right">利用投影获取List中第二个对象的名字:</td>  124.         <%-- 使用<s:propertyvalue="stus[1].{username}"/>获取到的值为:[李四] --%>  125.         <%-- 二者的区别在于:后者比前者多了一个中括号 --%>  126.         <tdalign="left">  127.             <s:propertyvalue="stus.{username}[1]"/>        128.             <s:propertyvalue="stus[1].{username}"/>  129.         </td>  130.     </tr>  131.     <tr>  132.         <tdalign="right">利用选择获取List中成绩及格的所有对象:</td>  133.         <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}"/></td>  134.     </tr>  135.     <tr>  136.         <tdalign="right">利用选择获取List中成绩及格的第一个对象:</td>  137.         <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}"/></td>  138.     </tr>  139.     <tr>  140.         <tdalign="right">利用选择获取List中成绩及格的最后一个对象:</td>  141.         <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}"/></td>  142.     </tr>  143. </table>  144. <hr/>  145. <tableborder="9">  146.     <tr>  147.         <tdalign="right">利用选择获取List中成绩及格的所有对象的名字:</td>  148.         <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}"/></td>  149.     </tr>  150.     <tr>  151.         <tdalign="right">利用选择获取List中成绩及格的第二个对象的名字:</td>  152.         <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}[1]"/></td>  153.     </tr>  154.     <tr>  155.         <tdalign="right">利用选择获取List中成绩及格的第一个对象的名字:</td>  156.         <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}"/></td>  157.     </tr>  158.     <tr>  159.         <tdalign="right">利用选择获取List中成绩及格的最后一个对象的名字:</td>  160.         <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}.{username}"/></td>  161.     </tr>  162.     <tr>  163.         <tdalign="right">利用选择获取List中成绩及格的第一个对象然后求大小:</td>  164.         <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}.size"/></td>  165.     </tr>  166. </table>  167. <hr/>  168. <table border="9">  169.     <tr>  170.         <tdalign="right">利用OGNL中的#号获取attr中的属性:</td>  171.         <tdalign="left"><s:propertyvalue="#attr.BB"/></td>  172.     </tr>  173.     <tr>  174.         <tdalign="right">利用OGNL中的#号获取request范围中的属性:</td>  175.         <tdalign="left"><s:propertyvalue="#request.req"/></td>  176.     </tr>  177.     <tr>  178.         <tdalign="right">利用OGNL中的#号获取session范围中的属性:</td>  179.         <tdalign="left"><s:propertyvalue="#session.ses"/></td>  180.     </tr>  181.     <tr>  182.         <tdalign="right">利用OGNL中的#号获取Paraments对象的属性:</td>  183.         <tdalign="left"><s:propertyvalue="#parameters.netname"/></td>  184.     </tr>  185.     <tr>  186.         <tdalign="right">使用&#60;&#37;=request.getParameter&#40;""&#41;&#37;&#62;或者&#36;&#123;param.name&#125;获取链接参数值:</td>  187.         <tdalign="left">  188.             ${param.netname}        189.             <%=request.getParameter("netname")%>  190.         </td>  191.     </tr>  192.     <tr>  193.         <tdalign="right">查看值栈中的信息:</td>  194.         <tdalign="left"><s:debug/></td>  195.     </tr>  196. </table> [xhtml]  view plain copy1. <%@ page language="java" pageEncoding="UTF-8"%>   2. <%@ taglib prefix="s" uri="/struts-tags"%>   3. <h1>这是使用OGNL输出的结果页面</h1>   4. <table border="9">   5.     <tr>   6.         <td align="right">获取姓名属性:</td>   7.         <td align="left"><s:property value="user.username"/></td>   8.         <%-- 另外还有两种写法也是可以正常输出值栈中对象的普通属性的 --%>   9.         <%-- <s:property value="user['username']"/> --%>   10.         <%-- <s:property value="user[/"username/"]"/> --%>   11.         <%-- 但是如果写成下面这种形式的话,就什么都不会输出了 --%>   12.         <%-- <s:property value="user[username]"/> --%>   13.     </tr>   14.     <tr>   15.         <td align="right">获取地址属性:</td>   16.         <td align="left"><s:property value="user.address.addr"/></td>   17.     </tr>   18.     <tr>   19.         <td align="right">调用值栈中的对象的普通方法:</td>   20.         <td align="left"><s:property value="user.getVOMethod()"/></td>   21.     </tr>   22.     <tr>   23.         <td align="right">调用值栈中Action的普通方法:</td>   24.         <td align="left"><s:property value="getCommon()"/></td>   25.     </tr>   26. </table>   27. <hr/>   28. <table border="9">   29.     <tr>   30.         <td align="right">获取普通类的静态属性:</td>   31.         <td align="left"><s:property value="@com.jadyer.vo.Address@TIPS"/></td>   32.     </tr>   33.     <tr>   34.         <td align="right">访问普通类的构造方法:</td>   35.         <td align="left"><s:property value="new com.jadyer.vo.Student('张小三',22).username"/></td>   36.     </tr>   37.     <tr>   38.         <td align="right">调用Action中的静态方法:</td>   39.         <td align="left"><s:property value="@com.jadyer.action.LoginAction@getStatic()"/></td>   40.     </tr>   41.     <tr>   42.         <td align="right">调用JDK中的类的静态方法:</td>   43.         <td align="left"><s:property value="@java.util.Calendar@getInstance().time"/></td>   44.     </tr>   45.     <tr>   46.         <td align="right">调用JDK中的类的静态方法:</td>   47.         <td align="left"><s:property value="@java.lang.Math@floor(46.58)"/></td>   48.     </tr>   49.     <tr>   50.         <td align="right">调用JDK中的类的静态方法:</td>   51.         <td align="left"><s:property value="@@floor(46.58)"/></td>   52.     </tr>   53. </table>   54. <hr/>   55. <table border="9">   56.     <tr>   57.         <td align="right">获取List中的所有元素:</td>   58.         <td align="left"><s:property value="testList"/></td>   59.     </tr>   60.     <tr>   61.         <td align="right">获取Set中的所有元素:</td>   62.         <td align="left"><s:property value="testSet"/></td>   63.     </tr>   64.     <tr>   65.         <td align="right">获取Map中的所有元素:</td>   66.         <td align="left"><s:property value="testMap"/></td>   67.     </tr>   68.     <tr>   69.         <td align="right">获取Map中的某个元素:</td>   70.         <td align="left"><s:property value="testMap['m22']"/></td>   71.         <%-- 另外还有两种写法也是可以正常获取Map中的某个具体元素的 --%>   72.         <%-- <s:property value="testMap.m22"/> --%>   73.         <%-- <s:property value="testMap[/"m22/"]"/> --%>   74.     </tr>   75.     <tr>   76.         <td align="right">获取Set中的某个元素:</td>   77.         <%-- 由于Set中的元素是无顺序的,所以不能使用下标获取数据,所以这里什么也得不到 --%>   78.         <td align="left"><s:property value="testSet[2]"/></td>   79.     </tr>   80.     <tr>   81.         <td align="right">获取List中的某个元素:</td>   82.         <td align="left"><s:property value="testList[2]"/></td>   83.     </tr>   84. </table>   85. <hr/>   86. <table border="9">   87.     <tr>   88.         <td align="right">获取List的大小:</td>   89.         <td align="left"><s:property value="testList.size"/></td>   90.     </tr>   91.     <tr>   92.         <td align="right">获取Set的大小:</td>   93.         <td align="left"><s:property value="testSet.size"/></td>   94.     </tr>   95.     <tr>   96.         <td align="right">获取Map的大小:</td>   97.         <td align="left"><s:property value="testMap.size"/></td>   98.     </tr>   99.     <tr>   100.         <td align="right">获取Map中所有的键:</td>   101.         <td align="left"><s:property value="testMap.keys"/></td>   102.     </tr>   103.     <tr>   104.         <td align="right">获取Map中所有的值:</td>   105.         <td align="left"><s:property value="testMap.values"/></td>   106.     </tr>   107.     <tr>   108.         <td align="right">Lambda计算4的阶乘:</td>   109.         <td align="left"><s:property value="#f= :[#this==1?1 : #this*#f(#this-1)],#f(4)"/></td>   110.     </tr>   111. </table>   112. <hr/>   113. <table border="9">   114.     <tr>   115.         <td align="right">获取List中的所有对象:</td>   116.         <td align="left"><s:property value="stus"/></td>   117.     </tr>   118.     <tr>   119.         <td align="right">利用投影获取List中对象的名字:</td>   120.         <td align="left"><s:property value="stus.{username}"/></td>   121.     </tr>   122.     <tr>   123.         <td align="right">利用投影获取List中第二个对象的名字:</td>   124.         <%-- 使用<s:property value="stus[1].{username}"/>获取到的值为:[李四] --%>   125.         <%-- 二者的区别在于:后者比前者多了一个中括号 --%>   126.         <td align="left">   127.             <s:property value="stus.{username}[1]"/>         128.             <s:property value="stus[1].{username}"/>   129.         </td>   130.     </tr>   131.     <tr>   132.         <td align="right">利用选择获取List中成绩及格的所有对象:</td>   133.         <td align="left"><s:property value="stus.{?#this.grade>=60}"/></td>   134.     </tr>   135.     <tr>   136.         <td align="right">利用选择获取List中成绩及格的第一个对象:</td>   137.         <td align="left"><s:property value="stus.{^#this.grade>=60}"/></td>   138.     </tr>   139.     <tr>   140.         <td align="right">利用选择获取List中成绩及格的最后一个对象:</td>   141.         <td align="left"><s:property value="stus.{$#this.grade>=60}"/></td>   142.     </tr>   143. </table>   144. <hr/>   145. <table border="9">   146.     <tr>   147.         <td align="right">利用选择获取List中成绩及格的所有对象的名字:</td>   148.         <td align="left"><s:property value="stus.{?#this.grade>=60}.{username}"/></td>   149.     </tr>   150.     <tr>   151.         <td align="right">利用选择获取List中成绩及格的第二个对象的名字:</td>   152.         <td align="left"><s:property value="stus.{?#this.grade>=60}.{username}[1]"/></td>   153.     </tr>   154.     <tr>   155.         <td align="right">利用选择获取List中成绩及格的第一个对象的名字:</td>   156.         <td align="left"><s:property value="stus.{^#this.grade>=60}.{username}"/></td>   157.     </tr>   158.     <tr>   159.         <td align="right">利用选择获取List中成绩及格的最后一个对象的名字:</td>   160.         <td align="left"><s:property value="stus.{$#this.grade>=60}.{username}"/></td>   161.     </tr>   162.     <tr>   163.         <td align="right">利用选择获取List中成绩及格的第一个对象然后求大小:</td>   164.         <td align="left"><s:property value="stus.{^#this.grade>=60}.{username}.size"/></td>   165.     </tr>   166. </table>   167. <hr/>   168. <table border="9">   169.     <tr>   170.         <td align="right">利用OGNL中的#号获取attr中的属性:</td>   171.         <td align="left"><s:property value="#attr.BB"/></td>   172.     </tr>   173.     <tr>   174.         <td align="right">利用OGNL中的#号获取request范围中的属性:</td>   175.         <td align="left"><s:property value="#request.req"/></td>   176.     </tr>   177.     <tr>   178.         <td align="right">利用OGNL中的#号获取session范围中的属性:</td>   179.         <td align="left"><s:property value="#session.ses"/></td>   180.     </tr>   181.     <tr>   182.         <td align="right">利用OGNL中的#号获取Paraments对象的属性:</td>   183.         <td align="left"><s:property value="#parameters.netname"/></td>   184.     </tr>   185.     <tr>   186.         <td align="right">使用&#60;&#37;=request.getParameter&#40;""&#41;&#37;&#62;或者&#36;&#123;param.name&#125;获取链接参数值:</td>   187.         <td align="left">   188.             ${param.netname}         189.             <%=request.getParameter("netname")%>   190.         </td>   191.     </tr>   192.     <tr>   193.         <td align="right">查看值栈中的信息:</td>   194.         <td align="left"><s:debug/></td>   195.     </tr>   196. </table>  然后是struts.xml文件[xhtml]  view plain copy1. <?xmlversion="1.0"encoding="UTF-8"?>  2. <!DOCTYPE struts PUBLIC  3.     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"  4.     "struts.apache.org/dtds/struts…">  5. <struts>  6.     <packagename="ognl"extends="struts-default">  7.         <actionname="login"class="com.jadyer.action.LoginAction">  8.             <resultname="input">/login.jsp</result>  9.             <resultname="success">/loginSuc.jsp?netname=hongyu</result>  10.             <!--  11.             <resultname="success"type="redirect">/loginSuc.jsp?netname=hongyu</result>  12.             <resultname="success"type="redirect">/loginSuc.jsp?netname=${user.username}</result>   13.              -->  14.         </action>  15.     </package>  16. </struts> [xhtml]  view plain copy1. <?xml version="1.0" encoding="UTF-8"?>   2. <!DOCTYPE struts PUBLIC   3.     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   4.     "struts.apache.org/dtds/struts…">   5. <struts>   6.     <package name="ognl" extends="struts-default">   7.         <action name="login" class="com.jadyer.action.LoginAction">   8.             <result name="input">/login.jsp</result>   9.             <result name="success">/loginSuc.jsp?netname=hongyu</result>   10.             <!--   11.             <result name="success" type="redirect">/loginSuc.jsp?netname=hongyu</result>   12.             <result name="success" type="redirect">/loginSuc.jsp?netname=${user.username}</result>    13.              -->   14.         </action>   15.     </package>   16. </struts>  接着是用到的三个VO类 [java]  view plain copy1. package com.jadyer.vo;  2. publicclass User {  3.     private String username;  4.     private String password;  5.     private Address address;  6.     /* 三个属性的setter和getter略 */  7.     public String getVOMethod(){  8.         return"这是User类中的一个普通方法";  9.     }  10. }  11.   12.   13. package com.jadyer.vo;  14. publicclass Address {  15.     //如果将TIPS设为private的话,loginSuc.jsp中就无法获取它的属性值了  16.     //事实上将一个静态的final属性设为private是毫无意义的  17.     //因为既然设置成了静态,那么就是供他人调用的,如果再设成private的话,别的地方根本就无法调用了  18.     //即使OGNL再怎么强大,它也不可能违反Java的规则,所以不要将静态的属性设为私有  19.     publicstaticfinal String TIPS = "玄玉加油!!";  20.     //addr属性的setter和getter略  21.     private String addr;  22. }  23.   24.   25. package com.jadyer.vo;  26. publicclass Student {  27.     private String username;  28.     privateint grade;  29.     /* 两个属性的setter和getter略 */  30.       31.     //只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法  32.     //因为框架默认的都会去调用无参的空的构造方法  33.     public Student(){};  34.     public Student(String username,int grade){  35.         this.username = username;  36.         this.grade = grade;  37.     }  38.     @Override  39.     public String toString() {  40.         //如果不重写它的toString()方法的话,默认调用toString()将输出【类型+@+内存地址的哈希值】  41.         return"{学生姓名:" + username +",成绩:" + grade + "}";  42.     }  43. } [java]  view plain copy1. package com.jadyer.vo;   2. public class User {   3.     private String username;   4.     private String password;   5.     private Address address;   6.     /* 三个属性的setter和getter略 */   7.     public String getVOMethod(){   8.         return "这是User类中的一个普通方法";   9.     }   10. }   11.    12.    13. package com.jadyer.vo;   14. public class Address {   15.     //如果将TIPS设为private的话,loginSuc.jsp中就无法获取它的属性值了   16.     //事实上将一个静态的final属性设为private是毫无意义的   17.     //因为既然设置成了静态,那么就是供他人调用的,如果再设成private的话,别的地方根本就无法调用了   18.     //即使OGNL再怎么强大,它也不可能违反Java的规则,所以不要将静态的属性设为私有   19.     public static final String TIPS = "玄玉加油!!";   20.     //addr属性的setter和getter略   21.     private String addr;   22. }   23.    24.    25. package com.jadyer.vo;   26. public class Student {   27.     private String username;   28.     private int grade;   29.     /* 两个属性的setter和getter略 */   30.        31.     //只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法   32.     //因为框架默认的都会去调用无参的空的构造方法   33.     public Student(){};   34.     public Student(String username,int grade){   35.         this.username = username;   36.         this.grade = grade;   37.     }   38.     @Override   39.     public String toString() {   40.         //如果不重写它的toString()方法的话,默认调用toString()将输出【类型+@+内存地址的哈希值】   41.         return "{学生姓名:" + username + ",成绩:" + grade + "}";   42.     }   43. }  最后是用来提供OGNL测试的数据的LoginAction.java[java]  view plain copy print ?1. package com.jadyer.action;  2.   3. import java.util.ArrayList;  4. import java.util.HashMap;  5. import java.util.HashSet;  6. import java.util.List;  7. import java.util.Map;  8. import java.util.Set;  9.   10. import org.apache.struts2.interceptor.RequestAware;  11. import org.apache.struts2.interceptor.SessionAware;  12.   13. import com.jadyer.vo.Student;  14. import com.jadyer.vo.User;  15. import com.opensymphony.xwork2.ActionSupport;  16.   17. @SuppressWarnings({"serial","unchecked"})  18. publicclass LoginActionextends ActionSupport implements RequestAware,SessionAware {  19.     private User user;  20.     private List testList = new ArrayList();  21.     private Set testSet =new HashSet();  22.     private Map testMap = new HashMap();  23.     private List stus = new ArrayList();  24.       25.     /* 以上五个属性的setter和getter略 */  26.       27.     private Map request;  28.     private Map session;  29.     publicvoid setRequest(Map request) {  30.         this.request = request;  31.     }  32.     publicvoid setSession(Map session) {  33.         this.session = session;  34.     }  35.       36.     publicstatic String getStatic(){  37.         return"这是LoginAction中的一个静态方法";  38.     }  39.     public String getCommon(){  40.         return"这是LoginAction中的一个普通方法";  41.     }  42.       43.     @Override  44.     public String execute() throws Exception {  45.         if(user.getUsername().trim().equalsIgnoreCase("admin") && user.getPassword().equals("jadyer")){  46.             testList.add("list11");  47.             testList.add("list22");  48.             testList.add("list33");  49.             testList.add("list44");  50.             testList.add("list55");  51.               52.             testSet.add("set11");  53.             testSet.add("set22");  54.             testSet.add("set33");  55.             testSet.add("set22");  56.             testSet.add("set11");  57.               58.             testMap.put("m11", "map11");  59.             testMap.put("m22","map22");  60.             testMap.put("m33", "map33");  61.             testMap.put("m44","map44");  62.             testMap.put("m55", "map55");  63.               64.             stus.add(new Student("张三",88));  65.             stus.add(new Student("李四",77));  66.             stus.add(new Student("王五",66));  67.             stus.add(new Student("马六",55));  68.               69.             request.put("req","这是通过OGNL中的#号获取的request属性范围的值");  70.             session.put("ses", "这是通过OGNL中的#号获取的session属性范围的值");  71.             request.put("BB","这是通过OGNL中的#号获取的request属性范围的BB");  72.             session.put("BB", "这是通过OGNL中的#号获取的session属性范围的BB");  73.             return SUCCESS;  74.         }else{  75.             return INPUT;  76.         }  77.     }     78. } 79.  

80.