在学习Struts2中的OGNL和值栈的时候,遇到了OGNL,看了一些后还是发下对这个OGNL 完全模糊,在此节单独对OGNL进行学习。
目的是学完后知道OGNL是来干嘛的?可以怎么使用。
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。 ——百度百科
OGNL我们看到最多的就是和Struts2的标签结合使用,但其实OGNL离开了Struts2也是可以的,只是用在Struts2中,就必须和标签库结合才能使用。
这篇文章就先讲讲OGNL不结合Struts2的一些用法,下篇文章再讲OGNL在Struts2中的用法。
1.OgnlContext类和Ognl类的介绍
在类中使用OGNL表达式,和两个类息息相关,分别是OgnlContext类和Ognl类。
Ognl类:This class provides static methods for parsing and interpreting OGNL expressions.根据官方解释,这个类是提供一些静态方法去解析表达式。
OgnlContext:This class defines the execution context for an OGNL expression.该类定义OGNL表达式的执行上下文。
public class OgnlContext extends Object implements Map {}
OgnlContext类实现了Map接口,所以它也是一个Map,可以通过put方法往该上下文环境中放元素。该上下文环境中,有两种对象:根对象和普通对象。我们可以使用它的setRoot方法设置根对象。根对象只能有一个,而普通对象则可以有多个。因为它实现了java.utils.Map 的接口。OgnlContext(ognl上下文)=根对象(1个)+非根对象(n个),非根对象要通过"#key"访问,根对象可以省略"#key"。
2.Ognl获取普通对象和根对象的方法
在上下文环境中,有根对象和普通的对象,两者的获取方式有所不同:获取根对象的属性值,可以直接使用属性名作为表达式,也可以使用#对象名.属性名的方式;获取普通对象的属性值,则必须使用#对象名.属性名的方式获取。(可以将普通对象设置为根对象,但只能有一个根对象,后面设置的根对象会覆盖前面的根对象)下面举例说明。
1 package OGNL; 2 3 import java.util.List; 4 5 public class School { 6 7 private String name; 8 private List<Teacher> teachers; 9 10 11 public School() { 12 super(); 13 } 14 15 16 public School(String name, List<Teacher> teachers) { 17 super(); 18 this.name = name; 19 this.teachers = teachers; 20 } 21 22 23 /** 24 * @return the name 25 */ 26 public String getName() { 27 return name; 28 } 29 /** 30 * @param name the name to set 31 */ 32 public void setName(String name) { 33 this.name = name; 34 } 35 /** 36 * @return the teachers 37 */ 38 public List<Teacher> getTeachers() { 39 return teachers; 40 } 41 /** 42 * @param teachers the teachers to set 43 */ 44 public void setTeachers(List<Teacher> teachers) { 45 this.teachers = teachers; 46 } 47 48 49 } 50 51 package OGNL; 52 53 public class Teacher { 54 55 private String name; 56 private String gender; 57 private int age; 58 59 60 public Teacher() { 61 super(); 62 } 63 64 public Teacher(String name, String gender, int age) { 65 super(); 66 this.name = name; 67 this.gender = gender; 68 this.age = age; 69 } 70 /** 71 * @return the name 72 */ 73 public String getName() { 74 return name; 75 } 76 /** 77 * @param name the name to set 78 */ 79 public void setName(String name) { 80 this.name = name; 81 } 82 /** 83 * @return the gender 84 */ 85 public String getGender() { 86 return gender; 87 } 88 /** 89 * @param gender the gender to set 90 */ 91 public void setGender(String gender) { 92 this.gender = gender; 93 } 94 /** 95 * @return the age 96 */ 97 public int getAge() { 98 return age; 99 } 100 /** 101 * @param age the age to set 102 */ 103 public void setAge(int age) { 104 this.age = age; 105 } 106 107 } 108 109 package OGNL; 110 111 import java.util.ArrayList; 112 import java.util.List; 113 114 import ognl.Ognl; 115 import ognl.OgnlContext; 116 import ognl.OgnlException; 117 118 public class Test { 119 120 public static void main(String args[]) throws OgnlException{ 121 122 //定义一个老师对象 123 Teacher t1 = new Teacher("zhangsan","男",30); 124 List<Teacher> teachers =new ArrayList<Teacher>(); 125 teachers.add(t1); 126 127 //定义一个学校对象 128 School sc = new School("China", teachers); 129 130 //创建一个OgnlContext对象 131 OgnlContext context = new OgnlContext(); 132 133 //将老师和学校放入上下文环境中 134 context.put("t1", t1); 135 context.put("sc", sc); 136 137 //未设置根对象之前,根对象为null 138 System.out.println("0000:"+context.getRoot()); 139 140 //设置学校为根对象 141 context.setRoot(sc); 142 System.out.println("1111:"+context.getRoot()); 143 //若继续设置根对象,会覆盖前面的根对象 144 //context.setRoot(t1); 145 146 //获取根对象属性 147 //获取根对象的属性值,可以直接使用属性名作为表达式,也可以使用#对象名.属性名的方式; 148 Object expression = Ognl.parseExpression("name"); 149 //Object expression = Ognl.parseExpression("#sc.name"); 150 151 Object result = Ognl.getValue(expression, context, context.getRoot()); 152 // 获取根对象的信息,使用#获取上下文中的属性值时,必须使用带Map context参数getValue方法,指定上下文环境 153 // 获取根对象的信息,直接获取,没有使用#,则可以使用不带Map context参数getValue方法 154 Object result1 = Ognl.getValue(expression, context.getRoot()); 155 System.out.println("2222:"+result); 156 System.out.println("2222:"+result1); 157 158 //获取普通对象的属性值,则必须使用#对象名.属性名的方式获取 159 expression = Ognl.parseExpression("#t1.name"); 160 result = Ognl.getValue(expression, context, context.getRoot()); 161 System.out.println("3333:"+result); 162 } 163 164 }
运行测试代码:这种方法通过属性来获取属性值
0000:null
1111:OGNL.School@11028347
2222:China
2222:China
3333:zhangsan
总结:
1.根对象只能有一个,当你尝试设置多个的时候,后面的会覆盖前面的。
2.访问根对象中的属性,可以直接使用属性名,或者#对象名.属性名,但不能使用对象名.属性名,不然它会认为这是根对象中的一个属性叫对象名,然后访问这个属性的名叫属性名的属性值。
3.不使用#获取根对象中的属性值时, 使用getValue方法可以不指定上下文环境,因为第三个参数已经得到了根对象,它指定去根对象中找。如果获取普通对象的属性,则必须在getValue方法中指定上下文环境,因为你不知道它找不到。
4.通过根对象间接获取普通对象的属性时,比如List集合,使用下标去获取
3.Ognl访问非静态方法、静态方法、静态字段的方法
Ognl不但可以访问我们自己定义的类的属性和方法,还可以访问Java API中的静态方法和静态字段。
1 package OGNL; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import ognl.Ognl; 7 import ognl.OgnlContext; 8 import ognl.OgnlException; 9 10 public class Test { 11 12 public static void main(String args[]) throws OgnlException{ 13 14 //定义一个老师对象 15 Teacher t1 = new Teacher("zhangsan","男",30); 16 List<Teacher> teachers =new ArrayList<Teacher>(); 17 teachers.add(t1); 18 19 //定义一个学校对象 20 School sc = new School("China", teachers); 21 22 //创建一个OgnlContext对象 23 OgnlContext context = new OgnlContext(); 24 25 //将老师和学校放入上下文环境中 26 context.put("t1", t1); 27 context.put("sc", sc); 28 29 //未设置根对象之前,根对象为null 30 System.out.println("根对象:"+context.getRoot()); 31 32 //设置学校为根对象 33 context.setRoot(sc); 34 System.out.println("设置根对象:"+context.getRoot()); 35 //若继续设置根对象,会覆盖前面的根对象 36 //context.setRoot(t1); 37 38 //获取根对象属性 39 //获取根对象的属性值,可以直接使用属性名作为表达式,也可以使用#对象名.属性名的方式; 40 Object expression = Ognl.parseExpression("name"); 41 //Object expression = Ognl.parseExpression("#sc.name"); 42 43 Object result = Ognl.getValue(expression, context, context.getRoot()); 44 // 获取根对象的信息,使用#获取上下文中的属性值时,必须使用带Map context参数getValue方法,指定上下文环境 45 // 获取根对象的信息,直接获取,没有使用#,则可以使用不带Map context参数getValue方法 46 Object result1 = Ognl.getValue(expression, context.getRoot()); 47 System.out.println("获取根对象的属性值:"+result); 48 System.out.println("获取根对象的属性值:"+result1); 49 50 //获取普通对象的属性值,则必须使用#对象名.属性名的方式获取 51 expression = Ognl.parseExpression("#t1.name"); 52 result = Ognl.getValue(expression, context, context.getRoot()); 53 System.out.println("获取普通对象的属性值:"+result); 54 55 //调用根对象中的方法 56 expression = Ognl.parseExpression("getName()"); 57 expression = Ognl.parseExpression("#sc.getName()"); 58 result = Ognl.getValue(expression, context, context.getRoot()); 59 System.out.println("调用根对象中的方法:"+result); 60 61 //调用普通对象中的方法 62 expression = Ognl.parseExpression("#t1.getAge()"); 63 result = Ognl.getValue(expression, context, context.getRoot()); 64 System.out.println("调用普通对象中的方法:"+result); 65 expression = Ognl.parseExpression("#t1.getName().length()"); 66 result = Ognl.getValue(expression, context, context.getRoot()); 67 System.out.println("调用普通对象中的方法:"+result); 68 69 //调用根对象中的静态方法 70 expression = Ognl.parseExpression("test00()"); 71 expression = Ognl.parseExpression("#sc.test00()"); 72 result = Ognl.getValue(expression, context, context.getRoot()); 73 System.out.println("调用根对象中的静态方法:"+result); 74 75 //调用API中的静态方法 76 expression = Ognl.parseExpression("@java.lang.Math@floor(4.5)"); 77 result = Ognl.getValue(expression, context, context.getRoot()); 78 System.out.println("调用API中的静态方法:"+result); 79 80 //调用API中的静态属性 81 expression = Ognl.parseExpression("@java.lang.Math@PI"); 82 result = Ognl.getValue(expression, context, context.getRoot()); 83 System.out.println("调用API中的静态属性:"+result); 84 85 } 86 87 }
在school.java中新加了一个静态函数:
1 public static String test00(){ 2 3 return "thank you"; 4 }
运行上面的测试code:
根对象:null
设置根对象:OGNL.School@11028347
获取根对象的属性值:China
获取根对象的属性值:China
获取普通对象的属性值:zhangsan
调用根对象中的方法:China
调用普通对象中的方法:30
调用普通对象中的方法:8
调用根对象中的静态方法:thank you
调用API中的静态方法:4.0
调用API中的静态属性:3.141592653589793.
所以到此我们可以看到OGNL实际上就是提供另一种方式来调用对象的任意属性和方法。
4.Ognl获取数组、集合、Map中元素的方法
Ognl表达式可以创建实例对象,以及获取实例对象中的属性,下面我们看看怎么通过Ognl创建一个集合、map以及通过Ognl获取里面的元素。
1 package OGNL; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.HashMap; 6 import java.util.List; 7 import java.util.Map; 8 9 import ognl.Ognl; 10 import ognl.OgnlContext; 11 import ognl.OgnlException; 12 13 public class Test02 { 14 15 public static void main(String[] args) throws OgnlException { 16 17 OgnlContext context = new OgnlContext(); 18 19 // 通过Ognl可以创建java的实例对象,只有是类的完整路径 20 Object expression = Ognl.parseExpression("new java.util.ArrayList()"); 21 Object result = Ognl.getValue(expression, context, context.getRoot()); 22 System.out.println("Ognl创建实例:"+result); 23 24 //注意这种自定义的类,一定要填写类的完整路径 25 expression = Ognl.parseExpression("new OGNL.Teacher('zhangsan','男',30)"); 26 result = Ognl.getValue(expression, context, context.getRoot()); 27 System.out.println("Ognl创建实例:"+result); 28 29 // 通过Ognl可以创建一个初始化的List 30 expression = Ognl.parseExpression("{'a', 'b', 'c', 'd'}"); 31 //expression = Ognl.parseExpression("['a', 'b', 'c', 'd']"); //这个报错 32 result = Ognl.getValue(expression, context, context.getRoot()); 33 System.out.println("Ognl初始化List:"+result); 34 35 // 通过Ognl可以创建一个初始化的Map,注意此时得加上#符号 36 expression = Ognl.parseExpression("#{'a':'aa', 'b':'bb', 'c':'cc', 'd':'dd'}"); 37 // 创建指定类型的Map 38 // expression = Ognl.parseExpression("#@java.util.TreeMap@{'a':'aa', 'b':'bb', 'c':'cc', 'd':'dd'}"); 39 result = Ognl.getValue(expression, context, context.getRoot()); 40 System.out.println("Ognl初始化Map:"+result); 41 42 // 通过Ognl访问数组中的元素 43 String[] name1 = {"liu", "xu"}; 44 context.put("name1", name1); 45 // 直接通过数组名+下标 46 expression = Ognl.parseExpression("#name1[1]"); 47 result = Ognl.getValue(expression, context, context.getRoot()); 48 System.out.println("通过Ognl访问数组中的元素:"+result); 49 50 // 通过Ognl访问集合中的元素 51 List<String> name2 = new ArrayList<String>(); 52 Collections.addAll(name2, name1); //将name1中的数据copy到name2中。 53 context.put("name2", name2); 54 // 直接通过集合名+下标 55 expression = Ognl.parseExpression("#name2[0]"); 56 result = Ognl.getValue(expression, context, context.getRoot()); 57 System.out.println("通过Ognl访问集合中的元素:"+result); 58 59 // 通过Ognl访问Map中的元素 60 Map<Integer, String> name3 = new HashMap<Integer, String>(); 61 name3.put(1, "liu"); 62 name3.put(2, "xu"); 63 context.put("name3", name3); 64 // 直接通过map名+key 65 expression = Ognl.parseExpression("#name3[1]"); 66 result = Ognl.getValue(expression, context, context.getRoot()); 67 System.out.println("通过Ognl访问Map中的元素 :"+result); 68 69 } 70 71 }
运行结果:
Ognl创建实例:[]
Ognl创建实例:OGNL.Teacher@2aaf7cc2
Ognl初始化List:[a, b, c, d]
Ognl初始化Map:{a=aa, b=bb, c=cc, d=dd}
通过Ognl访问数组中的元素:xu
通过Ognl访问集合中的元素:liu
通过Ognl访问Map中的元素 :liu
注意点
1.创建集合不用加#,创建map要加#。
2.创建类的一个对象,要使用类的完整路径。
3.要创建带有初始化值的指定类型的List或Map,可以这样#@java.util.TreeMap@{‘key’:’value’,’key’:’value’,……}。
OGNL还有其他用法。这里不再细说。通过上面的例子,我们可以看出,OGNL大概作用是什么:就是用来获取对象的属性和方法。
记住OGNL的表达式、根对象、上下文OgnlContext.
上面的例子中我们可以看到,都是直接调用了OgnlContext这个类,创建了context,我们用OGNL的时候,第二个参数就是context, 第三个参数就是context,getRoot()。
实际上这个上下文环境我们是可以自定义的,根对象我们也是可以自定义的。我们来看看下面的例子:
1 package OGNL; 2 3 public class Address { 4 5 private String city; 6 private String Street; 7 /** 8 * @return the city 9 */ 10 public String getCity() { 11 return city; 12 } 13 /** 14 * @param city the city to set 15 */ 16 public void setCity(String city) { 17 this.city = city; 18 } 19 /** 20 * @return the street 21 */ 22 public String getStreet() { 23 return Street; 24 } 25 /** 26 * @param street the street to set 27 */ 28 public void setStreet(String street) { 29 Street = street; 30 } 31 } 32 33 34 package OGNL; 35 36 public class User { 37 38 private String name; 39 private int age; 40 private String password; 41 private Address address; 42 /** 43 * @return the name 44 */ 45 public String getName() { 46 return name; 47 } 48 /** 49 * @param name the name to set 50 */ 51 public void setName(String name) { 52 this.name = name; 53 } 54 /** 55 * @return the age 56 */ 57 public int getAge() { 58 return age; 59 } 60 /** 61 * @param age the age to set 62 */ 63 public void setAge(int age) { 64 this.age = age; 65 } 66 /** 67 * @return the password 68 */ 69 public String getPassword() { 70 return password; 71 } 72 /** 73 * @param password the password to set 74 */ 75 public void setPassword(String password) { 76 this.password = password; 77 } 78 /** 79 * @return the address 80 */ 81 public Address getAddress() { 82 return address; 83 } 84 /** 85 * @param address the address to set 86 */ 87 public void setAddress(Address address) { 88 this.address = address; 89 } 90 } 91 92 package OGNL; 93 94 import java.util.HashMap; 95 96 import ognl.Ognl; 97 import ognl.OgnlException; 98 99 public class Test03 { 100 101 public static void main(String[] args) throws OgnlException { 102 103 User user = new User(); 104 user.setName("zhangsan"); 105 106 //将user对象作为OGNL的根,编写OGNL表达式来获取user对象中的各种属性值 107 //直接编写属性名,即获取user对象中的属性值 108 String name = (String) Ognl.getValue("name", new HashMap(), user); 109 System.out.println("0000:"+name); 110 111 //获取javaBean中另一个对象的属性值,用xxx.yyy 112 Address ads = new Address(); 113 ads.setCity("baoding"); 114 user.setAddress(ads); 115 String result = (String) Ognl.getValue("address.city", new HashMap(), user); 116 System.out.println("1111:"+result); 117 118 //对JavaBean中的属性进行赋值操作 119 Ognl.getValue("name='zhaosi'", new HashMap(), user); 120 System.out.println("2222:"+user.getName()); 121 Ognl.getValue("setName('wangwu')", new HashMap(), user); 122 System.out.println("3333:"+user.getName()); 123 //上面是两种赋值方式: 124 /*1:属性=value 125 Ognl.getValue("name='zhaosi'", new HashMap(), user); 126 2:setName(value) 127 Ognl.getValue("setName('wangwu')", new HashMap(), user); 128 */ 129 } 130 131 }
运行结果:
0000:zhangsan
1111:baoding
2222:zhaosi
3333:wangwu
可以看到这个例子中直接将user作为对象去使用。并且上下文环境直接是新建了一个HashMap。
上面两个例子都是讲解OGNL基本用法,主要区别就在于第二个例子中,都是将对象直接作为根对象去使用。没有用到OgnlContext这个类。
https://www.cnblogs.com/whgk/p/6600393.html
https://blog.csdn.net/a_helloword/article/details/80432364-----参考博客
作者:全网第一菜
来源:CSDN
原文:https://blog.csdn.net/a_helloword/article/details/80432364