- 浏览: 162471 次
- 性别:
文章分类
- 全部博客 (208)
- java web (1)
- java (5)
- Hibernate (10)
- MySql (17)
- GItLab的使用 (1)
- 数据库 (0)
- Spring (9)
- Hibernate + JPA (2)
- JPA (6)
- JQuery (15)
- Eclipse (8)
- Struts2 (2)
- POI (4)
- 工具类 (11)
- Linux (12)
- Json (2)
- 娱乐 (1)
- 学习 (2)
- log4j (1)
- Springmvc (7)
- Excel (3)
- 框架搭建 (2)
- 正则 (2)
- Javamelody (1)
- java反射 (2)
- 中文乱码 (1)
- @ResponseBody 中文乱码 (1)
- 从服务器下载文件 (2)
- ajax (4)
- 存储过程 (2)
- 设计模式 (1)
- junit (2)
- shiro (3)
- java 发送邮件 (1)
- jsp (1)
- xml (1)
- maven (4)
- svn (1)
- 定位 (1)
- redis (3)
- JVM (1)
- Jbpm4.4 (1)
- UML (2)
- Tomcat (1)
- Ckeditor (1)
- JRebel (1)
- CSS (2)
- echart (1)
- html5 (1)
- Ngrok (1)
- NatAPP (1)
- base64编码 (2)
- springBoot (6)
- clone (1)
- dubbo (1)
- zookeeper (1)
- SpringCloud (24)
- RestTemplate (1)
- RocketMQ (1)
- log4j2 (1)
- JS (1)
- 跨域 (1)
- 链路追踪 (2)
- lua (1)
- druid (1)
- thymleaf (1)
- 状态机 (3)
- stateless4j (2)
- mybatis (1)
- generator (1)
最新评论
Strut的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"/>就可以取到值了
辅助参考:http://blog.csdn.net/jadyer/archive/2010/09/16/5887509.aspx
手工向值栈中压入对象
正常情况下值栈保存的是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')}获取国际化信息
辅助参考:http://blog.csdn.net/jadyer/archive/2010/09/16/5887545.aspx
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文件
- <?xmlversion="1.0"encoding="UTF-8"?>
- <web-appversion="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <welcome-file-list>
- <welcome-file>login.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
- <?xmlversion="1.0"encoding="UTF-8"?>
- <web-appversion="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <welcome-file-list>
- <welcome-file>login.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
然后是用于输入用户名和密码等信息的测试页面login.jsp
- <%@ pagelanguage="java"pageEncoding="UTF-8"%>
- <h1>这是测试OGNL使用的登录页面</h1>
- <h3><fontcolor="red">提示:</font>程序设定的用户名和密码各为<fontcolor="blue"><strong>admin</strong></font>和<fontcolor="blue"><strong>jadyer</strong></font></h3>
- <h3><fontcolor="red">注意:</font>用户名和密码不正确时将停留在页面不动</h3>
- <formaction="<%=request.getContextPath()%>/login.action"method="POST">
- <%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%>
- <%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%>
- 姓名:<inputtype="text"name="user.username"><br>
- 密码:<inputtype="text"name="user.password"><br>
- 地址:<inputtype="text"name="user.address.addr"><br>
- <inputtype="submit"value="测试OGNL的输出">
- </form>
- <%@pagelanguage="java"pageEncoding="UTF-8"%>
- <h1>这是测试OGNL使用的登录页面</h1>
- <h3><fontcolor="red">提示:</font>程序设定的用户名和密码各为<fontcolor="blue"><strong>admin</strong></font>和<fontcolor="blue"><strong>jadyer</strong></font></h3>
- <h3><fontcolor="red">注意:</font>用户名和密码不正确时将停留在页面不动</h3>
- <formaction="<%=request.getContextPath()%>/login.action"method="POST">
- <%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%>
- <%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%>
- 姓名:<inputtype="text"name="user.username"><br>
- 密码:<inputtype="text"name="user.password"><br>
- 地址:<inputtype="text"name="user.address.addr"><br>
- <inputtype="submit"value="测试OGNL的输出">
- </form>
然后是用于显示OGNL处理结果的loginSuc.jsp页面
- <%@ pagelanguage="java"pageEncoding="UTF-8"%>
- <%@ taglibprefix="s"uri="/struts-tags"%>
- <h1>这是使用OGNL输出的结果页面</h1>
- <tableborder="9">
- <tr>
- <tdalign="right">获取姓名属性:</td>
- <tdalign="left"><s:propertyvalue="user.username"/></td>
- <%-- 另外还有两种写法也是可以正常输出值栈中对象的普通属性的 --%>
- <%--<s:propertyvalue="user['username']"/>--%>
- <%--<s:propertyvalue="user[/"username/"]"/>--%>
- <%-- 但是如果写成下面这种形式的话,就什么都不会输出了 --%>
- <%--<s:propertyvalue="user[username]"/>--%>
- </tr>
- <tr>
- <tdalign="right">获取地址属性:</td>
- <tdalign="left"><s:propertyvalue="user.address.addr"/></td>
- </tr>
- <tr>
- <tdalign="right">调用值栈中的对象的普通方法:</td>
- <tdalign="left"><s:propertyvalue="user.getVOMethod()"/></td>
- </tr>
- <tr>
- <tdalign="right">调用值栈中Action的普通方法:</td>
- <tdalign="left"><s:propertyvalue="getCommon()"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取普通类的静态属性:</td>
- <tdalign="left"><s:propertyvalue="@com.jadyer.vo.Address@TIPS"/></td>
- </tr>
- <tr>
- <tdalign="right">访问普通类的构造方法:</td>
- <tdalign="left"><s:propertyvalue="new com.jadyer.vo.Student('张小三',22).username"/></td>
- </tr>
- <tr>
- <tdalign="right">调用Action中的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@com.jadyer.action.LoginAction@getStatic()"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@java.util.Calendar@getInstance().time"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@java.lang.Math@floor(46.58)"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@@floor(46.58)"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testList"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Set中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testSet"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testMap"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中的某个元素:</td>
- <tdalign="left"><s:propertyvalue="testMap['m22']"/></td>
- <%-- 另外还有两种写法也是可以正常获取Map中的某个具体元素的 --%>
- <%--<s:propertyvalue="testMap.m22"/>--%>
- <%--<s:propertyvalue="testMap[/"m22/"]"/>--%>
- </tr>
- <tr>
- <tdalign="right">获取Set中的某个元素:</td>
- <%-- 由于Set中的元素是无顺序的,所以不能使用下标获取数据,所以这里什么也得不到 --%>
- <tdalign="left"><s:propertyvalue="testSet[2]"/></td>
- </tr>
- <tr>
- <tdalign="right">获取List中的某个元素:</td>
- <tdalign="left"><s:propertyvalue="testList[2]"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List的大小:</td>
- <tdalign="left"><s:propertyvalue="testList.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Set的大小:</td>
- <tdalign="left"><s:propertyvalue="testSet.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map的大小:</td>
- <tdalign="left"><s:propertyvalue="testMap.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中所有的键:</td>
- <tdalign="left"><s:propertyvalue="testMap.keys"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中所有的值:</td>
- <tdalign="left"><s:propertyvalue="testMap.values"/></td>
- </tr>
- <tr>
- <tdalign="right">Lambda计算4的阶乘:</td>
- <tdalign="left"><s:propertyvalue="#f= :[#this==1?1 : #this*#f(#this-1)],#f(4)"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List中的所有对象:</td>
- <tdalign="left"><s:propertyvalue="stus"/></td>
- </tr>
- <tr>
- <tdalign="right">利用投影获取List中对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用投影获取List中第二个对象的名字:</td>
- <%-- 使用<s:propertyvalue="stus[1].{username}"/>获取到的值为:[李四] --%>
- <%-- 二者的区别在于:后者比前者多了一个中括号 --%>
- <tdalign="left">
- <s:propertyvalue="stus.{username}[1]"/>
- <s:propertyvalue="stus[1].{username}"/>
- </td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的所有对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的最后一个对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的所有对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第二个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}[1]"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的最后一个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象然后求大小:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}.size"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">利用OGNL中的#号获取attr中的属性:</td>
- <tdalign="left"><s:propertyvalue="#attr.BB"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取request范围中的属性:</td>
- <tdalign="left"><s:propertyvalue="#request.req"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取session范围中的属性:</td>
- <tdalign="left"><s:propertyvalue="#session.ses"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取Paraments对象的属性:</td>
- <tdalign="left"><s:propertyvalue="#parameters.netname"/></td>
- </tr>
- <tr>
- <tdalign="right">使用<%=request.getParameter("")%>或者${param.name}获取链接参数值:</td>
- <tdalign="left">
- ${param.netname}
- <%=request.getParameter("netname")%>
- </td>
- </tr>
- <tr>
- <tdalign="right">查看值栈中的信息:</td>
- <tdalign="left"><s:debug/></td>
- </tr>
- </table>
- <%@pagelanguage="java"pageEncoding="UTF-8"%>
- <%@taglibprefix="s"uri="/struts-tags"%>
- <h1>这是使用OGNL输出的结果页面</h1>
- <tableborder="9">
- <tr>
- <tdalign="right">获取姓名属性:</td>
- <tdalign="left"><s:propertyvalue="user.username"/></td>
- <%--另外还有两种写法也是可以正常输出值栈中对象的普通属性的--%>
- <%--<s:propertyvalue="user['username']"/>--%>
- <%--<s:propertyvalue="user[/"username/"]"/>--%>
- <%--但是如果写成下面这种形式的话,就什么都不会输出了--%>
- <%--<s:propertyvalue="user[username]"/>--%>
- </tr>
- <tr>
- <tdalign="right">获取地址属性:</td>
- <tdalign="left"><s:propertyvalue="user.address.addr"/></td>
- </tr>
- <tr>
- <tdalign="right">调用值栈中的对象的普通方法:</td>
- <tdalign="left"><s:propertyvalue="user.getVOMethod()"/></td>
- </tr>
- <tr>
- <tdalign="right">调用值栈中Action的普通方法:</td>
- <tdalign="left"><s:propertyvalue="getCommon()"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取普通类的静态属性:</td>
- <tdalign="left"><s:propertyvalue="@com.jadyer.vo.Address@TIPS"/></td>
- </tr>
- <tr>
- <tdalign="right">访问普通类的构造方法:</td>
- <tdalign="left"><s:propertyvalue="newcom.jadyer.vo.Student('张小三',22).username"/></td>
- </tr>
- <tr>
- <tdalign="right">调用Action中的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@com.jadyer.action.LoginAction@getStatic()"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@java.util.Calendar@getInstance().time"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@java.lang.Math@floor(46.58)"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@@floor(46.58)"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testList"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Set中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testSet"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testMap"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中的某个元素:</td>
- <tdalign="left"><s:propertyvalue="testMap['m22']"/></td>
- <%--另外还有两种写法也是可以正常获取Map中的某个具体元素的--%>
- <%--<s:propertyvalue="testMap.m22"/>--%>
- <%--<s:propertyvalue="testMap[/"m22/"]"/>--%>
- </tr>
- <tr>
- <tdalign="right">获取Set中的某个元素:</td>
- <%--由于Set中的元素是无顺序的,所以不能使用下标获取数据,所以这里什么也得不到--%>
- <tdalign="left"><s:propertyvalue="testSet[2]"/></td>
- </tr>
- <tr>
- <tdalign="right">获取List中的某个元素:</td>
- <tdalign="left"><s:propertyvalue="testList[2]"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List的大小:</td>
- <tdalign="left"><s:propertyvalue="testList.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Set的大小:</td>
- <tdalign="left"><s:propertyvalue="testSet.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map的大小:</td>
- <tdalign="left"><s:propertyvalue="testMap.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中所有的键:</td>
- <tdalign="left"><s:propertyvalue="testMap.keys"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中所有的值:</td>
- <tdalign="left"><s:propertyvalue="testMap.values"/></td>
- </tr>
- <tr>
- <tdalign="right">Lambda计算4的阶乘:</td>
- <tdalign="left"><s:propertyvalue="#f=:[#this==1?1:#this*#f(#this-1)],#f(4)"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List中的所有对象:</td>
- <tdalign="left"><s:propertyvalue="stus"/></td>
- </tr>
- <tr>
- <tdalign="right">利用投影获取List中对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用投影获取List中第二个对象的名字:</td>
- <%--使用<s:propertyvalue="stus[1].{username}"/>获取到的值为:[李四]--%>
- <%--二者的区别在于:后者比前者多了一个中括号--%>
- <tdalign="left">
- <s:propertyvalue="stus.{username}[1]"/>
- <s:propertyvalue="stus[1].{username}"/>
- </td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的所有对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的最后一个对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的所有对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第二个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}[1]"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的最后一个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象然后求大小:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}.size"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">利用OGNL中的#号获取attr中的属性:</td>
- <tdalign="left"><s:propertyvalue="#attr.BB"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取request范围中的属性:</td>
- <tdalign="left"><s:propertyvalue="#request.req"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取session范围中的属性:</td>
- <tdalign="left"><s:propertyvalue="#session.ses"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取Paraments对象的属性:</td>
- <tdalign="left"><s:propertyvalue="#parameters.netname"/></td>
- </tr>
- <tr>
- <tdalign="right">使用<%=request.getParameter("")%>或者${param.name}获取链接参数值:</td>
- <tdalign="left">
- ${param.netname}
- <%=request.getParameter("netname")%>
- </td>
- </tr>
- <tr>
- <tdalign="right">查看值栈中的信息:</td>
- <tdalign="left"><s:debug/></td>
- </tr>
- </table>
然后是struts.xml文件
- <?xmlversion="1.0"encoding="UTF-8"?>
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
- "http://struts.apache.org/dtds/struts-2.0.dtd">
- <struts>
- <packagename="ognl"extends="struts-default">
- <actionname="login"class="com.jadyer.action.LoginAction">
- <resultname="input">/login.jsp</result>
- <resultname="success">/loginSuc.jsp?netname=hongyu</result>
- <!--
- <resultname="success"type="redirect">/loginSuc.jsp?netname=hongyu</result>
- <resultname="success"type="redirect">/loginSuc.jsp?netname=${user.username}</result>
- -->
- </action>
- </package>
- </struts>
- <?xmlversion="1.0"encoding="UTF-8"?>
- <!DOCTYPEstrutsPUBLIC
- "-//ApacheSoftwareFoundation//DTDStrutsConfiguration2.0//EN"
- "http://struts.apache.org/dtds/struts-2.0.dtd">
- <struts>
- <packagename="ognl"extends="struts-default">
- <actionname="login"class="com.jadyer.action.LoginAction">
- <resultname="input">/login.jsp</result>
- <resultname="success">/loginSuc.jsp?netname=hongyu</result>
- <!--
- <resultname="success"type="redirect">/loginSuc.jsp?netname=hongyu</result>
- <resultname="success"type="redirect">/loginSuc.jsp?netname=${user.username}</result>
- -->
- </action>
- </package>
- </struts>
接着是用到的三个VO类
- packagecom.jadyer.vo;
- publicclassUser {
- privateString username;
- privateString password;
- privateAddress address;
- /* 三个属性的setter和getter略 */
- publicString getVOMethod(){
- return"这是User类中的一个普通方法";
- }
- }
- packagecom.jadyer.vo;
- publicclassAddress {
- //如果将TIPS设为private的话,loginSuc.jsp中就无法获取它的属性值了
- //事实上将一个静态的final属性设为private是毫无意义的
- //因为既然设置成了静态,那么就是供他人调用的,如果再设成private的话,别的地方根本就无法调用了
- //即使OGNL再怎么强大,它也不可能违反Java的规则,所以不要将静态的属性设为私有
- publicstaticfinalString TIPS ="玄玉加油!!";
- //addr属性的setter和getter略
- privateString addr;
- }
- packagecom.jadyer.vo;
- publicclassStudent {
- privateString username;
- privateintgrade;
- /* 两个属性的setter和getter略 */
- //只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法
- //因为框架默认的都会去调用无参的空的构造方法
- publicStudent(){};
- publicStudent(String username,intgrade){
- this.username = username;
- this.grade = grade;
- }
- @Override
- publicString toString() {
- //如果不重写它的toString()方法的话,默认调用toString()将输出【类型+@+内存地址的哈希值】
- return"{学生姓名:"+ username +",成绩:"+ grade +"}";
- }
- }
- packagecom.jadyer.vo;
- publicclassUser{
- privateStringusername;
- privateStringpassword;
- privateAddressaddress;
- /*三个属性的setter和getter略*/
- publicStringgetVOMethod(){
- return"这是User类中的一个普通方法";
- }
- }
- packagecom.jadyer.vo;
- publicclassAddress{
- //如果将TIPS设为private的话,loginSuc.jsp中就无法获取它的属性值了
- //事实上将一个静态的final属性设为private是毫无意义的
- //因为既然设置成了静态,那么就是供他人调用的,如果再设成private的话,别的地方根本就无法调用了
- //即使OGNL再怎么强大,它也不可能违反Java的规则,所以不要将静态的属性设为私有
- publicstaticfinalStringTIPS="玄玉加油!!";
- //addr属性的setter和getter略
- privateStringaddr;
- }
- packagecom.jadyer.vo;
- publicclassStudent{
- privateStringusername;
- privateintgrade;
- /*两个属性的setter和getter略*/
- //只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法
- //因为框架默认的都会去调用无参的空的构造方法
- publicStudent(){};
- publicStudent(Stringusername,intgrade){
- this.username=username;
- this.grade=grade;
- }
- @Override
- publicStringtoString(){
- //如果不重写它的toString()方法的话,默认调用toString()将输出【类型+@+内存地址的哈希值】
- return"{学生姓名:"+username+",成绩:"+grade+"}";
- }
- }
最后是用来提供OGNL测试的数据的LoginAction.java
- packagecom.jadyer.action;
- importjava.util.ArrayList;
- importjava.util.HashMap;
- importjava.util.HashSet;
- importjava.util.List;
- importjava.util.Map;
- importjava.util.Set;
- importorg.apache.struts2.interceptor.RequestAware;
- importorg.apache.struts2.interceptor.SessionAware;
- importcom.jadyer.vo.Student;
- importcom.jadyer.vo.User;
- importcom.opensymphony.xwork2.ActionSupport;
- @SuppressWarnings({"serial","unchecked"})
- publicclassLoginActionextendsActionSupportimplementsRequestAware,SessionAware {
- privateUser user;
- privateList testList =newArrayList();
- privateSet testSet =newHashSet();
- privateMap testMap =newHashMap();
- privateList stus =newArrayList();
- /* 以上五个属性的setter和getter略 */
- privateMap request;
- privateMap session;
- publicvoidsetRequest(Map request) {
- this.request = request;
- }
- publicvoidsetSession(Map session) {
- this.session = session;
- }
- publicstaticString getStatic(){
- return"这是LoginAction中的一个静态方法";
- }
- publicString getCommon(){
- return"这是LoginAction中的一个普通方法";
- }
- @Override
- publicString execute()throwsException {
- if(user.getUsername().trim().equalsIgnoreCase("admin") && user.getPassword().equals("jadyer")){
- testList.add("list11");
- testList.add("list22");
- testList.add("list33");
- testList.add("list44");
- testList.add("list55");
- testSet.add("set11");
- testSet.add("set22");
- testSet.add("set33");
- testSet.add("set22");
- testSet.add("set11");
- testMap.put("m11","map11");
- testMap.put("m22","map22");
- testMap.put("m33","map33");
- testMap.put("m44","map44");
- testMap.put("m55","map55");
- stus.add(newStudent("张三",88));
- stus.add(newStudent("李四",77));
- stus.add(newStudent("王五",66));
- stus.add(newStudent("马六",55));
- request.put("req","这是通过OGNL中的#号获取的request属性范围的值");
- session.put("ses","这是通过OGNL中的#号获取的session属性范围的值");
- request.put("BB","这是通过OGNL中的#号获取的request属性范围的BB");
- session.put("BB","这是通过OGNL中的#号获取的session属性范围的BB");
- returnSUCCESS;
- }else{
- returnINPUT;
- }
- }
- }
浅析值栈
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"/>就可以取到值了
辅助参考:http://blog.csdn.net/jadyer/archive/2010/09/16/5887509.aspx
手工向值栈中压入对象
正常情况下值栈保存的是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')}获取国际化信息
辅助参考:http://blog.csdn.net/jadyer/archive/2010/09/16/5887545.aspx
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文件
- <?xmlversion="1.0"encoding="UTF-8"?>
- <web-appversion="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <welcome-file-list>
- <welcome-file>login.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
- <?xmlversion="1.0"encoding="UTF-8"?>
- <web-appversion="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <welcome-file-list>
- <welcome-file>login.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
然后是用于输入用户名和密码等信息的测试页面login.jsp
- <%@ pagelanguage="java"pageEncoding="UTF-8"%>
- <h1>这是测试OGNL使用的登录页面</h1>
- <h3><fontcolor="red">提示:</font>程序设定的用户名和密码各为<fontcolor="blue"><strong>admin</strong></font>和<fontcolor="blue"><strong>jadyer</strong></font></h3>
- <h3><fontcolor="red">注意:</font>用户名和密码不正确时将停留在页面不动</h3>
- <formaction="<%=request.getContextPath()%>/login.action"method="POST">
- <%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%>
- <%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%>
- 姓名:<inputtype="text"name="user.username"><br>
- 密码:<inputtype="text"name="user.password"><br>
- 地址:<inputtype="text"name="user.address.addr"><br>
- <inputtype="submit"value="测试OGNL的输出">
- </form>
- <%@pagelanguage="java"pageEncoding="UTF-8"%>
- <h1>这是测试OGNL使用的登录页面</h1>
- <h3><fontcolor="red">提示:</font>程序设定的用户名和密码各为<fontcolor="blue"><strong>admin</strong></font>和<fontcolor="blue"><strong>jadyer</strong></font></h3>
- <h3><fontcolor="red">注意:</font>用户名和密码不正确时将停留在页面不动</h3>
- <formaction="<%=request.getContextPath()%>/login.action"method="POST">
- <%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%>
- <%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%>
- 姓名:<inputtype="text"name="user.username"><br>
- 密码:<inputtype="text"name="user.password"><br>
- 地址:<inputtype="text"name="user.address.addr"><br>
- <inputtype="submit"value="测试OGNL的输出">
- </form>
然后是用于显示OGNL处理结果的loginSuc.jsp页面
- <%@ pagelanguage="java"pageEncoding="UTF-8"%>
- <%@ taglibprefix="s"uri="/struts-tags"%>
- <h1>这是使用OGNL输出的结果页面</h1>
- <tableborder="9">
- <tr>
- <tdalign="right">获取姓名属性:</td>
- <tdalign="left"><s:propertyvalue="user.username"/></td>
- <%-- 另外还有两种写法也是可以正常输出值栈中对象的普通属性的 --%>
- <%--<s:propertyvalue="user['username']"/>--%>
- <%--<s:propertyvalue="user[/"username/"]"/>--%>
- <%-- 但是如果写成下面这种形式的话,就什么都不会输出了 --%>
- <%--<s:propertyvalue="user[username]"/>--%>
- </tr>
- <tr>
- <tdalign="right">获取地址属性:</td>
- <tdalign="left"><s:propertyvalue="user.address.addr"/></td>
- </tr>
- <tr>
- <tdalign="right">调用值栈中的对象的普通方法:</td>
- <tdalign="left"><s:propertyvalue="user.getVOMethod()"/></td>
- </tr>
- <tr>
- <tdalign="right">调用值栈中Action的普通方法:</td>
- <tdalign="left"><s:propertyvalue="getCommon()"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取普通类的静态属性:</td>
- <tdalign="left"><s:propertyvalue="@com.jadyer.vo.Address@TIPS"/></td>
- </tr>
- <tr>
- <tdalign="right">访问普通类的构造方法:</td>
- <tdalign="left"><s:propertyvalue="new com.jadyer.vo.Student('张小三',22).username"/></td>
- </tr>
- <tr>
- <tdalign="right">调用Action中的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@com.jadyer.action.LoginAction@getStatic()"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@java.util.Calendar@getInstance().time"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@java.lang.Math@floor(46.58)"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@@floor(46.58)"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testList"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Set中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testSet"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testMap"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中的某个元素:</td>
- <tdalign="left"><s:propertyvalue="testMap['m22']"/></td>
- <%-- 另外还有两种写法也是可以正常获取Map中的某个具体元素的 --%>
- <%--<s:propertyvalue="testMap.m22"/>--%>
- <%--<s:propertyvalue="testMap[/"m22/"]"/>--%>
- </tr>
- <tr>
- <tdalign="right">获取Set中的某个元素:</td>
- <%-- 由于Set中的元素是无顺序的,所以不能使用下标获取数据,所以这里什么也得不到 --%>
- <tdalign="left"><s:propertyvalue="testSet[2]"/></td>
- </tr>
- <tr>
- <tdalign="right">获取List中的某个元素:</td>
- <tdalign="left"><s:propertyvalue="testList[2]"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List的大小:</td>
- <tdalign="left"><s:propertyvalue="testList.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Set的大小:</td>
- <tdalign="left"><s:propertyvalue="testSet.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map的大小:</td>
- <tdalign="left"><s:propertyvalue="testMap.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中所有的键:</td>
- <tdalign="left"><s:propertyvalue="testMap.keys"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中所有的值:</td>
- <tdalign="left"><s:propertyvalue="testMap.values"/></td>
- </tr>
- <tr>
- <tdalign="right">Lambda计算4的阶乘:</td>
- <tdalign="left"><s:propertyvalue="#f= :[#this==1?1 : #this*#f(#this-1)],#f(4)"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List中的所有对象:</td>
- <tdalign="left"><s:propertyvalue="stus"/></td>
- </tr>
- <tr>
- <tdalign="right">利用投影获取List中对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用投影获取List中第二个对象的名字:</td>
- <%-- 使用<s:propertyvalue="stus[1].{username}"/>获取到的值为:[李四] --%>
- <%-- 二者的区别在于:后者比前者多了一个中括号 --%>
- <tdalign="left">
- <s:propertyvalue="stus.{username}[1]"/>
- <s:propertyvalue="stus[1].{username}"/>
- </td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的所有对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的最后一个对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的所有对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第二个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}[1]"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的最后一个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象然后求大小:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}.size"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">利用OGNL中的#号获取attr中的属性:</td>
- <tdalign="left"><s:propertyvalue="#attr.BB"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取request范围中的属性:</td>
- <tdalign="left"><s:propertyvalue="#request.req"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取session范围中的属性:</td>
- <tdalign="left"><s:propertyvalue="#session.ses"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取Paraments对象的属性:</td>
- <tdalign="left"><s:propertyvalue="#parameters.netname"/></td>
- </tr>
- <tr>
- <tdalign="right">使用<%=request.getParameter("")%>或者${param.name}获取链接参数值:</td>
- <tdalign="left">
- ${param.netname}
- <%=request.getParameter("netname")%>
- </td>
- </tr>
- <tr>
- <tdalign="right">查看值栈中的信息:</td>
- <tdalign="left"><s:debug/></td>
- </tr>
- </table>
- <%@pagelanguage="java"pageEncoding="UTF-8"%>
- <%@taglibprefix="s"uri="/struts-tags"%>
- <h1>这是使用OGNL输出的结果页面</h1>
- <tableborder="9">
- <tr>
- <tdalign="right">获取姓名属性:</td>
- <tdalign="left"><s:propertyvalue="user.username"/></td>
- <%--另外还有两种写法也是可以正常输出值栈中对象的普通属性的--%>
- <%--<s:propertyvalue="user['username']"/>--%>
- <%--<s:propertyvalue="user[/"username/"]"/>--%>
- <%--但是如果写成下面这种形式的话,就什么都不会输出了--%>
- <%--<s:propertyvalue="user[username]"/>--%>
- </tr>
- <tr>
- <tdalign="right">获取地址属性:</td>
- <tdalign="left"><s:propertyvalue="user.address.addr"/></td>
- </tr>
- <tr>
- <tdalign="right">调用值栈中的对象的普通方法:</td>
- <tdalign="left"><s:propertyvalue="user.getVOMethod()"/></td>
- </tr>
- <tr>
- <tdalign="right">调用值栈中Action的普通方法:</td>
- <tdalign="left"><s:propertyvalue="getCommon()"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取普通类的静态属性:</td>
- <tdalign="left"><s:propertyvalue="@com.jadyer.vo.Address@TIPS"/></td>
- </tr>
- <tr>
- <tdalign="right">访问普通类的构造方法:</td>
- <tdalign="left"><s:propertyvalue="newcom.jadyer.vo.Student('张小三',22).username"/></td>
- </tr>
- <tr>
- <tdalign="right">调用Action中的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@com.jadyer.action.LoginAction@getStatic()"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@java.util.Calendar@getInstance().time"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@java.lang.Math@floor(46.58)"/></td>
- </tr>
- <tr>
- <tdalign="right">调用JDK中的类的静态方法:</td>
- <tdalign="left"><s:propertyvalue="@@floor(46.58)"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testList"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Set中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testSet"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中的所有元素:</td>
- <tdalign="left"><s:propertyvalue="testMap"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中的某个元素:</td>
- <tdalign="left"><s:propertyvalue="testMap['m22']"/></td>
- <%--另外还有两种写法也是可以正常获取Map中的某个具体元素的--%>
- <%--<s:propertyvalue="testMap.m22"/>--%>
- <%--<s:propertyvalue="testMap[/"m22/"]"/>--%>
- </tr>
- <tr>
- <tdalign="right">获取Set中的某个元素:</td>
- <%--由于Set中的元素是无顺序的,所以不能使用下标获取数据,所以这里什么也得不到--%>
- <tdalign="left"><s:propertyvalue="testSet[2]"/></td>
- </tr>
- <tr>
- <tdalign="right">获取List中的某个元素:</td>
- <tdalign="left"><s:propertyvalue="testList[2]"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List的大小:</td>
- <tdalign="left"><s:propertyvalue="testList.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Set的大小:</td>
- <tdalign="left"><s:propertyvalue="testSet.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map的大小:</td>
- <tdalign="left"><s:propertyvalue="testMap.size"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中所有的键:</td>
- <tdalign="left"><s:propertyvalue="testMap.keys"/></td>
- </tr>
- <tr>
- <tdalign="right">获取Map中所有的值:</td>
- <tdalign="left"><s:propertyvalue="testMap.values"/></td>
- </tr>
- <tr>
- <tdalign="right">Lambda计算4的阶乘:</td>
- <tdalign="left"><s:propertyvalue="#f=:[#this==1?1:#this*#f(#this-1)],#f(4)"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">获取List中的所有对象:</td>
- <tdalign="left"><s:propertyvalue="stus"/></td>
- </tr>
- <tr>
- <tdalign="right">利用投影获取List中对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用投影获取List中第二个对象的名字:</td>
- <%--使用<s:propertyvalue="stus[1].{username}"/>获取到的值为:[李四]--%>
- <%--二者的区别在于:后者比前者多了一个中括号--%>
- <tdalign="left">
- <s:propertyvalue="stus.{username}[1]"/>
- <s:propertyvalue="stus[1].{username}"/>
- </td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的所有对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的最后一个对象:</td>
- <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的所有对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第二个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}[1]"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的最后一个对象的名字:</td>
- <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}.{username}"/></td>
- </tr>
- <tr>
- <tdalign="right">利用选择获取List中成绩及格的第一个对象然后求大小:</td>
- <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}.size"/></td>
- </tr>
- </table>
- <hr/>
- <tableborder="9">
- <tr>
- <tdalign="right">利用OGNL中的#号获取attr中的属性:</td>
- <tdalign="left"><s:propertyvalue="#attr.BB"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取request范围中的属性:</td>
- <tdalign="left"><s:propertyvalue="#request.req"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取session范围中的属性:</td>
- <tdalign="left"><s:propertyvalue="#session.ses"/></td>
- </tr>
- <tr>
- <tdalign="right">利用OGNL中的#号获取Paraments对象的属性:</td>
- <tdalign="left"><s:propertyvalue="#parameters.netname"/></td>
- </tr>
- <tr>
- <tdalign="right">使用<%=request.getParameter("")%>或者${param.name}获取链接参数值:</td>
- <tdalign="left">
- ${param.netname}
- <%=request.getParameter("netname")%>
- </td>
- </tr>
- <tr>
- <tdalign="right">查看值栈中的信息:</td>
- <tdalign="left"><s:debug/></td>
- </tr>
- </table>
然后是struts.xml文件
- <?xmlversion="1.0"encoding="UTF-8"?>
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
- "http://struts.apache.org/dtds/struts-2.0.dtd">
- <struts>
- <packagename="ognl"extends="struts-default">
- <actionname="login"class="com.jadyer.action.LoginAction">
- <resultname="input">/login.jsp</result>
- <resultname="success">/loginSuc.jsp?netname=hongyu</result>
- <!--
- <resultname="success"type="redirect">/loginSuc.jsp?netname=hongyu</result>
- <resultname="success"type="redirect">/loginSuc.jsp?netname=${user.username}</result>
- -->
- </action>
- </package>
- </struts>
- <?xmlversion="1.0"encoding="UTF-8"?>
- <!DOCTYPEstrutsPUBLIC
- "-//ApacheSoftwareFoundation//DTDStrutsConfiguration2.0//EN"
- "http://struts.apache.org/dtds/struts-2.0.dtd">
- <struts>
- <packagename="ognl"extends="struts-default">
- <actionname="login"class="com.jadyer.action.LoginAction">
- <resultname="input">/login.jsp</result>
- <resultname="success">/loginSuc.jsp?netname=hongyu</result>
- <!--
- <resultname="success"type="redirect">/loginSuc.jsp?netname=hongyu</result>
- <resultname="success"type="redirect">/loginSuc.jsp?netname=${user.username}</result>
- -->
- </action>
- </package>
- </struts>
接着是用到的三个VO类
- packagecom.jadyer.vo;
- publicclassUser {
- privateString username;
- privateString password;
- privateAddress address;
- /* 三个属性的setter和getter略 */
- publicString getVOMethod(){
- return"这是User类中的一个普通方法";
- }
- }
- packagecom.jadyer.vo;
- publicclassAddress {
- //如果将TIPS设为private的话,loginSuc.jsp中就无法获取它的属性值了
- //事实上将一个静态的final属性设为private是毫无意义的
- //因为既然设置成了静态,那么就是供他人调用的,如果再设成private的话,别的地方根本就无法调用了
- //即使OGNL再怎么强大,它也不可能违反Java的规则,所以不要将静态的属性设为私有
- publicstaticfinalString TIPS ="玄玉加油!!";
- //addr属性的setter和getter略
- privateString addr;
- }
- packagecom.jadyer.vo;
- publicclassStudent {
- privateString username;
- privateintgrade;
- /* 两个属性的setter和getter略 */
- //只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法
- //因为框架默认的都会去调用无参的空的构造方法
- publicStudent(){};
- publicStudent(String username,intgrade){
- this.username = username;
- this.grade = grade;
- }
- @Override
- publicString toString() {
- //如果不重写它的toString()方法的话,默认调用toString()将输出【类型+@+内存地址的哈希值】
- return"{学生姓名:"+ username +",成绩:"+ grade +"}";
- }
- }
- packagecom.jadyer.vo;
- publicclassUser{
- privateStringusername;
- privateStringpassword;
- privateAddressaddress;
- /*三个属性的setter和getter略*/
- publicStringgetVOMethod(){
- return"这是User类中的一个普通方法";
- }
- }
- packagecom.jadyer.vo;
- publicclassAddress{
- //如果将TIPS设为private的话,loginSuc.jsp中就无法获取它的属性值了
- //事实上将一个静态的final属性设为private是毫无意义的
- //因为既然设置成了静态,那么就是供他人调用的,如果再设成private的话,别的地方根本就无法调用了
- //即使OGNL再怎么强大,它也不可能违反Java的规则,所以不要将静态的属性设为私有
- publicstaticfinalStringTIPS="玄玉加油!!";
- //addr属性的setter和getter略
- privateStringaddr;
- }
- packagecom.jadyer.vo;
- publicclassStudent{
- privateStringusername;
- privateintgrade;
- /*两个属性的setter和getter略*/
- //只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法
- //因为框架默认的都会去调用无参的空的构造方法
- publicStudent(){};
- publicStudent(Stringusername,intgrade){
- this.username=username;
- this.grade=grade;
- }
- @Override
- publicStringtoString(){
- //如果不重写它的toString()方法的话,默认调用toString()将输出【类型+@+内存地址的哈希值】
- return"{学生姓名:"+username+",成绩:"+grade+"}";
- }
- }
最后是用来提供OGNL测试的数据的LoginAction.java
- packagecom.jadyer.action;
- importjava.util.ArrayList;
- importjava.util.HashMap;
- importjava.util.HashSet;
- importjava.util.List;
- importjava.util.Map;
- importjava.util.Set;
- importorg.apache.struts2.interceptor.RequestAware;
- importorg.apache.struts2.interceptor.SessionAware;
- importcom.jadyer.vo.Student;
- importcom.jadyer.vo.User;
- importcom.opensymphony.xwork2.ActionSupport;
- @SuppressWarnings({"serial","unchecked"})
- publicclassLoginActionextendsActionSupportimplementsRequestAware,SessionAware {
- privateUser user;
- privateList testList =newArrayList();
- privateSet testSet =newHashSet();
- privateMap testMap =newHashMap();
- privateList stus =newArrayList();
- /* 以上五个属性的setter和getter略 */
- privateMap request;
- privateMap session;
- publicvoidsetRequest(Map request) {
- this.request = request;
- }
- publicvoidsetSession(Map session) {
- this.session = session;
- }
- publicstaticString getStatic(){
- return"这是LoginAction中的一个静态方法";
- }
- publicString getCommon(){
- return"这是LoginAction中的一个普通方法";
- }
- @Override
- publicString execute()throwsException {
- if(user.getUsername().trim().equalsIgnoreCase("admin") && user.getPassword().equals("jadyer")){
- testList.add("list11");
- testList.add("list22");
- testList.add("list33");
- testList.add("list44");
- testList.add("list55");
- testSet.add("set11");
- testSet.add("set22");
- testSet.add("set33");
- testSet.add("set22");
- testSet.add("set11");
- testMap.put("m11","map11");
- testMap.put("m22","map22");
- testMap.put("m33","map33");
- testMap.put("m44","map44");
- testMap.put("m55","map55");
- stus.add(newStudent("张三",88));
- stus.add(newStudent("李四",77));
- stus.add(newStudent("王五",66));
- stus.add(newStudent("马六",55));
- request.put("req","这是通过OGNL中的#号获取的request属性范围的值");
- session.put("ses","这是通过OGNL中的#号获取的session属性范围的值");
- request.put("BB","这是通过OGNL中的#号获取的request属性范围的BB");
- session.put("BB","这是通过OGNL中的#号获取的session属性范围的BB");
- returnSUCCESS;
- }else{
- returnINPUT;
- }
- }
- }
相关推荐
Struts OGNL详解 Struts 2框架是基于MVC设计模式的Java Web开发框架,而OGNL(Object-Graph Navigation Language)是Struts 2中的表达式语言,用于在Action类和视图之间传递数据。这篇博客将深入探讨Struts OGNL的...
struts2 中 OGNL表达式的使用struts2 中 OGNL表达式的使用
其中,OGNL(Object-Graph Navigation Language)是Struts2中的核心表达语言,用于在视图层与模型层之间传递数据。在深入理解OGNL的源码之前,我们首先需要了解OGNL的基本概念和用法。 OGNL是一种强大的表达式语言...
在Struts2中,OGNL(Object-Graph Navigation Language)是默认表达式语言,用于访问和操作对象的属性。在OGNL表达式中,`#`、`%`和``$`符号扮演着不同的角色,它们是OGNL语法的重要组成部分。下面将详细介绍这三个...
在这个“Struts2 OGNL用法项目”中,我们将深入探讨OGNL(Object-Graph Navigation Language),它是Struts2中一个强大的表达式语言,用于在模型对象和视图之间进行数据绑定和表达式计算。 OGNL是Struts2的核心组件...
### Struts2中OGNL的使用详解 #### 一、OGNL简介 OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于获取或设置一个对象图中的属性。它在Struts2框架中扮演着极其重要的角色,是Struts2实现...
OGNL(Object-Graph Navigation Language)是Struts2框架中的一个重要组件,用于在Web应用中访问和操作Java对象的属性,调用其方法,以及执行类型转换等操作。 OGNL是对象图导航语言的缩写,它是一种功能强大的...
struts ognl 的常用用法大全.“#”主要有三种用途:
Struts2 OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,它在Struts2框架中扮演着核心角色,用于数据绑定、控制流程以及动态方法调用。这篇博文可能详细介绍了Struts2框架中OGNL的使用、工作原理...
在Struts2中,OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于数据绑定和表示层的数据交换。这篇博客文章可能详细探讨了如何在Struts2中使用OGNL来传递和操作数据。 OGNL是Struts2的核心...
这个压缩包包含的是OGNL的2版本的源代码,这对于理解Struts2框架的工作原理以及OGNL语言的实现细节非常有帮助。 OGNL的主要功能是提供一种简洁的方式来获取和设置对象的属性,甚至可以处理复杂的对象图。例如,你...
OGNL(Object-Graph Navigation Language)是Struts2中的核心表达式语言,用于在Action对象和视图之间传递数据。在这个主题中,我们将深入探讨Struts2 OGNL2.6.11的源码,了解其内部工作原理和关键功能。 首先,...
在Struts2中,OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于获取和设置对象的属性。这篇博客将深入探讨OGNL在Struts2中的应用,并通过案例"TextOgnl"来展示其工作原理。 一、OGNL的基本...
Struts2 OGNL表达式是Java开发中一个重要的知识点,尤其在Web应用程序设计中扮演着核心角色。OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,它被Struts2框架广泛用于视图层与模型层之间的数据...
Struts2_OGNL Demo 是一个用于演示Struts2框架中OGNL(Object-Graph Navigation Language)表达式语言的实例。这个项目旨在帮助开发者理解和学习如何在Struts2中使用OGNL来操纵对象和数据。OGNL是Struts2中一个重要的...
OGNL(Object-Graph Navigation Language)是Struts2框架中重要的表达式语言,它用于在应用程序中进行数据绑定和表达式求值。这篇文档将详细解释OGNL API及其在Struts2框架中的应用。 首先,OGNL是一个强大的、动态...
Struts2 OGNL表达式是Java Web开发中一个重要的概念,它是一种强大的对象图形导航语言(Object-Graph Navigation Language)。在Struts2框架中,OGNL被广泛用于视图层,作为数据绑定的主要手段,使得开发者能够方便...
Struts2 OGNL---标签详解析 都有实例 适合初学者
Struts2是一个流行的Java web框架,它利用OGNL(Object-Graph Navigation Language)作为其核心表达式语言。OGNL是一种强大的表达式语言,允许开发者在Java对象之间导航和操作数据。在Struts2中,OGNL被广泛用于访问...
在Struts2中,OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于获取和设置对象属性,它在Struts2的核心组件中扮演着至关重要的角色。本篇文章将深入探讨OGNL在Struts2.0中的应用及其重要性。 ...