OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。
OGNL有如下类型的常量:
1. String字面量, 跟 Java一样 (除了可以单引号): 使用单引号或双引号, 以及转义字符;
2. 字符常量, 跟Java相同
3. 数字字面量, 比java类型多点. 除了Java的 int, long, float和 double, OGNL 允许你指定使用”b”或 “B”后缀指定BigDecimal, 使
用 “h” 或 “H” 后缀(是 “huge”—我们选择 “h” 对 BigInteger因为它与十六进制不混淆 ) BigIntegers ;
4. Boolean (true和 false);
5. null 直接量.
OGNL表达式的计算是围绕OGNL上下文进行的。
OGNL上下文实际上就是一个Map对象,由ognl.OgnlContext类表示。它里面可以存放很多个JavaBean对象。它有一个上下文根对象。
上下文中的根对象可以直接使用名来访问或直接使用它的属性名访问它的属性值。否则要加前缀“#key”。
Struts2的标签库都是使用OGNL表达式来访问ActionContext中的对象数据的
Struts2将ActionContext设置为OGNL上下文,并将值栈作为OGNL的根对象放置到ActionContext中。
值栈(ValueStack) :
可以在值栈中放入、删除、查询对象。访问值栈中的对象不用“#”。
Struts2总是把当前Action实例放置在栈顶。所以在OGNL中引用Action中的属性也可以省略“#”。
调用ActionContext的put(key,value)放入的数据,需要使用#访问。
下面我们在java项目中先学习以下OGNL:
完整的项目树:
User:
package com.lgh.ognltest.entity;
public class User {
private String name;
private Group group;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
public int add(int i , int j){
return i + j;
}
public static void show(String str){
System.out.println("hello " + str);
}
}
Group:
package com.lgh.ognltest.entity;
public class Group {
private String name;
private Organization organization;
public Group() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Organization getOrganization() {
return organization;
}
public void setOrganization(Organization organization) {
this.organization = organization;
}
}
Organization:
package com.lgh.ognltest.entity;
public class Organization {
public Organization() {
}
private String orgId;
public String getOrgId() {
return orgId;
}
public void setOrgId(String orgId) {
this.orgId = orgId;
}
}
@Test
public void test01() throws OgnlException {
User user = new User();
user.setName("zhangsan");
//第一个参数告诉要找谁个,第二个起点
String val = (String) Ognl.getValue("name", user);
System.out.println(val);
}
Ognl.getValue(“name”, user) :第二个参数代表根对象,上面我们已经讲了 查找根对象的属性不需要加 # ,那么要想 加# 怎么办呢?
@Test
public void test02() throws OgnlException {
User user = new User();
user.setName("zhangsan");
Group g = new Group();
g.setName("开发部");
Organization org = new Organization();
org.setOrgId("甲骨文");
user.setGroup(g);
g.setOrganization(org);
// String val = (String) Ognl.getValue("group.organization.orgId", user);
/** * 查找根对象中的属性 不需要加# * 若加# 怎需要 使用 #root * */
String val = (String) Ognl.getValue("#root.group.organization.orgId", user);
System.out.println(val);
// 结果: 甲骨文
}
@Test
public void test04() throws OgnlException {
User user1 = new User();
user1.setName("zhangsan");
User user2 = new User();
user2.setName("lisi");
Map<String,User> context = new HashMap<>();
context.put("u1", user1);
context.put("u2", user2);
/* * context 是OGNL的上下文对象 ,查找其中的属性 必须加 # * 查找多个属性时 应该 使用 +','+ 连接 * 直接使用 ,会只查找最后一个 * * */
// String val = (String) Ognl.getValue("#u1.name,#u2.name", context, new Object());
// 结果: lisi
// #号 表示从map集合中查找 没有# 就从第三个参数 根查找 #.root 也从根查找
String val = (String) Ognl.getValue("#u1.name+','+#u2.name+','+name", context, user1);
System.out.println(val);
// 结果: zhangsan,lisi,zhangsan
}
// Ognl 赋值
@Test
public void test05() throws OgnlException{
User user = new User();
Ognl.setValue("name", user, "zhangsan");
System.out.println(user.getName());
}
@Test
public void test06() throws OgnlException{
User user = new User();
Map map = new HashMap();
map.put("u1", user);
Ognl.setValue("#u1.name",map, user, "zhangsan");
String str= (String) Ognl.getValue("#u1.name+','+name", map,user);
System.out.println(user.getName());
System.out.println(str);
}
Ognl.setValue(“#u1.name”,map, user, “zhangsan”) 无法为多个对象赋值;
接下来我们看怎么为多个对象赋值:
//为多个对象赋值 第三个默认根
@Test
public void test07() throws OgnlException{
User user1 = new User();
User user2 = new User();
Map map = new HashMap();
Group g = new Group();
g.setName("开发部");
map.put("u1", user1);
map.put("u2", user2);
map.put("g", g);
Ognl.getValue("#u1.name='zhangsan',#u1.group=#g,#u2.name='lisi'", map,new Object());
String str= (String) Ognl.getValue("#u1.name+','+#u2.name+','+#u1.group.name", map,new Object());
System.out.println(str);
// zhangsan,lisi,开发部
}
//非静态方法调用
@Test
public void test08() throws OgnlException{
int sum = (int) Ognl.getValue("add(2,4)", new User());
System.out.println(sum);
// 6
}
@Test
public void test09() throws OgnlException{
List list = (List) Ognl.getValue("{2,4,5,8}", new Object());
Map map = new HashMap();
map.put("ls", list);
System.out.println(list);
// [2, 4, 5, 8]
int sum = (int) Ognl.getValue("add(#ls[1],#ls[2])",map ,new User());
System.out.println(sum);
// 9
}
静态属性或方法 调用前面要加@
@Test
public void test10() throws OgnlException{
Ognl.getValue("@com.lgh.ognltest.entity.User@show('Jim')", new Object());
// hello Jim
Ognl.getValue("@[email protected]('the good')", new Object());
// the good
}
@Test
public void test11() throws OgnlException{
Object root = new Object();
Map conMap = new HashMap();
List list = (List) Ognl.getValue("{3,4,2,5,9}", root);
conMap.put("ls", list);
System.out.println("list 的访问 ----------------");
System.out.println(Ognl.getValue("#ls[2]", conMap, root));
System.out.println("伪属性 虽然没有 getter 方法 但是 在 OGNL 上 也可以通过 . 得到值 ");
System.out.println(" list size :"+Ognl.getValue("#ls.size", conMap, root));
System.out.println(" list isEmpty :"+Ognl.getValue("#ls.isEmpty", conMap, root));
System.out.println("list ----------------");
int[] arr = (int[]) Ognl.getValue("new int[]{2,3,1,7}", root);
conMap.put("arr", arr);
System.out.println("array 的访问 ----------------");
System.out.println(Ognl.getValue("#arr[2]", conMap, root));
System.out.println("array ----------------");
Map map = (Map) Ognl.getValue("#@java.util.HashMap@{'name':'z3','age':30,'ls2':#ls}",conMap, root);
System.out.println(map);
}
list 的访问 ----------------
2
伪属性 虽然没有 getter 方法 但是 在 OGNL 上 也可以通过 . 得到值
list size :5
list isEmpty :false
list ----------------
array 的访问 ----------------
1
array ----------------
{name=z3, ls2=[3, 4, 2, 5, 9], age=30}
个人学习心得,难免有错误遗漏,欢迎指正讨论!