OGNL表达式

在学习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

原文地址:https://www.cnblogs.com/beilou310/p/10636184.html