WebWork的EL-对象图导航语言(Object Graph Navigation Language, 缩写为OGNL)是作为Web页面脚本的最佳选择。
一. 基本特性
1. 访问bean属性
根据JavaBean的规范,bean属性使用诸如getXxx(), setXxx(), isXxx()或者hasXxx()这样标准形式的getter方法或
setter方法。其中, isXxx()和hasXxx()形式用于boolean属性。在WebWork中,访问这些属性(不管是获取数据还是
设置数据)都使用形式为xxx的属性引用。
示例:
a. action
package ch8;
import ch4.User;
import com.opensymphony.xwork.ActionSupport;
public class OgnlTest extends ActionSupport{
private User user;
public String execute() {
user = new User();
user.setName("zs");
user.setPassword("password");
return SUCCESS;
}
//setter和getter方法
}
b. result
<action name="ognlTest" class="ch8.OgnlTest">
<result name="success">ognl.jsp</result>
</action>
c. jsp
<%@page contentType="text/html;charset=UTF-8" %>
<%@taglib uri="webwork" prefix="ww" %>
<html>
<body>
<ww:property value="user.name"/> <!--其中value中内容为ognl表达式-->
<ww:property value="user.password"/>
</body>
</html>
2. 常量
OGNL表达式常量与EL类型,
常量类型 范例
------------ --------------
char 'a'
String "hello world"
boolean true false
另String常量可以使用单引号或双引号括起来,示例:
<ww:property value="\"a\""/>并不等同于 <ww:property value='a'/>
3. 操作符
OGNL支持所有Java操作
运算 范例
------------ --------------
递增 ++foo
递减 foo++
等于 foo == bar
不等于 foo != bar
in foo in someList
not in foo not in someList
赋值(=) foo = 123
4. 方法调用
提供调用非属性相关的方法;
示例:假设ch4.User类中有一方法(静态方法亦可) :
public String sayHello() {
return "hello world";
}
使用以下形式可以在浏览器上输出:hello world
<ww:property value="user.sayHello()"/>
5. 设置数值及表达式列表
在单条语句当中执行以逗号分隔的多个表达式,最后一个表达式的返回值作为整条语句的输出结果。
例如foo值为123,而bar值为789,则以下形式输入 789:
<ww:property value="foo,bar"/>
6. 访问静态方法和类变量
使用@[className]@[Field Or Method]调用静态类变量和方法,类名必须使用包括包在内的完整类名;
示例:假设ch4.User类中有一方法(静态方法亦可) :
public static String sayHello() {
return "hello world";
}
使用以下形式可以在浏览器上输出:hello world
<ww:property value="@ch4.User@sayHello()"/>
另OGNL也可使用vs(vs代表Value Stack,就是值栈)前缀调用保存于值栈中的类的静态属性和静态方法;
<ww:property value="@vs@sayHello()"/>
一般来说,只有在一直了解值栈中包含什么对象的情况下,使用vs的形式才是有用的,否则建议使用完整的包
名和类名比较好。
7. 访问OGNL上下文及ActionContext
示例:
Java代码: OGNL表达式
------------------------------------------------------- ---------------------
ActionContext().getContext().getParameters() #parameters
ActionContext().getContext().getParameters().size() #parameters.size
((Kermit)ActionContext().getContext().get("kermit")).getAge() #kermit.age
WebWork中另提供一些更短标识符方便访问:
. parameters : 一个包含当前请求中所有HttpServletRequest参数的map;
. request : 一个包含当前请求中所有HttpServletRequest属性的map;
. session : 一个包含当前请求中所有HttpSession属性的map;
. application: 一个包含当前请求中所有ServletContext属性的map;
. attr : 一个依次从请求、会话和应用程序的Map中搜索属性的map;
示例:
a. action
package ch8;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import com.opensymphony.webwork.interceptor.ServletRequestAware;
import com.opensymphony.xwork.ActionSupport;
public class ScopeTest extends ActionSupport implements ServletRequestAware{
private HttpServletRequest request;
@Override
public void setServletRequest(HttpServletRequest arg0) {
request = arg0;
}
@Override
public String execute() {
HttpSession session = request.getSession();
ServletContext context = session.getServletContext();
request.setAttribute("req","request0");
session.setAttribute("ses","session1");
context.setAttribute("app","application2");
return SUCCESS;
}
}
b. result
<action name="scopeTest" class="ch8.ScopeTest">
<result name="success">scopeTest.jsp</result>
</action>
c. jsp
<%@page contentType="text/html;charset=UTF-8" %>
<%@taglib uri="webwork" prefix="ww" %>
Request parameter: <ww:property value="#parameters['name']"/><br>
Request attribute: <ww:property value="#request['req']"/><br>
Session attribute: <ww:property value="#session.ses"/><br>
Application attribute: <ww:property value="#application.app"/><br>
Request attribute: <ww:property value="#attr.req"/><br>
Session attribute: <ww:property value="#attr.ses"/><br>
Application attribute: <ww:property value="#attr.app"/><br>
二. 操作集合(Collections)
1. 操作列表(list)和数组(array)
Java代码 OGNL表达式
------------------------- ----------------------------------
list.get(0) list[0]
array[0] array[0]
((User)list.get(0)).getName() list[0].name
array.length array.length
list.size() list.size
list.isEmpty() list.isEmpty
除了访问列表的数值外,OGNL还可以动态地创建列表:使用大括号将元素括起来,元素间使用逗号分隔。
Java代码 OGNL表达式
------------------------- ----------------------------------
List list = new ArrayList(3); {1,3,5}
list.add(1);
list.add(3);
list.add(5);
return list;
------------------------- ----------------------------------
List list = new ArrayList(2); {"foo","bar"}[1]
list.add("foo");
list.add("bar");
return list.get(1);
2. 操作Map
Java代码 OGNL表达式
------------------------- ----------------------------------
map.get("foo") map['foo']
map.get(new Integer(1)) map[1]
User user = (User)map.get("zs"); map['zs'].name
return user.getName();
map.put("foo","bar"); map['foo']='bar'
map.size(); map.size
map.isEmpty(); map.isEmpty
除了访问Map的数值外,OGNL还可以动态地创建Map。必须在左边的大括号之前放置一个#号。
Java代码 OGNL表达式
------------------------- ----------------------------------
Map map = new HashMap(2); #{"foo":"bar","baz":"whazzit"}
map.put("foo","bar");
map.put("baz","whazzit");
return map;
Map map = new HashMap(2); #{1:"one",2:"two"}
map.put(new Integer(1),"one");
map.put(new Integer(2),"two");
return map;
Map map = new HashMap(2); #{#user1.name:#user1.mother.name,
map.put(user1.getName(),user1.getMother() #user2.name:#user2.mother.name}
.getName());
map.put(user2.getName(),user2.getMother()
.getName());
return map;
ActionContext.getContext(). #parameters['id']
getParameters().get("id");
String name = user.getName(); #session["user-"+name]
Map map = ActionContext.getContext()
.getSession();
return map.get("user-"+name);
session.put("user",user); #session['user'] = user
3. 对集合进行筛选(filtering)和投影(projecting)
筛选:以一个集合为基础生成一个新集合的技术,而新集合中只包含可以通过筛选的对象。语法:
collection.{? expression}
以上expression是真正意义上的筛选器, 会对集合中的每个对象进行求值。而#this这个特殊的变量
则是用于标识正在进行求值的对象。例,要从Kemit的孩子们中筛选出年龄等于2或者小于2的孩子,表
达式为:
#this.age <= 2
投影:根据投影规则对集合中的元素进行转换。语法:
collection.{ expression }
其中expression用来对原始集合中被循环迭代到的对象进行求值。
筛选返回的集合中的元素与原始集合中的是一样的,但数量有可能要少;
投影返回的集合中的元素与原始集合中的有可能不一样,但数量一样多;
示例:
OGNL表达式 描述
------------------------- ----------------------------------
children.{name} 投影的结果为所有孩子的姓名
children.{?#this.age > 2} 筛选的结果为年龄大于2的孩子
children.{?#this.age<=2}.{name} 选筛选出年龄小于等于2的孩子,再对结果列进行投影操作,得
到孩子的名字
children.{name +'->'+mother.name} 投影的结果为符合"名字->母亲名字"样式的字符串列表
4. "#"的多种用途
. 引用ActionContext中的值: #foo
. 动态构建Map #{1:'one',2:'two'}
. 对集合进行筛选和投影操作 children.{?#this.age > 2}
三. 表达式语言的高级特性
正是这些高级特性令WebWork能够在众多的MVC框架中脱颖而出。
1. 将值栈和表达式语言联系起来
在WebWork中,整个值栈就是上下文(context)中的根对象。WebWork提供了与OGNL特别的集成:根据表达式自动查找整
个栈(从上而下),直至找到了一个包含了所需的属性的对象。
举例:栈中有两个对象:Muppet和Person,两个对象都有name属性;Muppet有lifeSized属性而Person有salary属性。
Muppet对象在栈顶,而Person对象在其下面。如下图:
-------------------------------------
| Muppet |
| ------------ |
| name |
| lifeSized |
| |
| Person |
| ------------ |
| name |
| salary |
| |
| |
-------------------------------------
OGNL表达式 描述
------------------------- ----------------------------------
lifeSized 调用muppet.isLifeSized()
salary 调用person.getSalary()
name 因为muppet位于person之上,所以调用muppet.getName()
[1].name 由于[1]这个语法指明了WebWork将从位置1开始往下查找,所以
调用person.getName();
top 返回muppet
[1].top 由于[1]返回的是一个范围较小的值栈,而表达式top是基于它的,
所以整个表达式返回结果是person。因person位于这个新的,范围
较小的值栈的顶部。
2. 数据类型转换
OGNL表达式 描述
------------------------- ----------------------------------
#kermit.age = "25" 为一个int型变量设置String值,该String值随后会被转换为25
#kermit.name = 25 为一个String型变量设置int值,该int值随后会被转为"25"
3. 处理null属性的访问
OGNL在检测出访问了一个null对象的属性时,就会提供一种方式将null对象转化为真实对象。
4. 动态创建lambda表达式
定义语法::[...]
lambda表达式只能使用一个参数,该参数可通过#this引用。示例:
#isKermit = :[#this.name == @vs@OG_MUPPET ? true : false]
定义好之后,可将其置于OGNL上下文中,然后通过以下形式调用:
OGNL表达式 描述
------------------------- ----------------------------------
#isKermit(top) 判断位于栈顶的对象是否拥有Kermit这样的名字;
#isKermit(#kermit) kermit是Kermit类型吗?