OGNL表达式 1 什么是OGNL语言 你还记得 EL表达式语言么?没错OGNL也是表达式语言,不过它比EL可强大太多了。OGNL的全称为Object Graphic Navigation Language(对象图导航语言)。它是Struts2的默认表达式语言! 使用OGNL需要导入OGNL的Jar包:ognl-3.0.5.jar OGNL的功能介绍: EL一样的JavaBean导航; 调用对象方法; 调用类的静态方法; 索引数组元素; 操作集合; 1. EL可以读取JavaBean属性,OGNL使用起来与EL表达式有点相似 2. EL操作的数据是域对象,OGNL操作的数据OgnlContext,可以在OgnlContext指定一个root对象,在不指定操作的对象时默认为root对象。 2 OGNL入门 为了可以执行OGNL表达式,所以我们必须要先学会怎么来使用Ognl类。为了更好的演示Ognl我们需要先创建一些JavaBean用来做测试。 public class Address { private String country; private String city; private String street; …… } public class Employee { private String name; private double salary; private Address address; …… } 我们可以回忆一下EL的使用:${name},它会在所有域中去查找name这个域属性。也就是说,EL表达式也需要一个查询的范围。相同的道理,OGNL也需要一个查找的范围,它查询的范围是OgnlContext。OgnlContext其实就是一个Map,你可以向其内添加N个键值对。它还可以指定多个键值中的一个为根对象(root)! OgnlContext cxt = new OgnlContext(); Address add1 = new Address("中国", "北京", "大北窑"); Employee e1 = new Employee("张三", 10000, add1); Address add2 = new Address("中国", "北京", "西三旗"); Employee e2 = new Employee("李四", 12000, add2); cxt.put("emp1", e1); cxt.put("emp2", e2); cxt.setRoot(e1); 演示OGNL表达式需要使用Ognl类,我们先从它的getValue()方法开始。这个方法需要三个参数,分别是: OGNL表达式; 上下文对象; 根对象。 String name = (String)Ognl.getValue("#emp2.name", cxt, cxt.getRoot()); System.out.println(name); 其中“#emp2.name”是OGNL表达式,查找上下文中的元素必须以“#”开关,其中emp2对应上下文中的键,“.name”表示调用该元素的getName()方法,即JavaBean导航。如果它这个OGNL表达式翻译成Java代码,即:((Employee)cxt.get(“emp2”)).getName()。 String name = (String)Ognl.getValue("name", cxt, cxt.getRoot()); System.out.println(name); 其中“name”为OGNL表达式,当没有使用“#”开始时,表达在使用根对象。所以“name”表达式可以理解为:cxt.getRoot().getName()。即输出“张三”。 String name = (String)Ognl.getValue("address.street", cxt, cxt.getRoot()); System.out.println(name); 因为没有使用“#”开头,那么就是在使用根对象,即cxt.getRoot().getAddress().getStreet(),即输出“大北窑”。 1. OgnlContext就是一个Map,指定操作的对象时需要使用“#”为前缀,后缀为Map的key为后缀; 2. 当没有使用“#”时,表示操作的对象为root对象。 3 OGNL常量 OGNL也可以使用常量: 字符串常量:使用双引号,或单引号。如果字符串只有唯一字符时,必须使用双引号; 字符常量:使用单引号; 数值常量:与Java相同; boolean常量:与Java相同。 OGNL也支持null常量。 1. “hello”是字符串常量,’hello’也是字符串常量,’h’是字符常量; 2. true、false为boolean类型常量; 3. 1.0、100为数值类型常量; 4. null也是常量。 4 运算符 OGNL运算符基本与Java相同,但它还有一些特殊的运算符: 逗号(,):用逗号分隔多个OGNL表达式,这些表达式会依次被执行,而最后一个表达式的值为整个表达式的值; 大括号({}):用来创建列表,例如:{‘zhangSan’,’liSi’,’wangWu’}表示一个List; in和not in:in表示判断某个值是否在集合中,not in表达某个值是否不在集合中。 double s = (Double)Ognl.getValue("name,#emp2.name,salary", cxt, cxt.getRoot()); System.out.println(s); 上面使用了逗号表达式,一共是3个OGNL表达式,它们会被依次运行,但整个整句表达式的值为最后一个OGNL表达式的值,即salary的值。 boolean bool = (Boolean)Ognl.getValue("name in {'张三','李四'}", cxt, cxt.getRoot()); System.out.println(bool); 表达式“name in {‘张三’,’李四’}”首先需要得到name的结果,即根对象的name属性值,然后判断这个值是否在列表中存在,所以返回为true。 1. 逗号运算符很少使用,它的作用是把多个OGNL表达式连接成一个OGNL表达式,每个子表达式会从左到右依次运行,完整表达式的值来最右边表达式的值; 2. in和not in,用于判断某个值在集合中是否存在; 3. {}可以用来创建List集合。 4 设置JavaBean属性值(重点) OGNL表达式不只是可以获取JavaBean属性值,不可以设置JavaBean属性值。但这需要使用Ognl类的setValue()方法。 Ognl.setValue("#emp2.address.street", cxt, cxt.getRoot(), "育新"); System.out.println(Ognl.getValue("#emp2.address.street",cxt, cxt.getRoot())); 表达式指定的是cxt中键为emp2的对象,然后导航到它的address属性,再导航到street属性,最终给该属性设置值为“育新”。 1. “name”表示root对象的name属性; 2. “address.city”表示root对象的address属性的city属性; 3. “#emp.salary”表示上下文中key为emp的对象的salary属性。 5 调用对象方法 OGNL不只可以获取JavaBean属性,还可以调用对象方法。 String s = (String)Ognl.getValue("'OGNL'.toLowerCase()", cxt, cxt.getRoot()); System.out.println(s); 表达式“’OGNL’.toLowerCase()”表示调用字符串OGNL的toLowerCase()方法,千万要小心,在OGNL上添加单引或双引,指定其为字符串常量,不然会被误会来根对象的属性的。 当然,不只是可以调用字符串的方法,什么对象的方法都可以调用。 6 静态方法和静态属性 OGNL还可以调用类的静态方法,以及读取静态属性。操作静态方法或属性时,需要使用完整的类名称,并且需要使用两个“@”把类名称包含起来! String s = (String) Ognl.getValue( "@java.lang.String@format('%tF %<tT', new java.util.Date())", cxt, cxt.getRoot()); System.out.println(s); 上面的表达式可以翻译成:java.lang.String.format(“%tF %<tT”, new java.util.Date()) OGNL对java.lang.Math对有特殊的待遇,如果是操作Math类的静态属性或静态方法,可以不用给出类名称,但“@”不可以省略。 int max = (Integer)Ognl.getValue("@@max(1,2)", cxt, cxt.getRoot()); System.out.println(max); double pi = (Double)Ognl.getValue("@@PI", cxt, cxt.getRoot()); System.out.println(pi); 7 操作数组 OGNL可以用来操作数组,使用下标法即可: String[] names = {"zhangSan", "liSi", "wangWu"}; cxt.put("ns", names); String name = (String)Ognl.getValue("#ns[0]", cxt, cxt.getRoot()); System.out.println(name); 8 操作集合 OGNL可以用来创建List和Map,先来创建一个List它。 List<String> names = (List<String>)Ognl.getValue("{'zhangSan', 'liSi', 'wangWu'}", cxt, cxt.getRoot()); System.out.println(names); 这段代码创建一个List,类型为ArrayList。 创建Map必须以“#”开头 Map<String,String> map = (Map<String, String>)Ognl.getValue("#{'a':'A','b':'B'}", cxt, cxt.getRoot()); System.out.println(map); 创建的Map默认类型为HashMap类型。还可以创建Map时指定Map的类型: Map<String, String> map = (Map<String, String>) Ognl.getValue( "#@java.util.LinkedHashMap@{'aa':'AA','bb':'BB'}", cxt, cxt.getRoot()); System.out.println(map); 获取Map的值。 String s = (String) Ognl.getValue( "#@java.util.LinkedHashMap@{'aa':'AA','bb':'BB'}['bb']", cxt, cxt.getRoot()); System.out.println(s); 9 投影和选择 我们先来聊聊投影,如果有一个Employee的集合,可以通过投影获取所有的Employee的name属性值。这与数据库操作的查询指定列相似。 List<Employee> list = new ArrayList<Employee>(); list.add(new Employee("zhangSan", 10000)); list.add(new Employee("liSi", 11000)); list.add(new Employee("wangWu", 12000)); cxt.put("empList", list); List<String> nameList = (List<String>) Ognl.getValue("#empList.{name}", cxt, cxt.getRoot()); System.out.println(nameList); 获取所有Employee的name属性。这相当于循环遍历list集合,然后调用每个Employee对象的getName()方法。 选择是给出一个条件,获取集合中满足条件的元素。这相当与select * from xxx where con。例如我们要获取salary > 10000的Employee对象。 List<Employee> list = new ArrayList<Employee>(); list.add(new Employee("zhangSan", 10000)); list.add(new Employee("liSi", 11000)); list.add(new Employee("wangWu", 12000)); cxt.put("empList", list); List<Employee> empList = (List<Employee>) Ognl.getValue( "#empList.{?salary > 10000}", cxt, cxt.getRoot()); System.out.println(empList); 其中“{?salary > 10000}”中的“?”表示所有满足条件的元素都查询出来。还可以使用“^”或“$”,其中“^”表示查询第一个满足条件的元素,而“$”表示查询最后一个满足条件的元素。