OGNL的全称是Object Graph Navigation Language(对象图导航语言),它是一种强大的表达式语言,能通过简单一致的表达式语法来读取和设置Java对象的属性值,调用对象的方法,遍历整个对象的结构图,实现字段类型转换等功能。
一、为什么要使用OGNL
视图层的表达式语言通常是用来简化数据的访问操作,取代Java脚本代码,提供更清晰的视图层实现。比如,要获取user对象的age属性,利用OGNL表达式可以写成:
<s:property value="user.age"/>
而如果要换做Java脚本代码,则需要写成:
<%@ page import="com.chongqing.model.User" %>
<%
User user = (User)request.getAttribute("user");
String age = user.getAge();
out.print(age);
%>
可以看出,利用OGNL表达式会更加清晰和简洁。
二、值栈(ValueStack)
OGNL有一个上下文(Context)的概念,说白了上下文就是一个MAP结构,它实现了Java.utils.Map接口,在Struts2中上下文(Context)的实现为ActionContext ,它结构示意图如下:
|--request
|--application
OGNL context ------ | ValueStack(值栈,它是根对象)
|--session
|--attr
|--parameters
当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action 。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。
访问上下文(Context)中的对象需要使用#符号标注命名空间,如#application、#session等
另外OGNL会设定一个根对象(root对象),在Struts2中根对象就是ValueStack(值栈) 。如果要访问根对象(即ValueStack)中对象的属性,则可以省略#命名空间,直接访问该对象的属性即可。
可以通过<s:debug></s:debug>标签在浏览器上看到Context的内容,其实OGNL表达式就是用来访问Context中的内容。
三、OGNL表达式
OGNL表达式的语法多且杂,要全部总结出来有点困难,这里我偷一点懒,通过一个例子来说明,以后查阅也会方便一些。
OgnlAction类:
package com.chongqing.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;
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"));
}
public String execute() {
return SUCCESS;
}
public Cat getCat() {
return cat;
}
public Map<String, Dog> getDogMap() {
return dogMap;
}
public Set<Dog> getDogs() {
return dogs;
}
public String getPassword() {
return password;
}
public User getUser() {
return user;
}
public String getUsername() {
return username;
}
public List<User> getUsers() {
return users;
}
public String m() {
return "hello";
}
public void setCat(Cat cat) {
this.cat = cat;
}
public void setDogMap(Map<String, Dog> dogMap) {
this.dogMap = dogMap;
}
public void setDogs(Set<Dog> dogs) {
this.dogs = dogs;
}
public void setPassword(String password) {
this.password = password;
}
public void setUser(User user) {
this.user = user;
}
public void setUsername(String username) {
this.username = username;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
User类:
package com.chongqing.ognl;
public class User {
private int age = 8;
public User() {
}
public User(int age) {
super();
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "user" + age;
}
}
Cat类:
package com.chongqing.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";
}
}
Dog类:
package com.chongqing.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;
}
}
S类:
package com.chongqing.ognl;
public class S {
public static String STR = "STATIC STRING";
public static String s() {
return "static method";
}
}
ognl.jsp:
<?xml version="1.0" encoding="GB18030" ?>
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GB18030" />
<title>OGNL表达式语言学习</title>
</head>
<body>
<ol>
<%-- 访问普通方法和属性:
1、通过域模型的方式只有传入参数,才会构造对象,或者直接在action中new也可以
--%>
<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 />
<%-- 访问静态方法和属性:
1、OGNL表达式语言访问静态方法,需要在Struts2.xml配置allowStaticMethodAccess为true
2、@@max(2,3)这种方式只能访问Math的静态方法
--%>
<li>访问静态方法:<s:property value="@com.chongqing.ognl.S@s()"/></li>
<li>访问静态属性:<s:property value="@com.chongqing.ognl.S@STR"/></li>
<li>访问Math类的静态方法:<s:property value="@@max(2,3)" /></li>
<hr />
<li>访问普通类的构造方法:<s:property value="new com.chongqing.ognl.User(8)"/></li>
<hr />
<%-- 访问集合:
1、{}大括号可以表示一个集合
2、因为在Set中没有排序所以不能用下标访问
3、访问容器的大小用方法size()和属性size都行
--%>
<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>
<li>访问Map:<s:property value="dogMap"/></li>
<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 />
<%-- 投影:
1、投影其实就是对集合过滤选择
2、?表示选取过滤后的所有元素
3、^表示选取过滤后的第一个元素
4、$表示选取过滤后的最后一个元素
--%>
<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>
访问的URL为:
http://localhost:8080/Struts2_OGNL/ognl.action?username=u&password=p&user.age=11&cat.friend.name=oudy
结果为: