Ognl表达式语言
来源:互联网 发布:爱淘宝怎么分享宝贝 编辑:程序博客网 时间:2024/06/08 03:36
Ognl全称Object Graph Navigation Language,是Apache Commons下的一个子项目。和JSP中的EL表达式一样,通常作为View层访问数据的一种方式。但是OGNL的功能比EL表达式功能强大的多(看完这篇文章后你会觉得OGNL能把EL表达式秒成渣)
jar包下载
使用ognl最有名的项目就是Struts2和MyBatis了,关于OGNL在Struts2中的使用以及原理,后面会有一篇文章详细说明。
这里的例子不会依赖Struts2的运行环境。
官网下载地址:
http://commons.apache.org/proper/commons-ognl/download_ognl.cgi
Maven依赖:
<!-- https://mvnrepository.com/artifact/ognl/ognl --><dependency> <groupId>ognl</groupId> <artifactId>ognl</artifactId> <version>3.2.3</version></dependency>
基本语法
最基本的语法很简单:通过属性(property)来访问Bean的数据,所以OGNL要求类对象具有getter/setter方法(也就是符合标准JavaBean的规则)。
下面的例子中将会使用User类作为测试的JavaBean
public class User { private String username; private String password; public User(String username, String password) { this.username = username; this.password = password; } public User() { } // 省略getter/setter // 省略toString}
下面的例子中会经常用到Ognl类的两个方法(暂时不了解这两个方法有什么作用不要紧,后面用到的时候自然就明白):
/** * @param expression 将要解析的OGNL表达式 * @param root OGNL表达式的root元素对象 */public static Object getValue(String expression, Object root)/** * @param expression 将要解析的OGNL表达式 * @param context 用于取值的命名上下文 * @param root OGNL表达式的root元素对象 */public static Object getValue(String expression, Map context, Object root)
root对象
使用ognl表达式访问root元素对象中的属性不需要任何前缀。
root对象属性访问:
@Testpublic void test() throws OgnlException { User user = new User("apache", "123456"); Object value = Ognl.getValue("username", user); // user对象作为root元素 System.out.println(value); // apache // 注意这里的username需要加引号 Object value = Ognl.getValue("['username']", user); // user对象作为root元素 System.out.println(value); // apache}
对象的访问方式和Map的一样
对象方法调用:
@Testpublic void test() throws OgnlException { User user = new User("apache", "123456"); // 调用root元素的toString方法 Object value = Ognl.getValue("toString()", user); System.out.println(value); //User [username=apache, password=123456]}
数组索引:
@Testpublic void test() throws OgnlException { User u1 = new User("apache", "123456"); User u2 = new User("git", "234"); User u3 = new User("google", "567"); User[] users = new User[] { u1, u2, u3 }; // 访问root元素下的索引为1的元素 Object value = Ognl.getValue("[1].toString()", users); System.out.println(value); // User [username=git, password=234]}
context上下文
使用OGNL表达式访问context中的元素需要添加#
符号作为前缀,而且context需要是Map接口的实现类。同时要求添加一个root对象,此时root对象会以"root"
字符串做为Key添加到context中。
@Testpublic void test() throws OgnlException { User u1 = new User("apache", "123456"); User u2 = new User("git", "234"); User u3 = new User("google", "567"); User[] users = new User[] { u1, u2, u3 }; Map<String, Object> context = new HashMap<>(); context.put("names", new String[] { "ali", "huawei", "baidu" }); // 使用#前缀访问context下的元素 Object value = Ognl.getValue("#names[1]", context, users); // users作为root元素 System.out.println(value); //huawei // 使用#root访问root元素 Object v2 = Ognl.getValue("#root[0]", context, users); System.out.println(v2); // User [username=apache, password=123456]}
事实上使用
Object value = Ognl.getValue("username", user);
方式,不指定context,它会默认帮你创建一个OgnlContext,OgnlContext也实现了Map接口。而使用Object value = Ognl.getValue("#names[1]", context, users);
方式,指定的map类型的context,最终也会被转换成OgnlContext。
通过查看OgnlContext源码,会发现有几个关键点:
public class OgnlContext extends Object implements Map{ // root元素的key public static final String ROOT_CONTEXT_KEY = "root"; // this会在后面提到 public static final String THIS_CONTEXT_KEY = "this"; ... private static Map RESERVED_KEYS = new HashMap(11); private Object _root; // root元素 private Object _currentObject; // this元素 ... private final Map _values; // context内实际保存对象引用的Map static { String s; RESERVED_KEYS.put(ROOT_CONTEXT_KEY, null); RESERVED_KEYS.put(THIS_CONTEXT_KEY, null); ... } public Object get(Object key) { Object result; if (RESERVED_KEYS.containsKey(key)) { // this元素 if (key.equals(OgnlContext.THIS_CONTEXT_KEY)) { result = getCurrentObject(); // currentObject } else if (key.equals(OgnlContext.ROOT_CONTEXT_KEY)) { // root元素 result = getRoot(); } else if (key.equals(OgnlContext.TRACE_EVALUATIONS_CONTEXT_KEY)) { ... ... } else { throw new IllegalArgumentException("unknown reserved key '" + key + "'"); } } else { // 从map中取值 result = _values.get(key); } return result; } ...}
OGNL中的常量
1.字符串常量,需要用引号引起来(可以是单引号也可以是双引号,单引号可以作为内嵌脚本使用)。
2.字符常量,需要用单引号引起来
3.数值常量,支持Java的int,long,float,double。同时可以使用”b” 或 “B”作为后缀表示BigDecimal类型的数据,使用”h” 或 “H”作为后缀表示BigInteger类型的数据(这里的h表示huge,这个不会干扰16进制的数字)
4.布尔类型,true和false
5.空指针,null
集合元素
访问List元素
@Testpublic void testOgnl() throws OgnlException { User u1 = new User("apache", "123456"); User u2 = new User("git", "234"); User u3 = new User("google", "567"); List<User> users = new ArrayList<>(); users.add(u1); users.add(u2); users.add(u3); Map<String, Object> ctx = new HashMap<>(); ctx.put("users", users); // 同时将users以"users"为key添加到context中 // 使用#前缀访问context下的属性 Object v1 = Ognl.getValue("#users[1].password", ctx, users); // 以user作为root元素 System.out.println(v1); // 234 // 访问root元素下的属性(List也可以使用[]索引方式访问) Object v2 = Ognl.getValue("[1].password", ctx, users); System.out.println(v2); //234 // 也可以调用List.get方法访问 Object v3 = Ognl.getValue("get(1).password", ctx, users); System.out.println(v3); // 234 // 因为root元素会以“root”为key添加到context中 Object v4 = Ognl.getValue("#root[1].password", users); System.out.println(v4); // 234}
访问Map元素
@Testpublic void test() throws OgnlException { Object root = new Object(); Map<String, Object> ctx = new HashMap<>(); Map<String, Object> users = new HashMap<>(); users.put("apache", "123456"); users.put("git", "234"); users.put("google", "567"); ctx.put("users", users); // 使用[key]进行访问 Object v1 = Ognl.getValue("#users['apache']", ctx, root); System.out.println(v1); // 使用.运算符进行访问 Object v2 = Ognl.getValue("#users.apache", ctx, root); System.out.println(v2);}
Map和对象的访问方式一样:
@Testpublic void test() throws OgnlException { Object root = new Object(); Map<String, Object> ctx = new HashMap<>(); User user = new User("apache", "123456"); ctx.put("user", user); Object v1 = Ognl.getValue("#user['username']", ctx, root); System.out.println(v1); Object v2 = Ognl.getValue("#user.username", ctx, root); System.out.println(v2);}
集合的伪属性
@Testpublic void test() throws OgnlException { Object root = new Object(); Map<String, Object> ctx = new HashMap<>(); ctx.put("usernames", Arrays.asList("ali", "huawei", "baidu")); // 调用size方法获取集合元素个数 Object v1 = Ognl.getValue("#usernames.size()", ctx, root); System.out.println(v1); // 使用size伪属性获取集合元素个数 Object v2 = Ognl.getValue("#usernames.size", ctx, root); System.out.println(v2);}
OGNL中为集合相关的类提供了以下的伪属性:
Map
, List
Set
size
: 集合中元素的个数isEmpty
: 集合是否为空 List iterator
: 获取list
的迭代器 Map keys
: 等价于keys()方法values
: 等价于values()方法。注意: 这两个属性以及
size
and isEmpty
, 和map['size']
这种访问方式不同,map['size']
会访问key为'size'
的元素。 Set iterator
: 获取Set的迭代器 Iterator next
: 获取迭代器的下一个元素hasNext
: 迭代器是否有可用元素。 Enumeration next
: 获取迭代器的下一个元素hasNext
迭代器是否有可用元素。构造集合
构造原生数组
@Testpublic void test() throws OgnlException { // 使用OGNL表达式构造list Object v = Ognl.getValue("new int[] { 1, 2, 3 }", null); System.out.println(v.getClass()); // class [I System.out.println(Arrays.toString((int[]) v)); // [1, 2, 3]}
构造List元素
@Testpublic void test() throws OgnlException { // 使用OGNL表达式构造list Object v = Ognl.getValue("new int[] { 1, 2, 3 }", null); System.out.println(v.getClass()); // java.util.ArrayList System.out.println(v); // [abc, def, hff, git]}
构造Map集合
@Testpublic void test() throws OgnlException { // 构造map Object v = Ognl.getValue("#{'foo':'ffff', 'bar':'barvalue'}", null); System.out.println(v.getClass()); // class java.util.LinkedHashMap System.out.println(v); // {foo=ffff, bar=barvalue}}
使用指定的类构造Map
@Testpublic void test() throws OgnlException { // 指定使用HashMap构造map Object v = Ognl.getValue("#@java.util.HashMap@{'foo':'ffff', 'bar':'barvalue'}", null); System.out.println(v.getClass()); System.out.println(v);}
构造复杂map
@Testpublic void test() throws OgnlException { // 构造复杂map Object v = Ognl.getValue("#{'foo': {1, 2, 3, 4}, 'bar':'barvalue'}", null); System.out.println(v); // {foo=[1, 2, 3, 4], bar=barvalue}}
使用变量构造map、list或数组
@Testpublic void test() throws OgnlException { Map<String, Object> ctx = new HashMap<>(); ctx.put("usernames", Arrays.asList("ali", "git", "apache", "chrome")); Object v1 = Ognl.getValue("#{'u1':#usernames[0], 'u2':#usernames[2]}", ctx, new Object()); System.out.println(v1); // {u1=ali, u2=apache} Object v2 = Ognl.getValue("{#usernames[1], #usernames[3]}", ctx, new Object()); System.out.println(v2); // [git, chrome]}
[not] in操作
@Testpublic void test() throws OgnlException { Map<String, Object> ctx = new HashMap<>(); ctx.put("usernames", Arrays.asList("ali", "git", "apache", "chrome")); Object v5 = Ognl.getValue("'git' in #usernames", ctx, new Object()); System.out.println(v5); // true Object v6 = Ognl.getValue("'holmofy' not in #usernames", ctx, new Object()); System.out.println(v6); // true}
^、$和?操作符进行元素过滤
也有人把这些操作叫做投影(projection)
@Testpublic void test() throws OgnlException { User u1 = new User("root", "1"); User u2 = new User("git", "2"); User u3 = new User("apache", "3"); User u4 = new User("chrome", "4"); User u5 = new User("root", "5"); User u6 = new User("git", "6"); User u7 = new User("apache", "7"); User u8 = new User("chrome", "8"); List<User> users = new ArrayList<>(); users.add(u1); users.add(u2); users.add(u3); users.add(u4); users.add(u5); users.add(u6); users.add(u7); users.add(u8); Map<String, Object> ctx = new HashMap<>(); ctx.put("users", users); // 第一个元素 Object v1 = Ognl.getValue("#users.{^ true}", ctx, new Object()); System.out.println(v5.getClass()); // java.util.ArrayList System.out.println(v1); // [User [username=root, password=1]] // 第一个username == 'git'的元素 Object v2 = Ognl.getValue("#users.{^ #this.username=='git'}", ctx, new Object()); System.out.println(v5.getClass()); // java.util.ArrayList System.out.println(v2); // [User [username=git, password=2]] // 最后一个元素 Object v3 = Ognl.getValue("#users.{$ true}", ctx, new Object()); System.out.println(v5.getClass()); // java.util.ArrayList System.out.println(v3); // [User [username=chrome, password=8]] // 从后往前第一个username == 'apache'的元素 Object v4 = Ognl.getValue("#users.{$ #this.username=='apache'}", ctx, new Object()); System.out.println(v5.getClass()); // java.util.ArrayList System.out.println(v4); // [User [username=apache, password=7]] // 使用?号进行条件过滤 Object v5 = Ognl.getValue("#users.{? #this.username in {'git','apache'} }", ctx, new Object()); System.out.println(v5.getClass()); // java.util.ArrayList System.out.println(v5); // [User [username=git, password=2], User [username=apache, password=3], User [username=git, password=6], User [username=apache, password=7]]}
三目运算符
@Testpublic void test() throws OgnlException { Map<String, Object> ctx = new HashMap<>(); ctx.put("usernames", Arrays.asList("root", "git", "apache", "chrome")); Object value = Ognl.getValue("#usernames.size.(#this>2?2:#this)", ctx, new Object()); System.out.println(value); // 2}
类的静态方法调用
@Testpublic void test() throws OgnlException { Map<String, Object> ctx = new HashMap<>(); ctx.put("usernames", new String[] {"root", "git", "apache", "chrome"}); Object value = Ognl.getValue("@java.util.Arrays@toString(#usernames)", ctx, new Object()); System.out.println(value); // [root, git, apache, chrome]}
多条语句的执行
@Testpublic void test() throws OgnlException { Map<String, Object> ctx = new HashMap<>(); int[] arr = new int[] { 4, 5, 2, 6 }; ctx.put("arr", arr); Object value = Ognl.getValue("@java.util.Arrays@sort(#arr),#arr", ctx, new Object()); System.out.println(Arrays.toString((int[]) value)); // [2, 4, 5, 6] System.out.println(Arrays.toString(arr)); // [2, 4, 5, 6]}
Lambda表达式
@Testpublic void test() throws OgnlException { Object value = Ognl.getValue("#fib =:[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(8)", null); System.out.println(value);}
附录:OGNL语法摘要表
getValue()
NotessetValue()
Notes,
e2Sequence operator Both
e1
and e2
are evaluated with the same source object, and the result of e2
is returned. getValue
is called on e1
, and then setValue
is called on e2
. e1 =
e2Assignment operator
getValue
is called on e2
, and then setValue
is called on e1
with the result of e2
as the target object. Cannot be the top-level expression for setValue
. e1 ?
e2 :
e3Conditional operator
getValue
is called on e1
and the result is interpreted as a boolean. getValue
is then called on either e2
or e3
, depending on whether the result of e1
was true
or false
respectively, and the result is returned. getValue
is called on e1
, and then setValue
is called on either e2
or e3
. e1 ` *e2*, e1
or*e2*<br>Logical
or`operator e1 &&
e2, e1 and
e2Logical
and
operator getValue
is called on e1
and the result is interpreted as a boolean. If false
, that result is returned; if true, getValue
is called on e2 and its value is returned. getValue
is called on e1
; if true
, setValue
is called on e2
. Note that e1
being false
prevents any further setting from taking place. e1 ` *e2*, *e1*
bor*e2*<br>Bitwise
or`operator e1
and e2
are interpreted as integers and the result is an integer. e1 ^
e2, e1 xor
e2Bitwise exclusive-or operator
e1
and e2
are interpreted as integers and the result is an integer. Cannot be the top-level expression passed to setValue
. e1 &
e2, e1 band
e2Bitwise and operator
e1
and e2
are interpreted as integers and the result is an integer. Cannot be the top-level expression passed to setValue
. e1 ==
e2, e1 eq
e2Equality test
e1
!=
e2, e1 neq
*e2*Inequality test Equality is tested for as follows. If either value is null
, they are equal if and only if both are null
. If they are the same object or the equals()
method says they are equal, they are equal. If they are both Number
s, they are equal if their values as double-precision floating point numbers are equal. Otherwise, they are not equal. These rules make numbers compare equal more readily than they would normally, if just using the equals method. Cannot be the top-level expression passed to setValue
. e1 <
e2, e1 lt
e2Less than comparison
e1
<=
e2, e1 lte
e2Less than or equals comparison
e1
>
e2, e1 gt
e2Greater than comparison
e1
>=
e2, e1 gte
e2*Greater than or equals comparison
*e1
in
e2List membership comparison
e1
not in
e2List non-membership comparison The ordering operators compare with
compareTo()
if their arguments are non-numeric and implement Comparable
; otherwise, the arguments are interpreted as numbers and compared numerically. The in operator is not from Java; it tests for inclusion of e1 in e2, where e2 is interpreted as a collection. This test is not efficient: it iterates the collection. However, it uses the standard OGNL equality test. Cannot be the top-level expression passed to setValue
. e1 <<
e2, e1 shl
e2Bit shift left
e1
>>
e2, e1 shr
e2Bit shift right
e1
>>>
e2, e1 ushr
e2Logical shift right
e1
and e2
are interpreted as integers and the result is an integer. Cannot be the top-level expression passed to setValue
. e1 +
e2Addition
e1
-
e2Subtraction The plus operator concatenates strings if its arguments are non-numeric; otherwise it interprets its arguments as numbers and adds them. The minus operator always works on numbers. Cannot be the top-level expression passed to
setValue
. e1*
e2Multiplication
e1
/
e2Division
e1
%
e2Remainder Multiplication, division, which interpret their arguments as numbers, and remainder, which interprets its arguments as integers. Cannot be the top-level expression passed to
setValue
. +
eUnary plus
-
eUnary minus
!
e, not
eLogical not
~
eBitwise not
e
instanceof
*class*Class membership Unary plus is a no-op, it simply returns the value of its argument. Unary minus interprets its argument as a number. Logical not interprets its argument as a boolean. Bitwise not interprets its argument as an integer. The class argument to instanceof is the fully qualified name of a Java class. Cannot be the top-level expression passed to
setValue
. e.
method(
args)
Method call
e
.
property*Property
*e1
[
e2 ]
Index
e1
.{
e2 }
Projection
e1
.{?
e2 }
Selection
e1
.(
e2)
Subexpression evaluation
e1
(
e2)
Expression evaluation Generally speaking, navigation chains are evaluated by evaluating the first expression, then evaluating the second one with the result of the first as the source object. Some of these forms can be passed as top-level expressions to
setValue
and others cannot. Only those chains that end in property references (e.property), indexes (e1[e2]
), and subexpressions (e1.(e2)
) can be; and expression evaluations can be as well. For the chains, getValue
is called on the left-hand expression (e
or e1
), and then setValue
is called on the rest with the result as the target object. constant*Constant(
*e )
Parenthesized expression
method
(
args)
Method call
property
Property reference
[
e ]
Index reference
{
e,
… }
List creation
#
variableContext variable reference
@
class@
method(
args)
Static method reference
@
class@
fieldStatic field reference
new
class(
args)
Constructor call
new
array-component-class[] {
e,
… }
Array creation
#{
e1 :
e2,
… }
Map creation
#@
classname@{
e1 :
e2,
… }
Map creation with specific subclass
:[
e ]
Lambda expression definition Basic expressions Only property references (property
), indexes ([e]
), and variable references (#variable
) can be passed as top-level expressions to setValue
. For indexes, getValue
is called on e
, and then the result is used as the property “name” (which might be a String
or any other kind of object) to set in the current target object. Variable and property references are set more directly.参考文章:
OGNL官方文档:http://commons.apache.org/proper/commons-ognl/language-guide.html
- OGNL表达式语言介绍
- OGNL表达式语言介绍
- OGNL表达式语言
- OGNL表达式语言介绍
- OGNL表达式语言
- ognl表达式语言
- 六、OGNL表达式语言
- OGNL表达式语言
- OGNL表达式语言学习
- OGNL表达式语言1
- OGNL表达式语言
- OGNL表达式语言
- OGNL表达式语言(一)
- 国际化、OGNL表达式语言
- OGNL表达式语言学习
- OGNL表达式语言
- Struts2-----Ognl表达式语言
- Ognl表达式语言
- 质因子的分解
- android webview setTimeout不执行
- 克罗内克积 Kronecker product
- 【Luogu】P1006 传纸条 DP
- 使用 MyBatis-generator 插件逆向工程生成 Mapper、Dao、PO 文件的方法
- Ognl表达式语言
- Cadence.ADW.v16.60.015.Linux 1CD
- MacBook安装MacOS系统
- win32程序创建按钮并响应点击
- 安卓 传感器基础
- 机器人领域的期刊和会议
- CentOs 7怎么联网 怎么配置静态IP
- 扫雷
- CodeForces