package com.demo.ognl;
public class User {
private int age = 8;
public User() {}
public User(int age) {
super();
this.age = age;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "user" + age;
}
}
package com.demo.ognl;
public class S {
public static String STR = "STATIC STRING";
public static String s() {
return "static method" ;
}
}
OGNL
<constant name="struts.ognl.allowStaticMethodAccess" value="true"/> 在struts2.1 设置 就是说明允许静态方法访问
package com.demo.ognl;
public class Cat {
private Dog friend;
public Dog getFriend() {
return friend;
}
public void setFriend(Dog friend) {
this.friend = friend;
}
public String miaomiao() {
return "miaomiao" ;
}
}
package com.demo.ognl;
public class Dog {
private String name;
public Dog() {}
public Dog(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "dog: " + name;
}
}
package com.demo.ognl;
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 com.opensymphony.xwork2.ActionSupport;
public class OgnlAction extends ActionSupport {
private Cat cat = new Cat();
private Map<String, Dog> dogMap = new HashMap<String,Dog>();
private Set<Dog> dogs = new HashSet<Dog>();
private String password;
private User user;
private String username;
private List<User> users = new ArrayList<User>() ;
public OgnlAction() {
users.add(new User(1));
users.add(new User(2));
users.add(new User(3));
dogs.add(new Dog("dog1"));
dogs.add(new Dog("dog2"));
dogs.add(new Dog("dog3"));
dogMap.put("dog100", new Dog("dog100"));
dogMap.put("dog101", new Dog("dog101"));
dogMap.put("dog102", new Dog("dog102"));
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
public String m() {
return "hello";
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Map<String, Dog> getDogMap() {
return dogMap;
}
public void setDogMap(Map<String, Dog> dogMap) {
this.dogMap = dogMap;
}
public Set<Dog> getDogs() {
return dogs;
}
public void setDogs(Set<Dog> dogs) {
this.dogs = dogs;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
<?xml version="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>
<package name="ognl" extends="struts-default">
<action name="ognl" class="com.demo.ognl.OgnlAction">
<result>/ognl.jsp</result>
</action>
<action name="test" class="com.demo.ognl.TestAction">
<result type="chain">ognl</result>
</action>
</package>
</struts>
<?xml version="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>
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
<constant name="struts.devMode" value="true"/>
<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
<include file="/com/demo/ognl/ognl.xml"/>
</struts>
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@taglib uri="/struts-tags" prefix="s" %>
<html>
<head>
</head>
<body>
<ol>
<li>访问值栈中的action的普通属性: username = <s:property value="username"/></li>
<li>访问值栈中对象的普通属性(get set方法):<s:property value="user.age"/>
| <s:property value="user['age']"/> | <s:property value="user[\"age\"]"/>
| wrong: <%--<s:property value="user[age]"/>--%></li>
<li>访问值栈中对象的普通:(get set方法): <s:property value="cat.friend.name"/></li>
<li>访问值栈中对象的普通方法:<s:property value="password.length()"/></li>
<li>访问值栈中对象的普通方法:<s:property value="cat.miaomiao()"/></li>
<li>访问值栈中action的普通方法: <s:property value="m()"/></li>
<hr/>
<li>访问静态方法: <s:property value="@com.demo.ognl.S@s()"/></li>
<li>访问静态属性: <s:property value="@com.demo.ognl.S@STR"/></li>
<li>访问Math类的静态方法: <s:property value="@@max(2,3)"/></li>
<hr/>
<li>访问普通类的构造方法: <s:property value="new com.demo.ognl.User(8)"/></li>
<hr/>
<li>访问List:<s:property value="users"/></li>
<li>访问List中某个元素: <s:property value="users[1]"/></li>
<li>访问List中元素的某个属性的集合: <s:property value="users.{age}"/></li>
<li>访问List中元素某个属性的集合中的特定值: <s:property value="users.{age}[0]"/> | <s:property value="users[0].age"/></li>
<li>访问Set:<s:property value="dogs"/></li>
<li>访问Set中某个元素: <s:property value="dogs[1]"/></li> |取不到值是因为set是无顺序的、没意义
<li>访问Map: <s:property value="dogMap"/></li> | 重写了toString方法
<li>访问Map中某个元素: <s:property value="dogMap.dog101"/> | <s:property value="dogMap['dog101']"/>
| <s:property value="dogMap[\"dog101\"]"/> </li>
<li>访问Map中所有的key: <s:property value="dogMap.keys"/></li>
<li>访问Map中所有的value:<s:property value="dogMap.values"/></li>
<li>访问容器的大小: <s:property value="dogMap.size()"/> | <s:property value="users.size"/></li>
<hr/>
<li>投影(过滤): <s:property value="users.{?#this.age==1}[0]"/></li>
<li>投影:<s:property value="users.{^#this.age > 1}.{age}"/></li>
<li>投影: <s:property value="users.{$#this.age > 1}.{age}"/></li>
<li>投影: <s:property value="users.{$#this.age > 1}.{age} == null"/></Li>
<hr/>
<li>[]: <s:property value="[0].username"/></li>
</ol>
<s:debug></s:debug>
</body>
</html>
8.1.2 OGNL语法
基本的OGNL语法是十分简单的,当然OGNL支持丰富的表达式,一般情况下,不用担心OGNL的复杂性。例如有一个man对象,该对象有一个name属性,那么使用OGNL来获得该name属性可以使用如下表达式:
man.name |
OGNL表达式的基础单元称为导航链,简称为链。一个最简单的链由如下部分组成。
—
属性名称:如上述示例中的name。
—
方法调用:hashCode()返回当前对象的hash code。
—
数组元素:listeners[0]返回当前对象的监听器列表中的第一个元素。
★ 说明 ★
OGNL表达式基于OGNL上下文中的当前对象,一个“链”将使用上一个“链”的处理结果,开发者可以任意扩展该链的长度,OGNL没有限制。
例如,一个OGNL表达式如下:
name.toCharArray()[0].numericValue.toString() |
该表达式将按照如下步骤求值。
(1)获得OGNL Context中初始对象或者是根对象(root对象)的name对象。
(2)调用toCharArray()方法,返回一个String类型对象。
(3)获得该String对象的第一个字符。
(4)获得该字符的numericValue属性(该字符为一个Character对象,该对象有一个getNumericValue()方法,该方法返回一个Integer类型值)。
(5)将获得的Integer对象转换为一个String类型值(使用toString()方法)。
8.1.3 一个使用OGNL的示例
下面笔者以一个简单的示例来帮助读者理解OGNL表达式。使用OGNL表达式,需要在www.ognl.org网站下载一个ognl.jar插件包,将该文件复制到classpath路径下即可。建立一个复合类型,如代码8.1所示。
代码8.1 定义复合类型
package ch8; |
代码8.1所示内容定义了两个复合类型:团队(team)和人员(person)类型。使用OGNL表达式示例,如代码8.2所示。
代码8.2 使用OGNL表达式示例
package ch8; |
代码8.2所示内容定义了一个Map类型的嵌套属性,如图8.1所示。
运行该示例,控制器显示如下信息:
团队1 |
★ 说明 ★
OGNL可以使用非常简单的表达式来访问多层嵌套属性,为开发者提供了一个有力的工具。
8.2 Struts 2的OGNL
OGNL是Struts 2框架的默认表达式语言,增强了Struts 2的数据访问能力,同时简化了代码。
8.2.1 Struts 2的OGNL表达式
标准的OGNL会设定一个根对象(root对象)。假设使用标准OGNL表达式来求值(不使用Struts 2的OGNL表达式),如果OGNL上下文(OgnlContextMap类型)有两个对象:foo对象,在OgnlContext中名称为foo;bar对象,在OgnlContext中名称为bar。同时foo对象被设置为根对象(root)。则利用下面的OGNL表达式求值:
// 返回foo.getBlah() |
★ 说明 ★
使用OGNL是非常简单的,如果要访问的对象不是根对象,如示例中的bar对象,则需要使用命名空间,用“#”来标识,如“#bar”;如果访问一个根对象,则不用指定命名空间,可以直接访问根对象的属性。
在Struts2框架中,值栈(Value Stack)就是OGNL的根对象,假设值栈中存在两个对对象实例:Man和Animal,这两个对象实例都有一个name属性,Animal有一个species属性,Man有一个salary属性,假设Animal在值栈的顶部,Man在Animal后面,下面的代码片断会帮助读者更好地理解OGNL表达式:
// 调用animal.getSpecies() |
最后一行示例代码,返回的是animal.getName()返回值,即返回了Animal的name属性,因为Animal是值栈的顶部元素,OGNL将从顶部元素搜索,所以会返回Animal的name属性值。如果要获得Man的name值,则需要如下代码:
man.name |
Struts 2允许在值栈中使用索引,示例代码如下所示:
[0].name // 调用animal.getName() |
★ 注意 ★
使用索引,并不是直接获得指定的元素,而是从指定的索引位置搜索。
Struts 2中的OGNL Context是ActionContext,如图8.2所示。
★ 说明 ★
图8.2只是说明Struts 2的OGNL Context结构,实际上Context还包含其他对象。
由于值栈是Struts 2中OGNL的根对象,如果用户需要访问值栈中的对象,则可以直接通过下面的代码访问值栈中的属性:
//获得值栈中的foo属性 |
如果访问其他Context中的对象,由于不是根对象,在访问时,需要加#前缀。
—
application对象:用于访问ServletContext,例如#application.userName或者#application['userName'],相当于调用Servlet的getAttribute("username")。
—
session对象:用来访问HttpSession,例如#session.userName或者#session['userName'],相当于调用session.getAttribute("userName")。
—
request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request['userName'],相当于调用request.get力Attribute ("userName")。
—
parameters对象:用于访问HTTP的请求参数,例如#parameters.userName或者#parameters['userName'],相当于调用request.getParameter("username")。
—
attr对象:用于按page-request-session-application顺序访问其属性。
8.2.2 OGNL的集合操作
如果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式。
可以使用如下代码直接生成一个List对象:
{e1,e2,e3…} |
该OGNL表达式中,直接生成了一个List对象,该List对象中包含3个元素:e1、e2和e3。如果需要更多的元素,可以按照这样的格式定义多个元素,多个元素之间使用逗号隔开。
如下代码可以直接生成一个Map对象:
#{key1:value1,key2:value2,…} |
Map类型的集合对象,使用key-value格式定义,每个key-value元素使用冒号标识,多个元素之间使用逗号隔开。
对于集合类型,OGNL表达式可以使用in和not in两个元素符号。其中,in表达式用来判断某个元素是否在指定的集合对象中;not in判断某个元素是否不在指定的集合对象中,如代码8.3所示。
代码8.3 使用OGNL集合操作符
|
除了in和not in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个相关操作符。
—
?:获得所有符合逻辑的元素。
—
^:获得符合逻辑的第一个元素。
—
$:获得符合逻辑的最后一个元素。
例如代码:
person.relatives.{? #this.gender == 'male'} |
该代码可以获得person的所有性别为male的relatievs集合。
8.2.3 Lambda表达式
OGNL支持基本的Lambda表达式语法,通过Lambda表达式语法,可以在OGNL中使用一些简单的函数。例如:
Fibonacci: |
开发者可以使用Lambda表达式语法: