OGNL中的#、%和$符号
#、%和$符号在OGNL表达式中经常出现,而这三种符号也是开发者不容易掌握和理解的部分。在这里我们简单介绍它们的相应用途。
1.#符号的三种用法
1)访问非根对象属性,例如示例中的#session.msg表达式,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀。实际上,#相当于ActionContext. getContext();#session.msg表达式相当于ActionContext.getContext().getSession(). getAttribute("msg") 。
2)用于过滤和投影(projecting)集合,如示例中的persons.{?#this.age>20},persons.{?#this.name=='pla1'}.{age}[0]
3) 用来构造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}。
2.%符号
%符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。如下面的代码所示:
<h3>构造Map</h3>
<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" />
<p>The value of key "foo1" is <s:property value="#foobar['foo1']" /></p>
<p>不使用%:<s:url value="#foobar['foo1']" /></p>
<p>使用%:<s:url value="%{#foobar['foo1']}" /></p>
运行界面如下所示。
he value of key "foo1" is bar1
不使用%:#foobar['foo1']
使用%:bar1
3.$符号
$符号主要有两个方面的用途。
1) 在国际化资源文件中,引用OGNL表达式,例如国际化资源文件中的代码:reg.agerange=国际化资源信息:年龄必须在${min}同${max}之间。
2) 在Struts 2框架的配置文件中引用OGNL表达式,例如下面的代码片断所示:
</pre><pre name="code" class="html"><validators>
<field name="intb">
<field-validator type="int">
<param name="min">10</param>
<param name="max">100</param>
<message>BAction-test校验:数字必须为${min}为${max}之间!</message>
</field-validator>
</field>
</validators>
总结OGNL的使用方法:
访问属性
名字属性获取:<s:property value="user.username"/><br>
地址属性获取:<s:property value="user.address.addr"/><br>
调用值栈中对象的普通方法:<s:property value="user.get()"/><br>
调用Action中的静态方法:<s:property value="@struts.action.LoginAction@get()"/>
调用JDK中的类的静态方法:<s:property value="@java.lang.Math@floor(44.56)"/><br>
调用JDK中的类的静态方法(同上):<s:property value="@@floor(44.56)"/><br>
调用JDK中的类的静态方法:<s:property value="@java.util.Calendar@getInstance()"/><br>
调用普通类中的静态属性:<s:property value="@struts.vo.Address@TIPS"/><br>
调用普通类的构造方法:<s:property value="new struts.vo.Student('李晓红' , '美女' , 3 , 25).username"/>
获取List:<s:property value="testList"/><br>
获取List中的某一个元素(可以使用类似于数组中的下标获取List中的内容):
<s:property value="testList[0]"/><br>
获取Set:<s:property value="testSet"/><br>
获取Set中的某一个元素(Set由于没有顺序,所以不能使用下标获取数据):
<s:property value="testSet[0]"/><br> ×
获取Map:<s:property value="testMap"/><br>
获取Map中所有的键:<s:property value="testMap.keys"/><br>
获取Map中所有的值:<s:property value="testMap.values"/><br>
获取Map中的某一个元素(可以使用类似于数组中的下标获取List中的内容):
<s:property value="testMap['m1']"/><br>
获取List的大小:<s:property value="testSet.size"/><br>
利用选择获取List中成绩及格的对象:<s:property value="stus.{?#this.grade>=60}"/><br>
利用选择获取List中成绩及格的对象的username:
<s:property value="stus.{?#this.grade>=60}.{username}"/><br>
利用选择获取List中成绩及格的第一个对象的username:
<s:property value="stus.{?#this.grade>=60}.{username}[0]"/><br>
利用选择获取List中成绩及格的第一个对象的username:
<s:property value="stus.{^#this.grade>=60}.{username}"/><br>
利用选择获取List中成绩及格的最后一个对象的username:
<s:property value="stus.{$#this.grade>=60}.{username}"/><br>
利用选择获取List中成绩及格的第一个对象然后求大小:
<s:property value="stus.{^#this.grade>=600}.{username}.size"/><br>
OGNL能够引用集合的一些特殊的属性,这些属性并不是JavaBeans模式,例如size(),length()等等. 当表达式引用这些属性时,OGNL会调用相应的方法,这就是伪属性.
集合 | 伪属性 |
Collection(inherited by Map, List & Set) | size ,isEmpty |
List | iterator |
Map | keys , values |
Set | iterator |
Iterator | next , hasNext |
Enumeration | next , hasNext , nextElement , hasMoreElements |
Lambda :[…]
格式::[…]
使用Lambda表达式计算阶乘:
<s:property value="#f = :[#this==1?1:#this*#f(#this-1)] , #f(4)"/><br>
#可以取出堆栈上下文中的存放的对象.
名称 | 作用 | 例子 |
parameters | 包含当前HTTP请求参数的Map | #parameters.id[0]作用相当于 request.getParameter("id") |
request | 包含当前HttpServletRequest的属性(attribute)的Map | #request.userName相当于 request.getAttribute("userName") |
session | 包含当前HttpSession的属性(attribute)的Map | #session.userName相当于 session.getAttribute("userName") |
application | 包含当前应用的ServletContext的属性(attribute)的Map | #application.userName相当于 application.getAttribute("userName") |
attr | 用于按request > session > application顺序访问其属性(attribute) |
|
获取Paraments对象的属性:<s:property value="#parameters.username"/>
OGNL中%的使用
用%{}可以取出存在值堆栈中的Action对象,直接调用它的方法.
例如你的Action如果继承了ActionSupport .那么在页面标签中,用%{getText('key')}的方式可以拿出国际化信息.
OGNL中$的使用
“$”有两个主要的用途
l 用于在国际化资源文件中,引用OGNL表达式
l 在Struts 2配置文件中,引用OGNL表达式
值栈
ValueStack对象。这个对象贯穿整个Action的生命周期(每个Action类的对象实例会拥有一个ValueStack对象)。当 Struts 2接收到一个.action的请求后,会先建立Action类的对象实例,但并不会调用Action方法,而是先将Action类的相应属性放到 ValueStack对象的顶层节点(ValueStack对象相当于一个栈)。
在Action中获得ValueStack对象:ActionContext.getContext().getValueStack()
l Top语法
使用Top获取值栈中的第二个对象:<s:property value="[1].top.对象"/>
l N语法
使用N获取值栈中的第二个对象:<s:property value="[1].对象"/>
l @语法
调用action中的静态方法:<s:property value="@vs1@静态方法"/> vs:值栈 1:表示第一个。
DEMO:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="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>
<%@ page language="java" pageEncoding="UTF-8"%>
<h1>这是测试OGNL使用的登录页面</h1>
<h3><font color="red">提示:</font>程序设定的用户名和密码各为<font color="blue"><strong>admin</strong></font>和<font color="blue"><strong>jadyer</strong></font></h3>
<h3><font color="red">注意:</font>用户名和密码不正确时将停留在页面不动</h3>
<form action="<%=request.getContextPath()%>/login.action" method="POST">
<%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%>
<%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%>
姓名:<input type="text" name="user.username"><br>
密码:<input type="text" name="user.password"><br>
地址:<input type="text" name="user.address.addr"><br>
<input type="submit" value="测试OGNL的输出">
</form>
loginSuc.jsp(用于显示OGNL处理结果)
<%@ page language="java"pageEncoding="UTF-8"%>
<%@ taglib prefix="s"uri="/struts-tags"%>
<h1>这是使用OGNL输出的结果页面</h1>
<table border="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/>
<table border="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/>
<table border="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/>
<table border="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>
用到的三个VO类
package com.jadyer.vo;
publicclass User {
private String username;
private String password;
private Address address;
/* 三个属性的setter和getter略 */
public String getVOMethod(){
return"这是User类中的一个普通方法";
}
}
package com.jadyer.vo;
publicclass Address {
//如果将TIPS设为private的话,loginSuc.jsp中就无法获取它的属性值了
//事实上将一个静态的final属性设为private是毫无意义的
//因为既然设置成了静态,那么就是供他人调用的,如果再设成private的话,别的地方根本就无法调用了
//即使OGNL再怎么强大,它也不可能违反Java的规则,所以不要将静态的属性设为私有
publicstaticfinal String TIPS = "玄玉加油!!";
//addr属性的setter和getter略
private String addr;
}
package com.jadyer.vo;
publicclass Student {
private String username;
privateint grade;
/* 两个属性的setter和getter略 */
//只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法
//因为框架默认的都会去调用无参的空的构造方法
public Student(){};
public Student(String username,int grade){
this.username = username;
this.grade = grade;
}
@Override
public String toString() {
//如果不重写它的toString()方法的话,默认调用toString()将输出【类型+@+内存地址的哈希值】
return"{学生姓名:" + username +",成绩:" + grade + "}";
}
}
LoginAction.java(用来提供OGNL测试的数据)
package com.jadyer.action;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
import com.jadyer.vo.Student;
import com.jadyer.vo.User;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings({"serial","unchecked"})
publicclass LoginActionextends ActionSupport implements RequestAware,SessionAware {
private User user;
private List testList = new ArrayList();
private Set testSet =new HashSet();
private Map testMap = new HashMap();
private List stus = new ArrayList();
/* 以上五个属性的setter和getter略 */
private Map request;
private Map session;
publicvoid setRequest(Map request) {
this.request = request;
}
publicvoid setSession(Map session) {
this.session = session;
}
publicstatic String getStatic(){
return"这是LoginAction中的一个静态方法";
}
public String getCommon(){
return"这是LoginAction中的一个普通方法";
}
@Override
public String execute() throws Exception {
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(new Student("张三",88));
stus.add(new Student("李四",77));
stus.add(new Student("王五",66));
stus.add(new Student("马六",55));
request.put("req","这是通过OGNL中的#号获取的request属性范围的值");
session.put("ses", "这是通过OGNL中的#号获取的session属性范围的值");
request.put("BB","这是通过OGNL中的#号获取的request属性范围的BB");
session.put("BB", "这是通过OGNL中的#号获取的session属性范围的BB");
return SUCCESS;
}else{
return INPUT;
}
}
}
注意:这边将这些变量进行了初始化(new)。也可以不初始化,让框架帮你初始化,你只需要完成两件事情1 属性地类型必须是一个满足javabean规范的类,因为它要提供一个没有参数的构造方法。2 属性必须要满足javabean规范,提供对应的设置方法。
参考链接:
http://www.cnblogs.com/xly1208/archive/2011/11/19/2255500.html
http://blog.csdn.net/songylwq/article/details/7568859
http://www.360doc.com/content/10/1027/10/573136_64386997.shtml
http://blog.csdn.net/wxwlife2006/article/details/8242459