23 SpEl
23.1 简介
Spring也有自己的EL,叫Spring Expression Language,简称SpEl。其可以在程序中单独使用,也可以在Spring应用中进行bean定义时使用。其核心是org.springframework.expression.Expression接口,Spring使用该接口来表示EL中的表达式。通过Expression接口的系列getValue()方法我们可以获取对应Expression在特定EvaluationContext下的值,也可以通过其系列setValue()方法来设值。对应的Expression通常不是由我们直接来new对应实现类的实例,而是通过Spring提供的org.springframework.expression.ExpressionParser接口的系列parseExpression()方法来将一个字符串类型的表达式解析为一个Expression。以下是一个简单的示例,在该示例中我们将字符串表达式“1+2”解析为一个Expression,然后进行计算得出其值为3。
@Test
public void test() {
String expressionStr = "1+2";
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(expressionStr);
Integer val = expression.getValue(Integer.class);
System.out.println(expressionStr + "的结果是:" + val);
}
Expression接口有一系列的getValue()方法,当其不接收任何参数时表示将会把Expression的计算结果当做一个Object进行返回,如果我们希望返回的是特定的类型,则可以传递对应的类型作为getValue()方法的参数,如上述示例中传递的Interger.class。我们也可以通过给Expression的getValue()方法传递EvaluationContext用以获取在特定环境下的计算结果,也可以传递一个Object作为Expression计算的rootObject。关于Expression接口的更多介绍请参考Spring的API文档。
23.2 示例
SpEl可以支持一般的算术运算,也可以支持逻辑运算,还可以支持对象的方法调用等。下面我们来看一些对应用法的示例。
23.2.1 算术运算
SpEl支持的算术运算可以是加、减、乘、除、求余、指数等。下面是一个对应的示例。
@Test
public void test01() {
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("(1+2)*5 + 8-6/2").getValue().equals(20));//加减乘除
Assert.assertTrue(parser.parseExpression("8%3").getValue().equals(2));//求余
Assert.assertTrue(parser.parseExpression("2.0e3").getValue().equals(2000.0));//指数
Assert.assertTrue(parser.parseExpression("2^3").getValue().equals(8));//指数
}
23.2.2 逻辑运算
逻辑运算就是我们熟悉的与、或、非,在SpEl中就对应“and”、“or”和“!”。
@Test
public void test02() {
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("true and true").getValue(Boolean.class));//与
Assert.assertTrue(parser.parseExpression("true or false").getValue(Boolean.class));//与
Assert.assertTrue(parser.parseExpression("!false").getValue(Boolean.class));//非
}
23.2.3 比较运算
比较运算就是我们熟悉的大于(>)、大于等于(>=)、小于(<)、小于等于(<=)、等于(==)和不等于(!=)。
@Test
public void test03() {
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("5>3").getValue(Boolean.class));
Assert.assertTrue(parser.parseExpression("5<=8").getValue(Boolean.class));
Assert.assertTrue(parser.parseExpression("5==5").getValue(Boolean.class));
Assert.assertTrue(parser.parseExpression("5!=6").getValue(Boolean.class));
}
23.2.4 字符串
SpEl允许我们在表达式中直接使用int、double、String等。我们的Expression可以通过对应的字符串进行解析,那么当我们的表达式就是需要表示一个字符串时应该如何表示呢?这个时候需要通过单引号“’”来进行包裹。而当我们的字符串中包含单引号时,那么对应的单引号需要使用一个单引号进行转义,即连续两个单引号。
@Test
public void test04() {
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("'abc'").getValue().equals("abc"));
Assert.assertTrue(parser.parseExpression("'''abc'").getValue().equals("'abc"));
}
23.2.5 访问方法
在SpEl表达式中我们也可以直接访问对象的方法。在下述示例中我们就直接在SpEl中访问了字符串的length()方法。
@Test
public void test05() {
ExpressionParser parser = new SpelExpressionParser();
//直接访问String的length()方法。
Assert.assertTrue(parser.parseExpression("'abc'.length()").getValue().equals(3));
}
23.2.6 使用EvaluationContext
我们先来看一个例子,在下列示例中我们在表达式中直接写name和getName(),这个时候Expression是无法解析的,因为其不知道name和getName()对应什么意思。
@Test
public void test06() {
ExpressionParser parser = new SpelExpressionParser();
parser.parseExpression("name").getValue();
parser.parseExpression("getName()").getValue();
}
通过指定EvaluationContext我们就可以让name和getName()变得有意义。指定了EvaluationContext之后,Expression将根据对应的EvaluationContext来进行解析。如下示例中我们构建了一个基于user对象的EvaluationContext,user对象将作为StandardEvaluationContext的rootObject,那么对应的Expression就将根据该rootObject对象来获取对应表达式的值。我们可以看到user对象定义了一个getName()方法,在解析name和getName()表达式时都将访问user对象的getName()方法,即它们的返回结果都为字符串“abc”。
@Test
public void test06() {
Object user = new Object() {
public String getName() {
return "abc";
}
};
EvaluationContext context = new StandardEvaluationContext(user);
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("name").getValue(context, String.class).equals("abc"));
Assert.assertTrue(parser.parseExpression("getName()").getValue(context, String.class).equals("abc"));
}
上述示例中的表达式name表示对应EvaluationContext的rootObject的一个属性,在进行解析时,如果对应的get方法存在,则将直接访问对应的get方法,如上述示例中的getName(),否则将直接对其进行访问,这个时候就需要我们的属性是公有的,以便外部类可以访问。
对于对象而言,我们可以访问其属性的属性或方法,中间以点进行连接。
23.2.7 使用rootObject
当我们的表达式是基于某一个对象的时,我们也可以把对应的对象作为一个rootObject传递给对应的Expression以进行取值。如上述示例我们也可以直接将user对象作为rootObject传递给对应的Expression以获取对应的值。
@Test
public void test07() {
Object user = new Object() {
public String getName() {
return "abc";
}
};
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("name").getValue(user, String.class).equals("abc"));
Assert.assertTrue(parser.parseExpression("getName()").getValue(user, String.class).equals("abc"));
}
23.2.8 List、Array、Map等元素的访问
在SpEl中我们可以通过索引的形式访问List或Array的某一个元素,对应的索引是从0开始的,以“list[index]”的形式出现。如下述示例中的test08_1和test08_2。
@Test
public void test08_1() {
Object user = new Object() {
public List<String> getInterests() {
List<String> interests = Arrays.asList(new String[] {"BasketBall", "FootBall"});
return interests;
}
};
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("interests[0]").getValue(user, String.class).equals("BasketBall"));
Assert.assertTrue(parser.parseExpression("interests[1]").getValue(user, String.class).equals("FootBall"));
}
@Test
public void test08_2() {
Object user = new Object() {
public String[] getInterests() {
return new String[] {"BasketBall", "FootBall"};
}
};
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("interests[0]").getValue(user, String.class).equals("BasketBall"));
Assert.assertTrue(parser.parseExpression("interests[1]").getValue(user, String.class).equals("FootBall"));
}
而对于Map而言,则是通过类似于“map[key]”的形式访问对应的元素的。示例如下。
@Test
public void test08_3() {
Object user = new Object() {
public Map<String, String> getInterests() {
Map<String, String> interests = new HashMap<String, String>();
interests.put("key1", "BasketBall");
interests.put("key2", "FootBall");
return interests;
}
};
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("interests['key1']").getValue(user, String.class).equals("BasketBall"));
Assert.assertTrue(parser.parseExpression("interests['key2']").getValue(user, String.class).equals("FootBall"));
}
相关推荐
Spring_SpEl表达式使用用例 只是一个简单的demo,有需要的可以看看
spring spEL 表达式详解 运行环境:eclipse 构建工具:maven 不提供maven构建,maven用来解决jar包的依赖
用于Spring Cloud Function SPEL表达式注入漏洞测试环境搭建,是编译好的服务端程序,命令号java -jar *.jar运行即可,服务端运行在127.0.0.1:8080端口
Spring Cloud Gateway Actuator API SpEL表达式注入命令执行 0day 漏洞复现
主要介绍了Spring spel表达式使用方法示例,通过一些实例向大家展示了spel表达式的用法,需要的朋友可以了解下。
今天小编就为大家分享一篇关于Spring组件开发模式支持SPEL表达式,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
SpringBoot 自定义注解,属性支持SPEL表达式。介绍了SPEL表达式的解析
主要介绍了Spring实战之Bean定义中的SpEL表达式语言支持操作,结合实例形式分析了Bean定义中的SpEL表达式语言操作步骤与实现技巧,需要的朋友可以参考下
今天小编就为大家分享一篇关于Spring Boot配置Thymeleaf(gradle)的简单使用,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
一、创建Spring Boot应用 二、SpEL结合@Value注解读取配置文件属性 三、SpEL结合 @Value注解读取系统环境变量 四、配置文件的占位符
Spring Cloud Function 是基于Spring Boot 的函数计算框架,它抽象出所有传输细节和基础架构,允许开发人员保留所有熟悉的工具和流程,并专注于业务逻辑。 批量检测脚本:python Spel_RCE_POC.py url.txt 反弹...
主要介绍了如何使用SpEL表达式实现动态分表查询,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
SpringCloud Function SpEL注入漏洞分析(CVE-2022-22963).doc
Spring Expression Language (SpEL)中文文档。基于Spring4.x。
主要介绍了spring表达式语言SpEL用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
CVE-2022-22947 SpringCloud GateWay SpEL RCE.doc
【第一章】 Spring概述 ——跟我学Spring3 【第二章】 IoC 之 2.1 IoC基础 ——跟我学Spring3 【第二章】 IoC 之 2.2 IoC 容器基本原理 ——跟我学Spring3 【第二章】 IoC 之 2.3 IoC的配置使用——跟我学Spring3 ...
基于SpringBoot、Spring表达式语言 (SpEL)、annotation的操作日志 ### 简介 * 使用annotation来标注方法,标记操作内容 * 使用SpEL来动态生成操作日志内容,使操作日志记录更加详细(记录操作内容ID等关键信息) * ...
opt-log基于SpringBoot、Spring表达式语言 (SpEL)、annotation的操作日志简介使用annotation来标注方法,标记操作内容使用SpEL来动态生成操作日志内容,使操作日志记录更加详细(记录操作内容ID等关键信息)同一个...
主要介绍了Spring实战之SpEl语法,结合实例形式分析了SpEl创建数组、集合及解析变量等相关操作原理与实现技巧,需要的朋友可以参考下