OGNL

OGNLObject Graphic Navigation Language(对象图导航语言)的缩写,OGNL是一个开源项目,读者可以访问其官方站点www.ognl.org以获得源代码和相关资料。OGNL是一种功能强大的ELExpression Language,表达式语言),可以通过简单的表达式来访问Java对象中的属性。


OGNL
先在WebWork项目中得到应用,也是Struts 2框架视图默认的表达式语言,可以说,OGNL表达式是Struts 2框架的特点之一。

8.1  OGNL基础知识

8.1.1  OGNL的优势

同以往的技术相比,OGNL有哪些优势呢?总结起来有如下几个方面。
 
—  OGNL是将视图元素(例如textfieldcombobox等)同模型对象绑定在一起的一种语言。使用OGNL的类型转换功能,会使类型转换变得更加简单(例如将一个字符串类型转换为一个整数类型)。
 
—  表格元素同Swing TableModel对应的一种数据源语言。
 
—  可以将Web页面元素同后台服务器业务对象对应起来。
 
—  JSTLJSP标准标签库)表达更加丰富。

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;
import java.util.Date;
//
团队类
public class Team {
//
团队名称
private String teamname;
//
定义团队人员属性
private Person person;
//
团队人数
private int personnum;
//
属性的gettersetter方法
public String getTeamname() {
return teamname;
}
public void setTeamname(String teamname) {
this.teamname = teamname;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public int getPersonnum() {
return personnum;
}
public void setPersonnum(int personnum) {
this.personnum = personnum;
}
}
//
定义人员类
class Person {
//
姓名
private String name;
//
年龄
private int age;
//
人员出生日期
private Date birthday;
//
属性的gettersetter方法
public String getName() {
return name;
}
public  void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}

代码8.1所示内容定义了两个复合类型:团队(team)和人员(person)类型。使用OGNL表达式示例,如代码8.2所示。

代码8.2  使用OGNL表达式示例

