605 lines
22 KiB
Markdown
605 lines
22 KiB
Markdown
- [Spel](#spel)
|
||
- [Spel表达式计算](#spel表达式计算)
|
||
- [示例](#示例)
|
||
- [Concept](#concept)
|
||
- [调用方法](#调用方法)
|
||
- [调用属性](#调用属性)
|
||
- [调用构造器](#调用构造器)
|
||
- [在特定对象上计算表达式](#在特定对象上计算表达式)
|
||
- [EvaluationContext](#evaluationcontext)
|
||
- [EvaluationContext实现类](#evaluationcontext实现类)
|
||
- [TypeConversion](#typeconversion)
|
||
- [在定义Bean对象时使用Spel表达式](#在定义bean对象时使用spel表达式)
|
||
- [为field指定默认值](#为field指定默认值)
|
||
- [通过setter为field指定默认值](#通过setter为field指定默认值)
|
||
- [@Autowired方法和构造器](#autowired方法和构造器)
|
||
- [Spel语法](#spel语法)
|
||
- [字面量表达式](#字面量表达式)
|
||
- [字符串类型字面量](#字符串类型字面量)
|
||
- [Properties,Array,List,Map,Indexer](#propertiesarraylistmapindexer)
|
||
- [访问属性](#访问属性)
|
||
- [Array](#array)
|
||
- [Map](#map)
|
||
- [列表表示](#列表表示)
|
||
- [数组构建](#数组构建)
|
||
- [方法调用](#方法调用)
|
||
- [操作符](#操作符)
|
||
- [关系操作符](#关系操作符)
|
||
- [instanceof操作符和matches操作符](#instanceof操作符和matches操作符)
|
||
- [逻辑操作符](#逻辑操作符)
|
||
- [数学运算符](#数学运算符)
|
||
- [赋值运算符](#赋值运算符)
|
||
- [类型操作符](#类型操作符)
|
||
- [构造方法](#构造方法)
|
||
- [变量](#变量)
|
||
- [#this and #root](#this-and-root)
|
||
- [方法注册](#方法注册)
|
||
- [引用bean对象](#引用bean对象)
|
||
- [三元操作符](#三元操作符)
|
||
- [Elvis Operator](#elvis-operator)
|
||
- [空安全操作符](#空安全操作符)
|
||
- [集合过滤操作符](#集合过滤操作符)
|
||
- [集合映射](#集合映射)
|
||
- [表达式模板](#表达式模板)
|
||
|
||
|
||
# Spel
|
||
## Spel表达式计算
|
||
### 示例
|
||
如下是一个Spel表达式计算示例:
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
Expression exp = parser.parseExpression("'Hello World'");
|
||
String message = (String) exp.getValue();
|
||
// 最终message计算的值是'Hello World'
|
||
```
|
||
### Concept
|
||
`ExpressionParser`接口用于对表达式字符串进行解析,在上述示例中,表达式字符串是一个由单引号包围起来的字符串字面量。
|
||
|
||
`Expression`接口则是负责对表达式字符串进行计算。
|
||
|
||
在调用`parser.parseExpression`和`exp.getValue`,分别会抛出`ParseException`和`EvaluationException`异常。
|
||
|
||
Spel支持许多特性,例如调用方法,访问属性,调用构造方法等,示例如下:
|
||
|
||
#### 调用方法
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
|
||
String message = (String) exp.getValue();
|
||
// message值为Hello World!
|
||
```
|
||
|
||
#### 调用属性
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
|
||
// invokes 'getBytes().length'
|
||
Expression exp = parser.parseExpression("'Hello World'.bytes.length");
|
||
int length = (Integer) exp.getValue();
|
||
```
|
||
|
||
#### 调用构造器
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
|
||
String message = exp.getValue(String.class);
|
||
```
|
||
|
||
通过`public <T> T getValue(Class<T> desiredResultType)`方法,向getValue方法传递一个Class对象,可以避免在调用getValue方法调用之后需要将返回值手动转化为特定类型。如果类型转化失败,会抛出一个EvaluationException异常。
|
||
|
||
#### 在特定对象上计算表达式
|
||
Spel支持在一个特定的对象上(该对象通常被称作root object)进行计算,例如如下示例:
|
||
```java
|
||
// Create and set a calendar
|
||
GregorianCalendar c = new GregorianCalendar();
|
||
c.set(1856, 7, 9);
|
||
|
||
// The constructor arguments are name, birthday, and nationality.
|
||
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
|
||
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
|
||
Expression exp = parser.parseExpression("name"); // Parse name as an expression
|
||
String name = (String) exp.getValue(tesla);
|
||
// name == "Nikola Tesla"
|
||
|
||
exp = parser.parseExpression("name == 'Nikola Tesla'");
|
||
boolean result = exp.getValue(tesla, Boolean.class);
|
||
// result == true
|
||
```
|
||
|
||
### EvaluationContext
|
||
EvalutaionContext用于给表达式提供一个执行的上下文环境,通过EvalutaionContext,可以向context中放置一个变量,并且在后续中使用该变量:
|
||
```java
|
||
// 向context中放入一个list变量
|
||
ctx.setVariable("list",list)
|
||
|
||
// 在后续表达式中即可使用放入的list变量
|
||
// 获取放入context中的list变量的值
|
||
parser.parseExpression("#list[0]").getValue(ctx);
|
||
// 设置context中list变量的值
|
||
parser.parseExpression("#list[0]").setValue(ctx , "false");
|
||
```
|
||
#### EvaluationContext实现类
|
||
- SimpleEvaluationContext:实现了Spel语言的部分特性
|
||
- StandardEvaluationContext:实现了Spel语言的全部特性
|
||
|
||
### TypeConversion
|
||
默认情况下,spel会使用`org.springframework.core.convert.ConversionService`中的Conversion Service。该conversion service包含内置的类型转换,并且可以为类型之间指定自定义的类型转换。该转换是支持泛型的。
|
||
|
||
如下为支持泛型的示例:
|
||
```java
|
||
class Simple {
|
||
public List<Boolean> booleanList = new ArrayList<>();
|
||
}
|
||
|
||
Simple simple = new Simple();
|
||
simple.booleanList.add(true);
|
||
|
||
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
|
||
|
||
// "false" is passed in here as a String. SpEL and the conversion service
|
||
// will recognize that it needs to be a Boolean and convert it accordingly.
|
||
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");
|
||
|
||
// b is false
|
||
Boolean b = simple.booleanList.get(0);
|
||
```
|
||
|
||
### 在定义Bean对象时使用Spel表达式
|
||
可以通过@Value注解来为bean对象的域、方法参数、构造器参数指定默认值。通过如下方式来指定表达式:
|
||
- `#{ <expression string> }.`
|
||
|
||
#### 为field指定默认值
|
||
```java
|
||
public class FieldValueTestBean {
|
||
|
||
@Value("#{ systemProperties['user.region'] }")
|
||
private String defaultLocale;
|
||
|
||
public void setDefaultLocale(String defaultLocale) {
|
||
this.defaultLocale = defaultLocale;
|
||
}
|
||
|
||
public String getDefaultLocale() {
|
||
return this.defaultLocale;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 通过setter为field指定默认值
|
||
```java
|
||
public class PropertyValueTestBean {
|
||
|
||
private String defaultLocale;
|
||
|
||
@Value("#{ systemProperties['user.region'] }")
|
||
public void setDefaultLocale(String defaultLocale) {
|
||
this.defaultLocale = defaultLocale;
|
||
}
|
||
|
||
public String getDefaultLocale() {
|
||
return this.defaultLocale;
|
||
}
|
||
}
|
||
```
|
||
#### @Autowired方法和构造器
|
||
@Autowired方法和构造器可以使用@Value注解为参数指定默认值:
|
||
```java
|
||
public class SimpleMovieLister {
|
||
|
||
private MovieFinder movieFinder;
|
||
private String defaultLocale;
|
||
|
||
@Autowired
|
||
public void configure(MovieFinder movieFinder,
|
||
@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
|
||
this.movieFinder = movieFinder;
|
||
this.defaultLocale = defaultLocale;
|
||
}
|
||
|
||
// ...
|
||
}
|
||
```
|
||
|
||
```java
|
||
public class MovieRecommender {
|
||
|
||
private String defaultLocale;
|
||
|
||
private CustomerPreferenceDao customerPreferenceDao;
|
||
|
||
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao,
|
||
@Value("#{systemProperties['user.country']}") String defaultLocale) {
|
||
this.customerPreferenceDao = customerPreferenceDao;
|
||
this.defaultLocale = defaultLocale;
|
||
}
|
||
|
||
// ...
|
||
}
|
||
```
|
||
|
||
## Spel语法
|
||
### 字面量表达式
|
||
字面量表达式支持字符串、数值(整数、实数、十六进制数)、boolean类型和null。
|
||
#### 字符串类型字面量
|
||
其中字符串类型的字面量通过单引号包围,如果想要将单引号本身放入字符串字面量中,可以使用两个单引号:
|
||
```java
|
||
// 该值为h''h
|
||
parser.parseExpression("'h''''h'").getValue()
|
||
```
|
||
|
||
字面量的使用如下所示:
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
|
||
// evals to "Hello World"
|
||
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();
|
||
|
||
double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();
|
||
|
||
// evals to 2147483647
|
||
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();
|
||
|
||
boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
|
||
|
||
Object nullValue = parser.parseExpression("null").getValue();
|
||
```
|
||
### Properties,Array,List,Map,Indexer
|
||
#### 访问属性
|
||
```java
|
||
int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context);
|
||
|
||
|
||
String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);
|
||
```
|
||
属性名的第一个字符不区分大小写。
|
||
#### Array
|
||
可以通过方括号来访问array和list中的元素内容:
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
|
||
// Inventions Array
|
||
StandardEvaluationContext teslaContext = new StandardEvaluationContext(tesla);
|
||
|
||
// evaluates to "Induction motor"
|
||
String invention = parser.parseExpression("inventions[3]").getValue(teslaContext,
|
||
String.class);
|
||
|
||
|
||
// Members List
|
||
StandardEvaluationContext societyContext = new StandardEvaluationContext(ieee);
|
||
|
||
// evaluates to "Nikola Tesla"
|
||
String name = parser.parseExpression("Members[0].Name").getValue(societyContext, String.class);
|
||
|
||
// List and Array navigation
|
||
// evaluates to "Wireless communication"
|
||
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(societyContext,String.class);
|
||
```
|
||
#### Map
|
||
map中的值可以在方括号中指定字面量key来访问,示例如下所示:
|
||
```java
|
||
// Officer's Dictionary
|
||
|
||
Inventor pupin = parser.parseExpression("Officers['president']").getValue(societyContext,Inventor.class);
|
||
|
||
// evaluates to "Idvor"
|
||
String city =
|
||
parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(societyContext,
|
||
String.class);
|
||
|
||
// setting values
|
||
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext,"Croatia");
|
||
```
|
||
#### 列表表示
|
||
列表可以直接通过如下方式来表示:
|
||
```java
|
||
// evaluates to a Java list containing the four numbers
|
||
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
|
||
|
||
List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);
|
||
```
|
||
#### 数组构建
|
||
spel表达式中数组构建可以使用java语法:
|
||
```java
|
||
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
|
||
|
||
// Array with initializer
|
||
int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context);
|
||
|
||
// Multi dimensional array
|
||
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
|
||
```
|
||
### 方法调用
|
||
表达式中方法调用也可以使用java中的语法:
|
||
```java
|
||
// string literal, evaluates to "bc"
|
||
String c = parser.parseExpression("'abc'.substring(2, 3)").getValue(String.class);
|
||
|
||
// evaluates to true
|
||
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(societyContext, Boolean.class);
|
||
```
|
||
### 操作符
|
||
#### 关系操作符
|
||
关系操作符示例如下:
|
||
```java
|
||
// evaluates to true
|
||
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);
|
||
|
||
// evaluates to false
|
||
boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);
|
||
|
||
// evaluates to true
|
||
boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);
|
||
```
|
||
|
||
与null比较时的规则:
|
||
- 任何值都比null大,`X>null`永远为true
|
||
- 没有任何值比null小,`X<null`永远为false
|
||
|
||
#### instanceof操作符和matches操作符
|
||
```java
|
||
// evaluates to false
|
||
boolean falseValue = parser.parseExpression("'xyz' instanceof T(int)").getValue(Boolean.class);
|
||
|
||
// evaluates to true
|
||
boolean trueValue =
|
||
parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
|
||
|
||
//evaluates to false
|
||
boolean falseValue =
|
||
parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
|
||
```
|
||
#### 逻辑操作符
|
||
逻辑操作符支持and、or、not
|
||
```java
|
||
// -- AND --
|
||
|
||
// evaluates to false
|
||
boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class);
|
||
|
||
// evaluates to true
|
||
String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";
|
||
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
|
||
|
||
// -- OR --
|
||
|
||
// evaluates to true
|
||
boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class);
|
||
|
||
// evaluates to true
|
||
String expression = "isMember('Nikola Tesla') or isMember('Albert Einstein')";
|
||
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
|
||
|
||
// -- NOT --
|
||
|
||
// evaluates to false
|
||
boolean falseValue = parser.parseExpression("!true").getValue(Boolean.class);
|
||
|
||
|
||
// -- AND and NOT --
|
||
String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
|
||
boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
|
||
```
|
||
#### 数学运算符
|
||
```java
|
||
// Addition
|
||
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
|
||
|
||
String testString =
|
||
parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class); // 'test string'
|
||
|
||
// Subtraction
|
||
int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4
|
||
|
||
double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000
|
||
|
||
// Multiplication
|
||
int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6
|
||
|
||
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0
|
||
|
||
// Division
|
||
int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2
|
||
|
||
double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0
|
||
|
||
// Modulus
|
||
int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3
|
||
|
||
int one = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1
|
||
|
||
// Operator precedence
|
||
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21
|
||
```
|
||
#### 赋值运算符
|
||
```java
|
||
Inventor inventor = new Inventor();
|
||
StandardEvaluationContext inventorContext = new StandardEvaluationContext(inventor);
|
||
|
||
parser.parseExpression("Name").setValue(inventorContext, "Alexander Seovic2");
|
||
|
||
// alternatively
|
||
|
||
String aleks = parser.parseExpression("Name = 'Alexandar Seovic'").getValue(inventorContext,
|
||
String.class);
|
||
|
||
```
|
||
#### 类型操作符
|
||
T操作符会获取一个class对象,在传入T的类型为java.lang下类时,不用指定全类名,否则应指定全类名.
|
||
类中的静态方法也可以通过该操作符进行调用:
|
||
```java
|
||
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
|
||
|
||
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
|
||
|
||
boolean trueValue =
|
||
parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
|
||
.getValue(Boolean.class);
|
||
```
|
||
|
||
#### 构造方法
|
||
可以通过new操作符来调用构造方法,在调用构造方法需要指定全类名,但是基类和String可以不指定全类名:
|
||
```java
|
||
Inventor einstein =
|
||
p.parseExpression("new org.spring.samples.spel.inventor.Inventor('Albert Einstein',
|
||
'German')")
|
||
.getValue(Inventor.class);
|
||
|
||
//create new inventor instance within add method of List
|
||
p.parseExpression("Members.add(new org.spring.samples.spel.inventor.Inventor('Albert Einstein',
|
||
'German'))")
|
||
.getValue(societyContext);
|
||
|
||
```
|
||
### 变量
|
||
可以通过`#argName`语法来引用变量,可以通过`StandardEvaluationContext.setVariable`方法来设置变量:
|
||
```java
|
||
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
|
||
StandardEvaluationContext context = new StandardEvaluationContext(tesla);
|
||
context.setVariable("newName", "Mike Tesla");
|
||
|
||
parser.parseExpression("Name = #newName").getValue(context);
|
||
|
||
System.out.println(tesla.getName()) // "Mike Tesla"
|
||
```
|
||
#### #this and #root
|
||
#this变量一直都是被定义的,用于引用当前评估对象,#root变量也是一直都被定义的,引用root context对象。
|
||
```java
|
||
// create an array of integers
|
||
List<Integer> primes = new ArrayList<Integer>();
|
||
primes.addAll(Arrays.asList(2,3,5,7,11,13,17));
|
||
|
||
// create parser and set variable 'primes' as the array of integers
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||
context.setVariable("primes",primes);
|
||
|
||
// all prime numbers > 10 from the list (using selection ?{...})
|
||
// evaluates to [11, 13, 17]
|
||
List<Integer> primesGreaterThanTen =
|
||
(List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context);
|
||
```
|
||
|
||
### 方法注册
|
||
可以向StandardEvaluationContext中注册方法,注册的方法可以在spel中使用:
|
||
```java
|
||
public abstract class StringUtils {
|
||
|
||
public static String reverseString(String input) {
|
||
StringBuilder backwards = new StringBuilder();
|
||
for (int i = 0; i < input.length(); i++)
|
||
backwards.append(input.charAt(input.length() - 1 - i));
|
||
}
|
||
return backwards.toString();
|
||
}
|
||
}
|
||
```
|
||
注册方法到context中:
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||
|
||
context.registerFunction("reverseString",
|
||
StringUtils.class.getDeclaredMethod("reverseString",
|
||
new Class[] { String.class }));
|
||
|
||
String helloWorldReversed =
|
||
parser.parseExpression("#reverseString('hello')").getValue(context, String.class);
|
||
```
|
||
### 引用bean对象
|
||
如果为context配置了bean resolver,可以通过`@`语法来查询bean对象:
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||
context.setBeanResolver(new MyBeanResolver());
|
||
|
||
// This will end up calling resolve(context,"foo") on MyBeanResolver during evaluation
|
||
Object bean = parser.parseExpression("@foo").getValue(context);
|
||
```
|
||
### 三元操作符
|
||
```java
|
||
parser.parseExpression("Name").setValue(societyContext, "IEEE");
|
||
societyContext.setVariable("queryName", "Nikola Tesla");
|
||
|
||
expression = "isMember(#queryName)? #queryName + ' is a member of the ' " +
|
||
"+ Name + ' Society' : #queryName + ' is not a member of the ' + Name + ' Society'";
|
||
|
||
String queryResultString =
|
||
parser.parseExpression(expression).getValue(societyContext, String.class);
|
||
// queryResultString = "Nikola Tesla is a member of the IEEE Society"
|
||
```
|
||
### Elvis Operator
|
||
类似于`Optional.ofNullable(var).orElse()`,`?:`表达式可以达成同样效果:
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
|
||
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
|
||
StandardEvaluationContext context = new StandardEvaluationContext(tesla);
|
||
|
||
String name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, String.class);
|
||
|
||
System.out.println(name); // Nikola Tesla
|
||
|
||
tesla.setName(null);
|
||
|
||
name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, String.class);
|
||
|
||
System.out.println(name); // Elvis Presley
|
||
```
|
||
### 空安全操作符
|
||
`?.`操作符和js中的类似:
|
||
```java
|
||
ExpressionParser parser = new SpelExpressionParser();
|
||
|
||
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
|
||
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));
|
||
|
||
StandardEvaluationContext context = new StandardEvaluationContext(tesla);
|
||
|
||
String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class);
|
||
System.out.println(city); // Smiljan
|
||
|
||
tesla.setPlaceOfBirth(null);
|
||
|
||
city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class);
|
||
|
||
System.out.println(city); // null - does not throw NullPointerException!!!
|
||
```
|
||
### 集合过滤操作符
|
||
`?[selectionExpression]`可以完成集合的过滤,该操作符可以同时针对list和map,在针对map操作时,操作的是`Map.Entry`,entry的key和value都可以作为属性访问。
|
||
```java
|
||
// 针对list
|
||
List<Inventor> list = (List<Inventor>)
|
||
parser.parseExpression("Members.?[Nationality == 'Serbian']").getValue(societyContext);
|
||
|
||
// 针对map
|
||
Map newMap = parser.parseExpression("map.?[value<27]").getValue();
|
||
```
|
||
### 集合映射
|
||
类似于Stream.map,spel支持集合映射操作符
|
||
```java
|
||
// returns [ 'Smiljan', 'Idvor' ]
|
||
// 将Inventor集合映射为city集合
|
||
List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]");
|
||
```
|
||
### 表达式模板
|
||
表达式模板允许将字面量文本和一个或多个评估component混合在一起,评估块语法类似于`${}`
|
||
```java
|
||
String randomPhrase =
|
||
parser.parseExpression("random number is #{T(java.lang.Math).random()}",
|
||
new TemplateParserContext()).getValue(String.class);
|
||
|
||
// evaluates to "random number is 0.7038186818312008"
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|