网站制作xiu021网络推广赚钱平台有哪些
文章目录
- OGNL 介绍
- OGNL 使用场景
- - ognl
- - 主要功能
- - 注意事项
- - Ognl类的主要方法
- - 设置值
- - 获取值
- - 使用示例
- - Mybatis
- Java原生表达式的使用
- - Fastjson
- - JSONPath类的主要方法
- - 主要功能
- - JSONPath的优势
- - 使用示例
- Spring不选择OGNL的原因
OGNL 介绍
OGNL(Object Graph Navigation Language)表达式语言是一种用于Java语言的表达式语言,专门用于在对象图中进行导航和操作。
在Java中,OGNL可以让开发人员以简洁的方式访问和操作Java对象的属性、调用对象的方法,执行算术和逻辑运算,以及处理集合和数组等操作。OGNL的语法简洁明了,可以方便地用于在Java开发中进行动态属性存取、列表和Map操作、函数和方法调用等,为开发人员提供了便利的数据操作手段。
OGNL 使用场景
常见使用场景:
- ognl
- Fastjson
- ognl
使用ognl包需要引入依赖
maven依赖:
<dependency><groupId>ognl</groupId><artifactId>ognl</artifactId><version>3.3.4</version>
</dependency>
- 主要功能
-
访问对象属性:
使用点号(.)来访问对象的属性(也可设置对象的属性)。例如:person.name 表示访问 person 对象的 name 属性。
-
调用对象方法
使用at符号(@)来调用对象的方法。例如:@java.lang.Math@random() 表示调用 Math 类的 random 方法。
-
访问集合和数组:
使用方括号([])来访问集合或数组中的元素。例如:myList[0] 表示访问 myList 集合中的第一个元素。
-
赋值和表达式计算:
支持变量赋值和基本的算术、逻辑运算符。例如:age > 18 && age < 60 表示对 age 变量进行逻辑判断。
-
条件表达式:
支持条件运算符,如三元运算符 condition ? true : false。
-
对象引用:
使用(#)符号来引用对象。例如:#person.name 表示引用 person 对象的 name 属性。
-
内置对象:
OGNL中有一些内置对象,如 #context(上下文对象)、#root(根对象)、#this(当前对象)等,可以方便地用于表达式中的引用和操作。
- 注意事项
- 当表达式expression中的属性不存在时,获取或设置值会报错
- Ognl类的主要方法
applyExpressionMaxLength
:设置Ognl 表达式的最大允许长度限制- void applyExpressionMaxLength(Integer expressionMaxLength)
- expressionMaxLength:表达式的最大允许长度
- void applyExpressionMaxLength(Integer expressionMaxLength)
freezeExpressionMaxLength
:冻结 Ognl 表达式的最大允许长度的限制- void freezeExpressionMaxLength()
thawExpressionMaxLength
:解除 Ognl 表达式的最大允许长度的限制- void thawExpressionMaxLength()
createDefaultContext
:创建一个默认的 Ognl 上下文对象- Map createDefaultContext(Object root)
- root:根对象
- Map createDefaultContext(Object root, ClassResolver classResolver)
- root:根对象
- classResolver:类解析器
- Map createDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter)
- root:根对象
- classResolver:类解析器
- converter:类型转换器
- Map createDefaultContext(Object root, MemberAccess memberAccess)
- root:根对象
- memberAccess:成员访问对象
- Map createDefaultContext(Object root, MemberAccess memberAccess, ClassResolver classResolver, TypeConverter converter)
- root:根对象
- memberAccess:成员访问对象
- classResolver:类解析器
- converter:类型转换器
- Map createDefaultContext(Object root)
addDefaultContext
:向默认 Ognl 上下文中添加一个自定义的上下文对象- Map addDefaultContext(Object root, Map context)
- root:根对象
- context:上下文对象
- Map addDefaultContext(Object root, ClassResolver classResolver, Map context)
- root:根对象
- classResolver:类解析器
- context:上下文对象
- Map addDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, Map context)
- root:根对象
- classResolver:类解析器
- converter:类型转换器
- context:上下文对象
- Map addDefaultContext(Object root, MemberAccess memberAccess, ClassResolver classResolver, TypeConverter converter, Map context)
- root:根对象
- memberAccess:成员访问对象
- classResolver:类解析器
- converter:类型转换器
- context:上下文对象
- Map addDefaultContext(Object root, Map context)
compileExpression
:将字符串表达式编译为 Ognl 表达式对象- Node compileExpression(OgnlContext context, Object root, String expression)
- context:上下文对象
- expression:字符串表达式
- Node compileExpression(OgnlContext context, Object root, String expression)
parseExpression
:将字符串表达式解析为 Ognl 表达式对象- Object parseExpression(String expression)
- expression:字符串表达式
- Object parseExpression(String expression)
getLastEvaluation
:从上下文中获取最后一个评估(Evaluation)对象- Evaluation getLastEvaluation(Map context)
- context:上下文对象
- Evaluation getLastEvaluation(Map context)
setRoot
:设置 Ognl 表达式的根对象- void setRoot(Map context, Object root)
- context:上下文对象
- root:根对象
- void setRoot(Map context, Object root)
getRoot
:获取 Ognl 表达式的根对象- Object getRoot(Map context)
- context:上下文对象
- Object getRoot(Map context)
isConstant
:判断给定的表达式是否是常量- isConstant(Object tree)
- tree:Ognl 表达式对象
- isConstant(Object tree, Map context)
- tree:Ognl 表达式对象
- context:上下文对象
- isConstant(String expression)
- expression:字符串表达式
- isConstant(String expression, Map context)
- expression:字符串表达式
- context:上下文对象
- isConstant(Object tree)
isSimpleProperty
:判断给定的表达式是否是简单的属性- isSimpleProperty(String expression)
- expression:字符串表达式
- isSimpleProperty(String expression, Map context)
- expression:字符串表达式
- context:上下文对象
- isSimpleProperty(Object tree)
- tree:Ognl 表达式对象
- isSimpleProperty(Object tree, Map context)
- tree:Ognl 表达式对象
- context:上下文对象
- isSimpleProperty(String expression)
isSimpleNavigationChain
:判断给定的表达式是否是简单的导航链- isSimpleNavigationChain(String expression)
- expression:字符串表达式
- isSimpleNavigationChain(String expression, Map context)
- expression:字符串表达式
- context:上下文对象
- isSimpleNavigationChain(Object tree)
- tree:Ognl 表达式对象
- isSimpleNavigationChain(Object tree, Map context)
- tree:Ognl 表达式对象
- context:上下文对象
- isSimpleNavigationChain(String expression)
setValue
:将给定的值设置到根对象的属性中-
void setValue(String expression, Object root, Object value)
根据表达式定位到根对象的属性,并将给定的值设置为该属性的值- expression:字符串表达式
- root:根对象
- value:要设置的值
-
void setValue(String expression, Map context, Object root, Object value)
使用给定的上下文对象和根对象,根据表达式定位到根对象的属性,并将给定的值设置为该属性的值- expression:字符串表达式
- context:上下文对象
- root:根对象
- value:要设置的值
-
void setValue(Object tree, Object root, Object value)
使用表达式对象定位到根对象的属性,并将给定的值设置为该属性的值- tree:Ognl 表达式对象
- root:根对象
- value:要设置的值
-
void setValue(Object tree, Map context, Object root, Object value)
使用给定的上下文对象和根对象,根据表达式对象定位到根对象的属性,并将给定的值设置为该属性的值- tree:Ognl 表达式对象
- context:上下文对象
- root:根对象
- value:要设置的值
-
void setValue(ExpressionAccessor expression, OgnlContext context, Object root, Object value)
使用给定的表达式访问器、上下文对象和根对象,定位到根对象的属性,并将给定的值设置为该属性的值- expression:Ognl 表达式访问器
- context:Ognl 表达式访问器
- root:根对象
- value:要设置的值
-
getValue
:通过给定的表达式从根对象中获取属性值- Object getValue(String expression, Object root)
根据表达式定位到根对象的属性,并返回该属性的值- expression:字符串表达式
- root:根对象
- Object getValue(String expression, Object root, Class resultType)
根据表达式定位到根对象的属性,并将返回的值转换为指定的结果类型- expression:字符串表达式
- root:根对象
- resultType:结果类型
- Object getValue(String expression, Map context, Object root)
使用给定的上下文对象和根对象,根据表达式定位到根对象的属性,并返回该属性的值- expression:字符串表达式
- context:上下文对象
- root:根对象
- Object getValue(String expression, Map context, Object root, Class resultType)
使用给定的上下文对象和根对象,根据表达式定位到根对象的属性,并将返回的值转换为指定的结果类型- expression:字符串表达式
- context:上下文对象
- root:根对象
- resultType:结果类型
- Object getValue(Object tree, Object root)
使用表达式对象定位到根对象的属性,并返回该属性的值- tree:Ognl 表达式对象
- root:根对象
- Object getValue(Object tree, Object root, Class resultType)
使用表达式对象定位到根对象的属性,并将返回的值转换为指定的结果类型- tree:Ognl 表达式对象
- root:根对象
- resultType:结果类型
- Object getValue(Object tree, Map context, Object root)
使用给定的上下文对象和根对象,根据表达式对象定位到根对象的属性,并返回该属性的值- tree:Ognl 表达式对象
- context:上下文对象
- root:根对象
- Object getValue(Object tree, Map context, Object root, Class resultType)
使用给定的上下文对象和根对象,根据表达式对象定位到根对象的属性,并将返回的值转换为指定的结果类型- tree:Ognl 表达式对象
- context:上下文对象
- root:根对象
- resultType:结果类型
- Object getValue(ExpressionAccessor expression, OgnlContext context, Object root)
使用给定的表达式访问器、上下文对象和根对象,定位到根对象的属性,并返回该属性的值- expression:Ognl 表达式访问器
- context:Ognl 上下文对象
- root:根对象
- Object getValue(ExpressionAccessor expression, OgnlContext context, Object root, Class resultType)
使用给定的表达式访问器、上下文对象和根对象,定位到根对象的属性,并将返回的值转换为指定的结果类型- expression:Ognl 表达式访问器
- context:Ognl 上下文对象
- root:根对象
- resultType:结果类型
- Object getValue(String expression, Object root)
- 设置值
-
使用字符串表达式方式设置值
public static void main(String[] args) throws Exception {// 创建一个根对象Person person = new Person("John", 25);// 创建一个 Ognl 上下文OgnlContext context = new OgnlContext();context.setRoot(person);// 使用字符串表达式方式设置值Ognl.setValue("name", context, person, "Alice");Ognl.setValue("age", context, person, 30);// 输出更新后的属性值System.out.println(person.getName()); // 输出:AliceSystem.out.println(person.getAge()); // 输出:30}
-
使用 Ognl 表达式对象方式设置值
public static void main(String[] args) throws Exception {// 创建一个根对象Person person = new Person("John", 25);// 创建一个 Ognl 表达式对象Object tree = Ognl.parseExpression("name");// 使用表达式对象方式设置值Ognl.setValue(tree, person, "Alice");// 输出更新后的属性值System.out.println(person.getName()); // 输出:Alice}
-
使用 Ognl 表达式访问器和 Ognl 上下文对象方式设置根值
public static void main(String[] args) throws OgnlException {// 创建一个根对象Person person = new Person("John", 25);// 创建一个 Ognl 上下文OgnlContext context = new OgnlContext();context.setRoot(person);// 创建一个 Ognl 表达式访问器ExpressionAccessor expression = OgnlRuntime.getPropertyAccessor(Person.class);// 使用表达式访问器和上下文对象设置值Object tree = Ognl.parseExpression("age");Ognl.setValue(expression, context, person, tree, 30);// 输出更新后的属性值System.out.println(person.getAge()); // 输出:30}
- 获取值
-
使用字符串表达式方式获取值
public static void main(String[] args) throws OgnlException {// 创建一个根对象Person person = new Person("Alice", 30);// 使用字符串表达式方式获取值Object nameValue = Ognl.getValue("name", person);System.out.println(nameValue); // 输出:Alice// 使用字符串表达式方式获取值Object ageValue = Ognl.getValue("age", person);System.out.println(ageValue); // 输出:30}
-
使用字符串表达式及Ognl 上下文对象方式获取值
public static void main(String[] args) throws OgnlException {// 创建一个根对象Person person = new Person("Alice", 30);// 创建一个 Ognl 上下文OgnlContext context = new OgnlContext();context.setRoot(person);// 使用带上下文参数的字符串表达式方式获取值Object nameValue = Ognl.getValue("name", context, person);System.out.println(nameValue); // 输出:Alice// 使用带上下文参数的字符串表达式方式获取值Object ageValue = Ognl.getValue("age", context, person);System.out.println(ageValue); // 输出:30}
-
使用 Ognl 表达式对象方式获取值
public static void main(String[] args) throws OgnlException {// 创建一个根对象Person person = new Person("Alice", 30);// 创建一个 Ognl 表达式对象Object nameTree = Ognl.parseExpression("name");// 使用表达式对象方式获取值Object nameValue = Ognl.getValue(nameTree, person);System.out.println(nameValue); // 输出:Alice}
-
使用 Ognl 表达式对象及Ognl 上下文对象方式获取值
public static void main(String[] args) throws OgnlException {// 创建一个根对象Person person = new Person("Alice", 30);// 创建一个 Ognl 上下文OgnlContext context = new OgnlContext();context.setRoot(person);// 创建一个 Ognl 表达式对象Object nameTree = Ognl.parseExpression("name");// 使用表达式对象方式获取值Object nameValue = Ognl.getValue(nameTree, context, person);System.out.println(nameValue); // 输出:Alice}
-
使用自定义的表达式访问器和上下文对象方式获取值
public static void main(String[] args) throws OgnlException {// 创建一个根对象Person person = new Person("Alice", 30);// 创建一个 Ognl 上下文OgnlContext context = new OgnlContext();context.setRoot(person);// 创建一个自定义的表达式访问器ExpressionAccessor expression = OgnlRuntime.getPropertyAccessor(Person.class);// 使用自定义的表达式访问器和上下文对象获取值Object ageValue = Ognl.getValue(expression, context, person, "age");System.out.println(ageValue); // 输出:30}
- 使用示例
maven依赖
<dependency><groupId>ognl</groupId><artifactId>ognl</artifactId><version>3.3.4</version>
</dependency>
实现源码
public class OGNLTest {@Data@NoArgsConstructor@AllArgsConstructorpublic static class User {public Integer userId;public String userName;public Sex sex;}@Data@NoArgsConstructor@AllArgsConstructorpublic static class Sex {public Integer sexCode;public String sexName;}public static void main(String[] args) throws OgnlException {// 访问对象属性User user = new User(111111, "哈哈", new Sex(1, "男"));Integer userId = (Integer) Ognl.getValue("userId", user);System.out.println(userId);// 111111Integer sexCode = (Integer) Ognl.getValue("sex.sexCode", user);System.out.println(sexCode);// 1// 调用对象方法Double random = (Double) Ognl.getValue("@java.lang.Math@random()", null);System.out.println(random);// 0.9562367273068916// 访问集合和数组List<User> list = Stream.of(user).collect(Collectors.toList());String sexName = (String) Ognl.getValue("[0].sex.sexName", list);System.out.println(sexName);// 男// 赋值和表达式计算boolean isMan = (Boolean) Ognl.getValue("sex.sexCode == 1", user);System.out.println(isMan);// true// 条件表达式String sex = (String) Ognl.getValue("sex.sexCode == 1 ? \"男\" : \"女\"", user);System.out.println(sex);// 男// 对象引用Map<String,Object> context = new HashMap<>();context.put("aaa", new Sex(2, "女"));Integer sexCode1 = (Integer) Ognl.getValue("#aaa.sexCode", context, user);System.out.println(sexCode1);// 2// 内置对象Integer sexCode2 = (Integer) Ognl.getValue("#root.sex.sexCode", user);System.out.println(sexCode2);// 1Integer sexCode3 = (Integer) Ognl.getValue("#this.sex.sexCode", user);System.out.println(sexCode3);// 1}
}
- Mybatis
MyBatis 早期版本确实使用过 OGNL 作为表达式语言,特别是在动态 SQL 处理中。在 MyBatis 的 XML 配置文件中,OGNL 被用来处理一些复杂的表达式,例如在 、 等标签中进行条件判断。
然而,由于 OGNL 存在一些性能和安全问题,MyBatis 在后续版本中逐步淘汰了 OGNL,转而使用更为简洁和安全的 OGNL 变种 或 Java 原生表达式。目前,OGNL 仍然可以通过自定义插件使用,但它已不再是 MyBatis 的核心功能。
Java原生表达式更简单、更安全,并且能够直接利用 Java 语言的语法和功能进行条件判断、循环等操作。
Java原生表达式的使用
在 MyBatis 中,Java原生表达式主要用于动态 SQL 的编写,特别是在 、、 等标签中,用于控制 SQL 的生成逻辑。
基本语法:
在 MyBatis 中,Java原生表达式通常出现在如下标签的属性中:
- :用于条件判断
- :类似于 switch-case 的控制结构
- :用于循环生成 SQL 部分
- :用于动态 SQL 中的空白字符去除
常用的Java 原生表达式:
- 条件表达式
- 三元运算符
- 逻辑运算符
- 逻辑运算(&&, ||, !)
- 数学运算(+, -, *, /)
- 类型转换(通过 (type) 强制转换)
- 方法调用(如 string.equals())
使用示例:
(1) 标签中的 Java 原生表达式:
标签用于根据某个条件动态地生成 SQL 片段。我们可以在 标签中直接使用 Java 表达式进行条件判断。
<select id="selectUser" resultType="User">SELECT * FROM users<where><if test="username != null">AND username = #{username}</if><if test="age != null">AND age = #{age}</if></where>
</select>
- test=“username != null” 中的 username != null 就是一个 Java 原生表达式。
- 在这里,test 属性值就是 Java 表达式的条件判断语句,如果表达式结果为 true,那么 中的 SQL 片段才会被加入到最终生成的 SQL 中。
(2) 标签中的 Java 原生表达式:
标签类似于 Java 中的 switch-case 语法,用于根据多个条件选择生成不同的 SQL 片段。
<select id="selectUser" resultType="User">SELECT * FROM users<where><choose><when test="age != null">AND age = #{age}</when><when test="username != null">AND username = #{username}</when><otherwise>AND status = 'active'</otherwise></choose></where>
</select>
- 允许在多个 中根据不同条件选择合适的 SQL 片段。
- 每个 中的 test 属性也可以使用 Java 表达式。
(3) 标签中的 Java 原生表达式:
标签用于循环生成 SQL 片段,通常用于处理数组、集合或列表类型的参数。
<select id="selectUsersByIds" resultType="User">SELECT * FROM users<where><foreach collection="ids" item="id" open="AND id IN (" separator="," close=")">#{id}</foreach></where>
</select>
- collection=“ids”:表示传入的参数集合或数组。
- 在 标签中,我们可以使用 Java 表达式来处理循环逻辑和参数拼接。
(4) 使用 Java 原生三元运算符:
在 MyBatis 中,Java原生表达式也支持使用 Java 的三元运算符来简化条件判断。
<select id="selectUser" resultType="User">SELECT * FROM usersWHERE status = <if test="status != null">#{status}</if><if test="status == null">'active'</if>
</select>
使用三元运算符来替代多重条件判断,改为:
<select id="selectUser" resultType="User">SELECT * FROM usersWHERE status = #{status != null ? status : 'active'}
</select>
(5) 标签中的 Java 原生表达式:
标签用于对生成的 SQL 语句进行前后字符的去除(如去掉 AND 或 OR 等)。
<select id="selectUser" resultType="User">SELECT * FROM users<trim prefix="WHERE" prefixOverrides="AND |OR "><if test="status != null">AND status = #{status}</if><if test="age != null">AND age = #{age}</if></trim>
</select>
- Fastjson
- JSONPath类的主要方法
-
Object
eval
(String json, String path)
通过给定的 JSON 数据和 JSONPath 表达式,返回匹配该表达式的结果对象 -
JSONArray
extract
(Object json, String path)
根据指定的 JSONPath 表达式,从 JSON 对象中提取匹配的 JSON 数组。返回一个 JSONArray 对象 -
boolean
contains
(Object json, String path)
判断 JSON 数据中是否包含匹配指定 JSONPath 表达式的内容 -
boolean
containsValue
(Object json, String path, Object value)
判断 JSON 对象中匹配 JSONPath 表达式的内容是否包含指定的值 -
int
size
(Object json, String path)
计算 JSONPath 表达式匹配的内容的大小,并返回匹配结果的个数 -
Set<?>
keySet
(Object json, String path)
返回 JSONPath 表达式匹配的所有键值的 Set 集合 -
void
arrayAdd
(Object rootObject, String path, Object… values)
在 JSON 对象中的指定位置添加一个或多个元素 -
void
remove
(Object json, String path)
根据指定的 JSONPath 表达式,从 JSON 对象中移除匹配路径的内容 -
void
set
(Object json, String path, Object value)
根据指定的 JSONPath 表达式,在 JSON 对象中设置匹配路径的值为指定的 value -
JSONPath
compile
(String path)
编译 JSONPath 表达式,返回一个对应的 JSONPath 对象这个方法可以提高后续对同一个 JSONPath 表达式的操作性能。
-
Object
read
(String json, String path)
读取 JSON 数据中指定 JSONPath 表达式的值 -
List
paths
(Object json, String path)
获取 JSON 对象中匹配指定 JSONPath 表达式的所有路径,并返回一个 JSONPath 列表 -
void
setArrayItem
(Object json, String path, Object value)
根据指定的 JSONPath 表达式,在 JSON 数组中设置匹配路径的元素为指定的 value -
void
removeArrayItem
(Object json, String path, int index)
根据指定的 JSONPath 表达式,从 JSON 数组中移除指定索引位置的元素
- 主要功能
-
设置JSON对象中的属性值
-
获取JSON对象中的属性值
- JSONPath的优势
- 设置JSON对象中的属性值时,如果属性不存在,也会自动创建
- 获取JSON对象中的属性值是,如果属性不存在,不会报错空指针,会返回null
- 使用示例
public class OGNLTest {public static void main(String[] args) {// 设置JSON对象中的属性值JSONObject jsonObject = new JSONObject();JSONPath.set(jsonObject, "$.role.roleName", "管理员");JSONPath.set(jsonObject, "$.user.userName", "Joker");System.out.println(JSON.toJSONString(jsonObject));// {"role":{"roleName":"管理员"},"user":{"userName":"Joker"}}JSONObject jsonObject1 = JSON.parseObject("{\"role\":{\"roleName\":\"管理员\"},\"user\":{\"userName\":\"Joker\"}}");JSONPath.set(jsonObject1, "$.user.userId", 18);System.out.println(JSON.toJSONString(jsonObject1));// {"role":{"roleName":"管理员"},"user":{"userName":"Joker","userId":18}}// 获取JSON对象中的属性值System.out.println(JSONPath.eval(jsonObject, "$.role.roleName"));// 管理员System.out.println(JSONPath.eval(jsonObject, "$.user.userName"));// JokerSystem.out.println(JSONPath.eval(jsonObject, "$.user.age"));// nullSystem.out.println(JSONPath.eval(jsonObject, "$.user.sex.setName"));// null}
}
Spring不选择OGNL的原因
Spring 官方推荐的表达式语言是Spring Expression Language (SpEL) ,它提供了更强大的功能和更多的特性。
为什么Spring使用SpEL替代了OGNL了呢:
- OGNL 在早期版本中被发现存在一些安全漏洞,尤其是当其用于动态求值时,可能会导致恶意代码执行。因此,在使用 OGNL 时要特别小心,尽量避免在不信任的输入中执行 OGNL 表达式,或使用一些安全措施来过滤不安全的表达式。
可参考文章:
Spring SpEL表达式的使用