 package ch8;
import java.util.HashMap;
import java.util.Map;
import ognl.Ognl;
import ognl.OgnlException;
public class TestOGNL {
public static void main(String[] args) {
//
定义一个Map对象
Map m = new HashMap();
//
定义一个Team对象
Team team1 = new Team();
team1.setTeamname("
团队1");
//
定义一个Person对象
Person person1 = new Person();
person1.setName("pla1");
//
添加team元素
team1.setPerson(person1);
//
定义一个Team对象
Team team2 = new Team();
team2.setTeamname("
团队2");
//
定义一个Person对象
Person person2 = new Person();
person2.setName("pla2");
//
添加team元素
team2.setPerson(person2);

//
添加Map元素
m.put("team1", team1);
m.put("team2", team2);
try {
System.out.println(Ognl.getValue("team1.teamname", m));
System.out.println(Ognl.getValue("team2.person.name", m));
System.out.println(Ognl.getValue("teamname", team2));
System.out.println(Ognl.getValue("person.name", team2));
} catch (OgnlException e) {
}
}
}


代码8.2所示内容定义了一个Map类型的嵌套属性,如图8.1所示。

  

8.1  嵌套属性示意图

运行该示例,控制器显示如下信息:

 团队1
pla2
团队2
pla2

说明

OGNL可以使用非常简单的表达式来访问多层嵌套属性,为开发者提供了一个有力的工具。

8.2  Struts 2OGNL

OGNLStruts 2框架的默认表达式语言,增强了Struts 2的数据访问能力,同时简化了代码。

8.2.1  Struts 2OGNL表达式

标准的OGNL会设定一个根对象(root对象)。假设使用标准OGNL表达式来求值(不使用Struts 2OGNL表达式),如果OGNL上下文(OgnlContext Map类型)有两个对象:foo对象,在OgnlContext中名称为foobar对象,在OgnlContext中名称为bar。同时foo对象被设置为根对象(root)。则利用下面的OGNL表达式求值:

// 返回foo.getBlah()
#foo.blah
//
返回bar.getBlah()
#bar.blah
//
返回foo.getBlah() ,因为foo为根对象
blah

说明

使用OGNL是非常简单的,如果要访问的对象不是根对象,如示例中的bar对象,则需要使用命名空间,用“#”来标识,如“#bar”;如果访问一个根对象,则不用指定命名空间,可以直接访问根对象的属性。

Struts 2框架中,值栈(Value Stack)就是OGNL的根对象,假设值栈中存在两个对象实例:ManAnimal,这两个对象实例都有一个name属性,Animal有一个species属性,Man有一个salary属性,假设Animal在值栈的顶部,ManAnimal后面,下面的代码片断会帮助读者更好地理解OGNL表达式:

 // 调用animal.getSpecies()
species
//
调用man.getSalary()
salary
//
调用animal.getName(),因为Animal位于值栈的顶部
name

最后一行示例代码,返回的是animal.getName()返回值,即返回了Animalname属性,因为Animal是值栈的顶部元素,OGNL将从顶部元素搜索,所以会返回Animalname属性值。如果要获得Manname值,则需要如下代码:

 man.name

Struts 2允许在值栈中使用索引,示例代码如下所示:

[0].name   // 调用animal.getName()
[1].name   //
调用man.getName()

注意

使用索引,并不是直接获得指定的元素,而是从指定的索引位置搜索。

Struts 2中的OGNL ContextActionContext,如图8.2所示。

  

8.2  Struts 2OGNL Context结构示意图

说明

8.2只是说明Struts 2OGNL Context结构,实际上Context还包含其他对象。

由于值栈是Struts 2OGNL的根对象,如果用户需要访问值栈中的对象,则可以直接通过下面的代码访问值栈中的属性:

//获得值栈中的foo属性
${foo}

如果访问其他Context中的对象,由于不是根对象,在访问时,需要加#前缀。
 
—  application对象:用于访问ServletContext,例如#application.userName或者#application['userName'],相当于调用ServletgetAttribute("username")
 
—   session对象:用来访问HttpSession,例如#session.userName或者#session['userName'],相当于调用session.getAttribute("userName")
 
—  request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request['userName'],相当于调用request.getAttribute ("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个元素:e1e2e3。如果需要更多的元素,可以按照这样的格式定义多个元素,多个元素之间使用逗号隔开。

如下代码可以直接生成一个Map对象:

#{key1:value1,key2:value2,…}


Map
类型的集合对象,使用key-value格式定义,每个key-value元素使用冒号标识,多个元素之间使用逗号隔开。

对于集合类型,OGNL表达式可以使用innot in两个元素符号。其中,in表达式用来判断某个元素是否在指定的集合对象中;not in判断某个元素是否不在指定的集合对象中,如代码8.3所示。

代码8.3  使用OGNL集合操作符

 
muhahaha


boo


muhahaha


boo

除了innot in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个相关操作符。
 
—  ?:获得所有符合逻辑的元素。
 
—  ^:获得符合逻辑的第一个元素。
 
—  $:获得符合逻辑的最后一个元素。

例如代码:

person.relatives.{? #this.gender == 'male'}

该代码可以获得person的所有性别为malerelatievs集合。

8.2.3  Lambda表达式

OGNL支持基本的Lambda表达式语法,通过Lambda表达式语法,可以在OGNL中使用一些简单的函数。例如:

Fibonacci:
if n==0 return 0;
elseif n==1 return 1;
else return fib(n-2)+fib(n-1);
fib(0) = 0
fib(1) = 1
fib(11) = 89

开发者可以使用Lambda表达式语法:

 

8.3  Struts 2中使用OGNL

在这里,笔者以一个示例来演示Struts 2如何使用OGNL表达式。

8.3.1  业务控制器

为本示例建立一个业务控制器,该控制器用到了代码8.1中定义的Person人员信息类。该业务控制器如代码8.4所示。

代码8.4  Struts 2OGNL示例业务控制器

package ch8;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class OgnlAction extends ActionSupport {
//List
类型属性
private List persons;
//execute
方法
public String execute() throws Exception {
//
获得ActionContext实例,以便访问Servlet API
ActionContext ctx = ActionContext.getContext();
//
存入application
ctx.getApplication().put("msg", "application
信息");
//
保存session
ctx.getSession().put("msg", "seesion
信息");
//
保存request信息
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("msg", "request
信息");
//
persons赋值
persons = new LinkedList();
Person person1=new Person();
person1.setName("pla1");
person1.setAge(26);
person1.setBirthday(new Date());
 persons.add(person1);
 
 Person person2=new Person();
 person2.setName("pla2");
person2.setAge(36);
person2.setBirthday(new Date());
 persons.add(person2);
 Person person3=new Person();
 person3.setName("pla3");
person3.setAge(16);
person3.setBirthday(new Date());
 persons.add(person3);
 return SUCCESS;
}
public List getPersons() {
return persons;
}
public void setPersons(List persons) {
this.persons = persons;
}
}

该业务控制器分别在applicationsessionrequest中存入名为“msg”的字符串信息,另外定义了一个List类型属性,同时添加了两个Person类型元素。在配置文件中增加了相应的配置,代码如下:


/ch8/showognl.jsp

8.3.2  JSP视图

showognl.jsp是使用了OGNL表达式的JSP视图,视图用来显示Action中处理的各种信息,读者可以看到,使用OGNL表达式,代码更加简洁和直观,如代码8.5所示。

代码8.5  使用OGNL表达式的JSP视图



http://www.w3.org/TR/ xhtml1/DTD/xhtml1-transitional.dtd">
http://www.w3.org/1999/xhtml">



   

访问OGNL上下文和Action上下文



parameters:

 

request.msg:

 

session.msg:

 

application.msg:

 

attr.msg:

 


 

用于过滤和投影(projecting)集合

 

年龄大于20

 




1.                         - 年龄:


 

姓名为pla1的年龄:

 


 

构造Map



The value of key "foo1" is

 

8.3.3  运行示例

在浏览器中输入http://localhost:8080/bookcode/ch8/OgnlAction.action?msg=hello,运行结果如图8.3所示。

 

8.3  Struts 2中使用OGNL表达式

说明

本示例演示了如何使用OGNL表达式来访问OGNL上下文和值栈,同时演示了如何使用OGNL表达式进行集合操作。对读者深入理解Struts 2OGNL表达式的使用有所帮助。

8.3.4  OGNL中的#%$符号

#%$符号在OGNL表达式中经常出现,而这三种符号也是开发者不容易掌握和理解的部分。在这里笔者简单介绍它们的相应用途。


1
#符号

#符号的用途一般有三种。
 
—  访问非根对象属性,例如示例中的#session.msg表达式,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀。实际上,#相当于ActionContext. getContext()#session.msg表达式相当于ActionContext.getContext().getSession(). getAttribute("msg")
 
—  用于过滤和投影(projecting)集合,如示例中的persons.{?#this.age>20}
 
—  用来构造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}

2%符号

%符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。如下面的代码所示:

构造Map



The value of key "foo1" is

 

不使用%:

 

使用%:

运行界面如图8.4所示。

 

8.4 “%”OGNL表达式用法

3$符号

$符号主要有两个方面的用途。
 
—  在国际化资源文件中,引用OGNL表达式,例如国际化资源文件中的代码:reg.agerange=国际化资源信息:年龄必须在${min}${max}之间。
 
—  Struts 2框架的配置文件中引用OGNL表达式,例如下面的代码片断所示:

 


10
100
BAction-test
校验:数字必须为${min}${max}之间!



8.4  本章小结

对于Struts 1.x开发者来说,OGNL是一个陌生的事物,而OGNL也正是Struts 2框架的特点之一,OGNLStruts 2框架内置的表达式语言,读者需要掌握以下知识点:
 
—  理解OGNL的优势;
 
—  掌握基本的OGNL表达式;
 
—  理解Struts 2OGNL的特点;
 
—  掌握OGNL常用的表达式。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值