SpEL表达式转载
# 前言
自从学了 SpEL表达式语言 , 我发现 字符串 简直是万能类型 , 不仅能存 , 能定义 , 能访问 , 能调用 等 , 一应俱全 , 非常强大 . 特别是搭配SpringBoot常用的注解上 , 能够实现很多高级逻辑功能 , 仅通过简短的表达式解决了大多核心功能! 非常值得学习的一个知识点!!
转载文章 : https://zhuanlan.zhihu.com/p/174786047 (opens new window)
# SpEL基础
SpEL在求表达式值时一般分为四步 :
- 创建解析器:SpEL使用ExpressionParser接口表示解析器,提供SpelExpressionParser默认实现
- 解析表达式:使用ExpressionParser的parseExpression来解析相应的表达式为Expression对象
- 构造上下文:准备比如变量定义等等表达式需要的上下文数据
- 求值:通过Expression接口的getValue方法根据上下文获得表达式值
应用示例 :
public static void main(String[] args) {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("('Hello'+'World').concat(#end)");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("end","!");
String value = expression.getValue(context, String.class);
System.out.println("value = " + value);
System.out.println("original = " + "HelloWorld".concat("!"));
}
/* 结果
value = HelloWorld!
original = HelloWorld!
*/
# ExpressionParser接口
解析器 , 意图解析表达式
public interface ExpressionParser {
Expression parseExpression(String expressionString) throws ParseException;
/**
* 分析表达式字符串并返回可用于重复计算的表达式对象。
* 形参:
* expressionString – 要解析的原始表达式字符串
* context – 影响此表达式解析例程的上下文(可选)
* 返回值: 已分析的表达式
*/
Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
}
# 自定义模板
ParserContext是标识表达式解析的前后模板 , 如 : 前缀 #{ , 后缀 }
// 定义1
ParserContext parserContext = new ParserContext() {
@Override
public boolean isTemplate() {
return true;
}
@Override
public String getExpressionPrefix() {
return "#{";
}
@Override
public String getExpressionSuffix() {
return "}";
}
};
// 定义2
ParserContext parserContext = new TemplateParserContext("%{","}")
# EvaluationContext接口
构造上下文 , 意图 为表达式自定义变量赋值
核心方法 :
- setRootObject() : 设置根对象
- setVariable() : 设置自定义变量
点击展开代码
public interface EvaluationContext {
/**
* 返回默认的根上下文对象,应根据该对象解析非限定属性/方法/等。计算表达式时可以覆盖此字段。
*/
TypedValue getRootObject();
/**
* 返回将依次要求读取/写入属性的访问器列表。
*/
List<PropertyAccessor> getPropertyAccessors();
/**
* 返回一个解析器列表,这些解析器将依次被要求查找构造函数。
*/
List<ConstructorResolver> getConstructorResolvers();
/**
* 返回解析程序的列表,这些解析程序将依次被要求查找方法。
*/
List<MethodResolver> getMethodResolvers();
/**
* 返回一个可以按名称查找 bean 的 Bean 解析器。
*/
@Nullable
BeanResolver getBeanResolver();
/**
* 返回可用于按短名称或完全限定名查找类型的类型定位器。
*/
TypeLocator getTypeLocator();
/**
* 返回一个类型转换器,该转换器可以将值从一种类型转换(或强制)到另一种类型。
*/
TypeConverter getTypeConverter();
/**
* 返回一个类型比较器,用于比较对象对的相等性。
*/
TypeComparator getTypeComparator();
/**
* 返回一个运算符重载器,该运算符重载器可能支持超过标准类型集之间的数学运算。
*/
OperatorOverloader getOperatorOverloader();
/**
* 将指定 Supplier 创建的值分配给此评估上下文中的命名变量。
* 与 setVariable(String, Object) 相反,此方法只应用于支持表达式中的赋值运算符 (=)。
* 形参:
* name – 要分配的变量的名称
* valueSupplier – 要分配给变量的值的供应商
* 返回值: TypedValue 包装分配的值
*/
default TypedValue assignVariable(String name, Supplier<TypedValue> valueSupplier) {
TypedValue typedValue = valueSupplier.get();
setVariable(name, typedValue.getValue());
return typedValue;
}
/**
* 将此评估上下文中的命名变量设置为指定值。
* 与 assignVariable(String, Supplier) 相反,此方法只应在直接与 EvaluationContext 交互时以编程方式调用
* 形参:
* name – 要设置的变量的名称 value – 要放置在变量中的值
*/
void setVariable(String name, @Nullable Object value);
/**
* 在此评估上下文中查找命名变量。
* 形参:
* name – 要查找的变量的名称
* 返回值: 变量的值,或者 null 如果未找到
*/
@Nullable
Object lookupVariable(String name);
}
# Expression接口
表达式对象 , 意图 执行表达式得到的结果(求值)
点击展开代码
public interface Expression {
String getExpressionString();
@Nullable
Object getValue() throws EvaluationException;
@Nullable
<T> T getValue(@Nullable Class<T> desiredResultType) throws EvaluationException;
@Nullable
Object getValue(@Nullable Object rootObject) throws EvaluationException;
@Nullable
<T> T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType) throws EvaluationException;
@Nullable
Object getValue(EvaluationContext context) throws EvaluationException;
@Nullable
Object getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
@Nullable
<T> T getValue(EvaluationContext context, @Nullable Class<T> desiredResultType) throws EvaluationException;
@Nullable
<T> T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> desiredResultType)
throws EvaluationException;
@Nullable
Class<?> getValueType() throws EvaluationException;
@Nullable
Class<?> getValueType(@Nullable Object rootObject) throws EvaluationException;
@Nullable
Class<?> getValueType(EvaluationContext context) throws EvaluationException;
@Nullable
Class<?> getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
@Nullable
TypeDescriptor getValueTypeDescriptor() throws EvaluationException;
@Nullable
TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException;
@Nullable
TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException;
@Nullable
TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
boolean isWritable(@Nullable Object rootObject) throws EvaluationException;
boolean isWritable(EvaluationContext context) throws EvaluationException;
boolean isWritable(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
void setValue(@Nullable Object rootObject, @Nullable Object value) throws EvaluationException;
void setValue(EvaluationContext context, @Nullable Object value) throws EvaluationException;
void setValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Object value) throws EvaluationException;
}
应用示例 :
@Test
void test() {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("HelloWorld%{#end}",new TemplateParserContext("%{","}"));
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("end","!!");
String value = expression.getValue(context, String.class);
System.out.println("value = " + value);
System.out.println("original = " + "HelloWorld".concat("!!"));
}
/* 结果
value = HelloWorld!!
original = HelloWorld!
*/
# SpEL语法
# 基本表达式
SpEL支持的字面量包括:字符串、数字类型(int、long、float、double)、布尔类型、null类型
点击展开代码
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
System.out.println("'Hello World!' = " +
parser.parseExpression("'Hello World!'").getValue(String.class));
System.out.println("1 = " + parser.parseExpression("1").getValue(Integer.class));
System.out.println("-1L = " + parser.parseExpression("-1L").getValue(long.class));
System.out.println("1.1 = " + parser.parseExpression("1.1").getValue(Float.class));
System.out.println("1.1E+2 = " + parser.parseExpression("1.1E+2").getValue(double.class));
System.out.println("0xa = " + parser.parseExpression("0xa").getValue(Integer.class));
System.out.println("0xaL = " + parser.parseExpression("0xaL").getValue(long.class));
System.out.println("true = " + parser.parseExpression("true").getValue(boolean.class));
System.out.println("false = " + parser.parseExpression("false").getValue(boolean.class));
System.out.println("null = " + parser.parseExpression("null").getValue(Object.class));
}
/* 结果
'Hello World!' = Hello World!
1 = 1
-1L = -1
1.1 = 1.1
1.1E+2 = 110.0
0xa = 10
0xaL = 10
true = true
false = false
null = null
*/
# 运算表达式
SpEL支持加(+)、减(-)、乘(*)、除(/)、求余(%)、幂(^)运算
点击展开代码
@Test
void test() {
SpelExpressionParser parser = new SpelExpressionParser();
System.out.println("1+1 = " + parser.parseExpression("1+1").getValue(Integer.class));;
System.out.println("2-1 = " + parser.parseExpression("2-1").getValue(Integer.class));;
System.out.println("2*2 = " + parser.parseExpression("2*2").getValue(Integer.class));;
System.out.println("4/2 = " + parser.parseExpression("4/2").getValue(Integer.class));;
System.out.println("4%3 = " + parser.parseExpression("4%3").getValue(Integer.class));;
System.out.println("2^2 = " + parser.parseExpression("2^2").getValue(Integer.class));;
}
/* 结果
1+1 = 2
2-1 = 1
2*2 = 4
4/2 = 2
4%3 = 1
2^2 = 4
*/
# 关系表达式
等于(==)、不等于(!=)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=),区间(between)运算
SpEL也支持单词缩写应用 : (支持小写)
- 等于 :
EQ
:==
- 不等于 :
NE
:!=
- 大于 :
GT
:>
- 大于等于 :
GE
:>=
- 小于 :
LT
:<
- 小于等于 :
LE
:<=
点击展开代码
@Test
void test() {
SpelExpressionParser parser = new SpelExpressionParser();
System.out.println("1<2 = " +
parser.parseExpression("1<2").getValue(Boolean.class));
System.out.println("1 GT 2 (大于)= " +
parser.parseExpression("1 GT 2").getValue(Boolean.class));
System.out.println("1!=2 = " +
parser.parseExpression("1!=2").getValue(Boolean.class));
System.out.println("1 eq 2 (等于)= " +
parser.parseExpression("2 eq 2").getValue(Boolean.class));
System.out.println("1 between {1,3} = " +
parser.parseExpression("2 between {1,3}").getValue(Boolean.class));
System.out.println("6 between {1,3} = " +
parser.parseExpression("4 between {1,3}").getValue(Boolean.class));
}
/* 结果
1<2 = true
1 GT 2 (大于)= false
1!=2 = true
1 eq 2 (等于)= true
1 between {1,3} = true
6 between {1,3} = false
*/
# 逻辑表达式
且(and
/ &&
)、或(or
/ ||
)、非(!
/ NOT
)
点击展开代码
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
System.out.println("2>1 and (!true or !false) = " +
parser.parseExpression("2>1 and (!true or !false)").getValue(boolean.class));
System.out.println("2>1 && (!true || !false) = " +
parser.parseExpression("2>1 && (!true || !false)").getValue(boolean.class));
System.out.println("2>1 and (NOT true or NOT false) = " +
parser.parseExpression("2>1 and (NOT true or NOT false)").getValue(boolean.class));
System.out.println("2>1 && (NOT true || NOT false) = " +
parser.parseExpression("2>1 && (NOT true || NOT false)").getValue(boolean.class));
}
/* 结果
2>1 and (!true or !false) = true
2>1 && (!true || !false) = true
2>1 and (NOT true or NOT false) = true
2>1 && (NOT true || NOT false) = true
*/
# 其他表达式
- 三目运算
- 正则表达
- 括号优先表达式
点击展开代码
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
// 三目运算
System.out.println("2>1?true:false = " +
parser.parseExpression("2>1?true:false").getValue(boolean.class));
// 简化三目运算符
System.out.println("1>2?:true = " +
parser.parseExpression("1>2?:true").getValue(boolean.class));
// 正则表达式
System.out.println("'abc'.matches('[a-z]+') = " +
parser.parseExpression("'abc'.matches('[a-z]+')").getValue(boolean.class));
System.out.println("'123' matches '\\d{3}' = " +
parser.parseExpression("'123' matches '\\d{3}' ").getValue(boolean.class));
// 括号优先
System.out.println("(2+3)*(2+4) = " +
parser.parseExpression("(2+3)*(2+4)").getValue());
System.out.println("((2*2)+(2*4))+((3*2)+(3*4)) = " +
parser.parseExpression("((2*2)+(2*4))+((3*2)+(3*4))").getValue());
}
/* 结果
2>1?true:false = true
1>2?:true = false
'abc'.matches('[a-z]+') = true
'123' matches '\d{3}' = true
(2+3)*(2+4) = 30
((2*2)+(2*4))+((3*2)+(3*4)) = 30
*/
# Java代码表达式解析
# 类类型表达式
使用 T(Type)
来表示 Class对象实例 , Type
必须是全限定类名 , 出了基础类型的包路径外 , 使用类表达式同时还可以访问静态资源(成员 变量/方法)
点击展开代码
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
// 访问基础类型
System.out.println("T(String) = " +
parser.parseExpression("T(String)"));
// 访问其他类 (其他类必须全限定名)
System.out.println("T(com.ruoyi.test.SpelTest) = " +
parser.parseExpression("T(com.ruoyi.test.SpelTest)"));
// 静态成员访问 , 实际 Integer.MAX_VALUE
System.out.println("T(Integer).MAX_VALUE = " +
parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class));
// 静态方法访问 , 实际 Integer.paraseInt('1')
System.out.println("T(Integer).paraseInt('1') = " +
parser.parseExpression("T(Integer).parseInt('1')").getValue(int.class));
}
/* 结果
T(String) = org.springframework.expression.spel.standard.SpelExpression@2a32de6c
T(com.ruoyi.test.SpelTest) = org.springframework.expression.spel.standard.SpelExpression@7692d9cc
T(Integer).MAX_VALUE = 2147483647
T(Integer).paraseInt('1') = 1
*/
# 类实例化
类实例化 , 通过Java new
关键字实现 , 类名要全限定名 , 除java基础类型外
点击展开代码
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
System.out.println("new String('路人甲java') = " +
parser.parseExpression("new String('路人甲java')").getValue(String.class));
System.out.println("new java.util.Date() = " +
parser.parseExpression("new java.util.Date()").getValue(Date.class));
}
/* 结果
new String('路人甲java') = 路人甲java
new java.util.Date() = Fri Oct 13 10:55:55 CST 2023
*/
# instanceof表达式
和Java原生用法同理 , 但需要借助 T(Type) 识别类型 , 不能使用 .class 识别
点击展开代码
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
System.out.println("'路人甲' instanceof T(String) = " +
parser.parseExpression("'路人甲' instanceof T(String)").getValue(Boolean.class));
System.out.println("new com.ruoyi.test.SpelTest() instanceof T(com.ruoyi.test.SpelTest) = " +
parser.parseExpression("new com.ruoyi.test.SpelTest() instanceof T(com.ruoyi.test.SpelTest)").getValue(Boolean.class));
}
/* 结果
'路人甲' instanceof T(String) = true
new com.ruoyi.test.SpelTest() instanceof T(com.ruoyi.test.SpelTest) = true
*/
# 变量定义及引用
在模板中可以实现变量定义 , 通过 EvaluationContext.setVariable()方法 实现
点击展开代码
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("num1", 1);
context.setVariable("num2", 2);
System.out.println("#num1 + #num2 = " +
parser.parseExpression("#num1 + #num2").getValue(context, Integer.class));
//StandardEvaluationContext构造器传入root对象,可以通过#root来访问root对象
String root = new String("我是root对象");
context = new StandardEvaluationContext(root);
System.out.println("#root = " +
parser.parseExpression("#root").getValue(context, String.class));
//#this用来访问当前上线文中的对象
System.out.println("#this = " +
parser.parseExpression("#this").getValue(context, String.class));
}
/* 结果
#num1 + #num2 = 3
#root = 我是root对象
#this = 我是root对象
*/
# 自定义函数
SpEL也可以实现像引入变量一样使用函数 , 但目前仅支持 静态方法 . 通过 EvaluationContext.registerFunction()方法 进行注册自定义函数 (使用方式和引入变量一样)
引入前提需要自行通过Java反射拿到 静态方法对象
点击展开代码
@Test
void test() throws SecurityException, NoSuchMethodException {
//定义2个函数,registerFunction和setVariable都可以,不过从语义上面来看用registerFunction更恰当
StandardEvaluationContext context = new StandardEvaluationContext();
Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class);
context.registerFunction("parseInt1", parseInt);
context.setVariable("parseInt2", parseInt);
ExpressionParser parser = new SpelExpressionParser();
System.out.println("#parseInt1('3') = " +
parser.parseExpression("#parseInt1('3')").getValue(context, int.class));
System.out.println("#parseInt2('3') = " +
parser.parseExpression("#parseInt2('3')").getValue(context, int.class));
System.out.println("#parseInt1('3') == #parseInt2('3') = " +
parser.parseExpression("#parseInt1('3') == #parseInt2('3')").getValue(context, boolean.class));
}
/* 结果
#parseInt1('3') = 3
#parseInt2('3') = 3
#parseInt1('3') == #parseInt2('3') = true
*/
# 变量赋值
变量赋值通过 Expression.setValue()方法 为表达式赋值
点击展开代码
@Test
public void test() {
// 匿名内部类实例对象
Object obj = new Object() {
private Integer num1;
private Integer num2;
public Integer getNum1() {
return num1;
}
public void setNum1(Integer num1) {
this.num1 = num1;
}
public Integer getNum2() {
return num2;
}
public void setNum2(Integer num2) {
this.num2 = num2;
}
public Integer add() {
return this.num1 + this.num2;
}
@Override
public String toString() {
return "$classname{" +
"num1=" + num1 +
", num2=" + num2 +
'}';
}
};
{
//user为root对象
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext(obj);
// 会通过 setName()方法 存值
parser.parseExpression("#root.num1").setValue(context, 2);
parser.parseExpression("#root.num2").setValue(context, 2);
// 输出对象 , 默认使用 toString()方法
System.out.println("#root.num1 = " +
parser.parseExpression("#root.num1").getValue(context, Integer.class));
System.out.println("#root.num2 = " +
parser.parseExpression("#root.num2").getValue(context, Integer.class));
System.out.println("#root.add() = " +
parser.parseExpression("#root.add()").getValue(context, Integer.class));
System.out.println("#root = " +
parser.parseExpression("#root").getValue(context, obj.getClass()));
}
{
//user为变量
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("obj", obj);
parser.parseExpression("#obj.num1").setValue(context, 2);
parser.parseExpression("#obj.num2").setValue(context, 2);
System.out.println("#obj.num1 = " +
parser.parseExpression("#obj.num1").getValue(context, Integer.class));
System.out.println("#obj.num2 = " +
parser.parseExpression("#obj.num2").getValue(context, Integer.class));
System.out.println("#obj.add() = " +
parser.parseExpression("#obj.add()").getValue(context, Integer.class));
System.out.println("#obj = " +
parser.parseExpression("#obj").getValue(context, obj.getClass()));
}
}
/* 结果
#root.num1 = 2
#root.num2 = 2
#root.add() = 4
#root = $classname{num1=2, num2=2}
#obj.num1 = 2
#obj.num2 = 2
#obj.add() = 4
#obj = $classname{num1=2, num2=2}
*/
# 安全导航表达式
但在表达式中获取属性 , 如 : user.name , 但这个过程不能确保user数据是有效的 , 因此需要安全导航来进行避免空指针异常问题 .
应用方式 : (对象/属性)?.属性
(这个使用方法和JS中的ES6语法类似)
点击展开代码
@Test
public void test() {
Object user = new Object() {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "$classname{" +
"name='" + name + '\'' +
'}';
}
};
//user为变量
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("user", user);
parser.parseExpression("#user.name").setValue(context, "张三丰");
try {
System.out.println("#user.name = " +
parser.parseExpression("#user.name").getValue(context, String.class));
} catch (EvaluationException | ParseException e) {
System.out.println("数据访问空指针异常 [#user.name]");
}
try {
System.out.println("#obj.name = " +
parser.parseExpression("#obj.name").getValue(context, String.class));
} catch (EvaluationException | ParseException e) {
System.out.println("数据访问空指针异常 [#obj.name]");
}
try {
System.out.println("#user?.name = " +
parser.parseExpression("#user?.name").getValue(context, String.class));
} catch (EvaluationException | ParseException e) {
System.out.println("数据访问空指针异常 [#user.name]");
}
try {
System.out.println("#obj?.name = " +
parser.parseExpression("#obj?.name").getValue(context, String.class));
} catch (EvaluationException | ParseException e) {
System.out.println("数据访问空指针异常 [#obj.name]");
}
}
/* 结果
#user.name = 张三丰
数据访问空指针异常 [#obj.name]
#user?.name = 张三丰
#obj?.name = null
*/
# Bean引用
支持SpringBoot Ioc容器引入Bean , 通过 @
符号 引入Bean , 引入需要 BeanResolver接口 实现
点击展开代码
static class Car {
public String name;
public Car(String name) {
this.name = name;
}
public String run() {
return name + " 跑起来了...";
}
}
@Test
public void test() {
// 存Bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
Car car = new Car("保时捷");
factory.registerSingleton("car", car);
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new BeanFactoryResolver(factory));
ExpressionParser parser = new SpelExpressionParser();
System.out.println("@car.name = " +
parser.parseExpression("@car.name").getValue(context, String.class));
System.out.println("@car.run() = " +
parser.parseExpression("@car.run()").getValue(context, String.class));
Car carBean = parser.parseExpression("@car").getValue(context, Car.class);
System.out.println("car = " + car);
System.out.println("carBean = " + carBean);
System.out.println("car == factory.getBean('car') = " + car == factory.getBean("car"));
System.out.println("carBean == factory.getBean('car') = " + carBean == factory.getBean("car"));
}
/* 结果
carName = 保时捷
car.run() = 保时捷在奔跑
car = com.ruoyi.test.SpelTest$Car@1dac5ef
carBean = com.ruoyi.test.SpelTest$Car@1dac5ef
car == factory.getBean('car') = true
carBean == factory.getBean('car') = true
*/
# 集合应用
# List
List 定义使用方式 {表达式1 , 表达式2 , 表达式n}
, 字面量表达式定义的List不可修改
点击展开代码
@Test
public void test14() {
ExpressionParser parser = new SpelExpressionParser();
// 对于字面量列表也将返回不可修改的List
List<Integer> result = parser.parseExpression("{1,2,3}").getValue(List.class);
System.out.println("result = " + result);
// 访问List
System.out.println("{1,2,3}[0] = " +
parser.parseExpression("{1,2,3}[0]").getValue(int.class));
System.out.println("{1,2,3}.get(1) = " +
parser.parseExpression("{1,2,3}.get(1)").getValue(int.class));
try {
result.set(0, 2);
} catch (Exception e) {
System.out.println("set错误 , result不能更改");
}
// 对于列表中只要有一个不是字面量表达式,将只返回原始List (运算表达式)
List<List<Integer>> result2 = parser.parseExpression("{{1+2,2+4},{3,4+4}}").getValue(List.class);
result2.get(0).set(0, 1);
System.out.println("result2 = " + result2);
// 声明数组并初始化
System.out.println("new int[2]{1,2} = " +
parser.parseExpression("new int[2]{1,2}").getValue(int[].class)[0]);
// 访问数组
System.out.println("new int[2]{1,2}[1] = " +
parser.parseExpression("new int[2]{1,2}[1]").getValue(int.class));
}
/* 结果
result = [1, 2, 3]
{1,2,3}[0] = 1
{1,2,3}.get(1) = 2
set错误 , result不能更改
result2 = [[1, 6], [3, 8]]
new int[2]{1,2} = 1
new int[2]{1,2}[1] = 2
*/
# Map
Map 定义通过 EvaluationContext.setVariable()方法 存Map字典 , 访问方式 map[key]
点击展开代码
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext();
//SpEL对Map字典元素访问的支持
Map<String, Integer> map = new HashMap<>();
map.put("a", 8);
map.put("b", 10);
context.setVariable("map", map);
System.out.println("#map['b'] = " +
parser.parseExpression("#map['b']").getValue(context, int.class));
}
/* 结果
#map['b'] = 8
*/
其他类型使用方式也同理
// SpEL目前支持所有集合类型的访问
Collection<Integer> collection = new HashSet<>();
collection.add(2);
collection.add(4);
collection.add(6);
context.setVariable("collection", collection);
System.out.println("#collection = " +
parser.parseExpression("#collection").getValue(context, int.class));
System.out.println("#collection[1] = " +
parser.parseExpression("#collection[1]").getValue(context, int.class));
/* 结果
#collection = 2
#collection[1] = 4
*/
# 集合选择
集合通过表达式筛选出满足条件的新集合 , 使用方式 (map|list).?[选择表达式]
, 表达式结果为布尔值控制筛选
- list 获取当前值
#this
- map 获取当前字典
key
/value
点击展开代码
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext();
List<Integer> list = Arrays.asList(2, 4, 6, 8, 10);
context.setVariable("list", list);
System.out.println("#list = " +
parser.parseExpression("#list").getValue(context, List.class));
System.out.println("#list.?[#this>6] = " +
parser.parseExpression("#list.?[#this>6]").getValue(context, List.class));
System.out.println("#list.?[(#this>2 && #this<8)] = " +
parser.parseExpression("#list.?[(#this>2 && #this<8)]").getValue(context, List.class));
}
/* 结果
#list = [2, 4, 6, 8, 10]
#list.?[#this>6] = [8, 10]
#list.?[(#this>2 && #this<8)] = [4, 6]
*/
@Test
void test() {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext();
Map<String,Integer> map = new HashMap<String,Integer>(){{
put("a",2);
put("b",4);
put("c",6);
put("d",8);
put("e",10);
}};
context.setVariable("map", map);
System.out.println("#map = " +
parser.parseExpression("#map").getValue(context, Map.class));
System.out.println("#map.?[key!='a'] = " +
parser.parseExpression("#map.?[key!='a']").getValue(context, Map.class));
System.out.println("#map.?[value > 6] = " +
parser.parseExpression("#map.?[value > 6]").getValue(context, Map.class));
System.out.println("#map.![value + 2] = " +
parser.parseExpression("#map.![value + 2]").getValue(context, List.class));
}
/* 结果
#map = {a=2, b=4, c=6, d=8, e=10}
#map.?[key!='a'] = {b=4, c=6, d=8, e=10}
#map.?[value > 6] = {d=8, e=10}
#map.![value + 2] = [4, 6, 8, 10, 12]
*/