文章目录
推荐
下面文档基本就是官方文档的翻译,源自:Spring-SpEL表达式超级详细使用全解,做了一丢丢的练习实践补充(官方文档中的所有示例)
一、概述
1、什么是SpEL
SpEL(Spring Expression Language)是Spring框架中用于表达式语言的一种方式。它类似于其他编程语言中的表达式语言,用于在运行时计算值或执行特定任务。
SpEL提供了一种简单且强大的方式来访问和操作对象的属性、调用对象的方法,以及实现运算、条件判断等操作。它可以被用于XML和注解配置中,可以用于许多Spring框架中的特性,如依赖注入、AOP、配置文件等。
SpEL表达式可以在字符串中进行定义,使用特殊的语法和符号来表示特定的操作。例如,可以使用${expression}来表示一个SpEL表达式,其中expression是具体的SpEL语句。
SpEL支持各种操作和函数,包括算术运算、逻辑运算、条件判断、正则表达式匹配、集合操作等。它还支持访问上下文中的变量和参数,以及调用对象的方法。
2、SpEL能做什么
SpEL表达式具有广泛的功能,以下是一些SpEL表达式可以做的事情:
- 访问对象属性:SpEL表达式可以通过对象引用来访问对象的属性,例如${object.property}。
- 调用方法:SpEL表达式可以调用对象的方法,例如${object.method()}。
- 进行算术运算:SpEL表达式支持各种算术运算符,如加法、减法、乘法和除法。
- 进行逻辑运算:SpEL表达式支持逻辑运算符,如与、或、非等。
- 进行条件判断:SpEL表达式可以进行条件判断,例如通过if语句判断条件,并执行相应的操作。
- 访问集合元素和属性:SpEL表达式可以通过索引或键来访问集合中的元素或对象的属性。
- 执行正则表达式匹配:SpEL表达式可以执行正则表达式匹配,并返回匹配结果。
- 访问上下文变量和参数:SpEL表达式可以访问上下文中的变量和方法参数。
- 进行类型转换:SpEL表达式可以进行类型转换操作,将一个对象转换为另一种类型。
- 支持特殊操作符:SpEL表达式支持一些特殊的操作符,如Elvis操作符(?:)、安全导航操作符(?.)等。
总的来说,SpEL表达式可以用于在运行时计算值、执行任务和操作对象,提供了灵活且强大的表达能力,广泛应用于Spring框架中的各种功能和配置中。
二、SpEL表达式使用
1、文字表达式
支持的文字表达式类型有字符串、数值(int、real、hex)、布尔和null。字符串由单引号分隔。若要将单引号本身放在字符串中,请使用两个单引号字符。
通常来说,不会单纯的定义一个简单的文字表达式,而是通过方法调用等等复杂的操作,来完成一个功能:
// 定义Parser,可以定义全局的parser
ExpressionParser parser = new SpelExpressionParser();
// 获取字符串 "Hello World"
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();
// double类型 6.0221415E23
double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();
// int类型 2147483647
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();
// true
boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
// null
Object nullValue = parser.parseExpression("null").getValue();
2、属性, 数组, List, Map,和 索引
(1)属性操作
注意!属性名的第一个字母不区分大小写。
// 定义Parser,可以定义全局的parser
ExpressionParser parser = new SpelExpressionParser();
// 注意!属性名的第一个字母不区分大小写。 birthdate.year等效于Birthdate.Year
// 取出Inventor 中,birthdate属性的year属性
Inventor zhangsan = new Inventor("zhangsan", new Date(), "China");
// 定义StandardEvaluationContext ,传入一个操作对象
StandardEvaluationContext zhangsanContext = new StandardEvaluationContext(zhangsan);
int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(zhangsanContext);
System.out.println(year); // 2023
//取出Inventor的placeOfBirth的city属性
PlaceOfBirth placeOfBirth = new PlaceOfBirth("长沙", "中国");
zhangsan.setPlaceOfBirth(placeOfBirth);
String city = (String) parser.parseExpression("placeOfBirth.City").getValue(zhangsanContext);
System.out.println(city); // 长沙
(2)数组和List
数组和List的内容是通过使用方括号符号获得的。
// 定义Parser,可以定义全局的parser
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 省略数据初始化
// 取出tesla对象的inventions 第四个数据
String invention = parser.parseExpression("inventions[3]").getValue(
context, tesla, String.class);
// 取出ieee对象的第一个Member的name属性
String name = parser.parseExpression("Members[0].Name").getValue(
context, ieee, String.class);
// 取出ieee对象的第一个Member中的第七个Inventions
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(
context, ieee, String.class);
(3)Map
Map操作是通过key来获取的
// 取出societyContext的Officers中的key为president的值
Inventor pupin = parser.parseExpression("Officers['president']").getValue(
societyContext, Inventor.class);
String city = parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(
societyContext, String.class);
// Officers中key为advisors的值取第一个
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(
societyContext, "Croatia");
3、内嵌List
可以使用{}符号在表达式中直接表示List。{}本身意味着一个空列表。
// 定义Parser,可以定义全局的parser
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// [1, 2, 3, 4]
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
System.out.println(numbers);
// 嵌套: [[a, b], [x, y]]
List listOfLists = (List) parser.parseExpression("{
{'a','b'},{'x','y'}}").getValue(context);
System.out.println(listOfLists);
4、内嵌Map
使用{key:value}符号在表达式中表示Map。{:}意味着空Map。
// 定义Parser,可以定义全局的parser
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// {name=Nikola, dob=10-July-1856}
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);
System.out.println(inventorInfo);
// 嵌套:{name={first=Nikola, last=Tesla}, dob={day=10, month=July, year=1856}}
Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);
System.out.println(mapOfMaps);
// List与Map可以嵌套使用,互相结合。
// 嵌套:[{name={first=Nikola, last=Tesla}}, {dob={day=10, month=July, year=1856}}]
List listOfMaps = (List) parser.parseExpression("{
{name:{first:'Nikola',last:'Tesla'}},{dob:{day:10,month:'July',year:1856}}}").getValue(context);
System.out.println(listOfMaps);
5、构建数组
多维数组不提供初始化方式。
// 定义Parser,可以定义全局的parser
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
// 数组并初始化
int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context);
// 多维数组
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
6、调用类的方法
ExpressionParser parser = new SpelExpressionParser();
// 调用substring方法
String bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);
// 调用societyContext中对象的isMember方法,并传值。
StandardEvaluationContext societyContext = new StandardEvaluationContext(society);
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
societyContext, Boolean.class);
7、SpEL操作符
(1)标准运算符
使用标准运算符表示法支持关系运算符(等于、不等于、小于、小于或等于、大于和大于或等于)。
null不被视为任何东西(即不为零)。因此,任何其他值总是大于null (X > null总是为真),并且没有任何其他值小于零(X < null总是为假)。
ExpressionParser parser = newSpelExpressionParser();
// 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);
(2)instanceof 和 正则表达式的匹配操作符
使用基本类型时要小心,因为它们会立即被装箱为包装器类型,所以1 instanceof T(int)会计算为false,而1 instanceof T(Integer)会计算为true。
// evaluates to false
boolean falseValue = parser.parseExpression(
"'xyz' instanceof T(Integer)").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);
(3)操作符的英文等价标识
每个符号操作符也可以被指定为纯字母的等价物。这避免了所使用的符号对于嵌入表达式的文档类型具有特殊含义的问题(例如在XML文档中)。所有文本操作符都不区分大小写。对应的文本是: lt (<) gt (>) le (<=) ge (>=) eq (==) ne (!=) div (/) mod (%) not (!)
(4)逻辑运算符
SpEL支持以下逻辑运算符:and、or、not
// 结果: false
boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class);
// 调用方法并根据方法返回值判断
String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
// -- OR --
boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class);
// 调用方法并根据方法返回值判断
String expression = "isMember('Nikola Tesla') or isMember('Albert Einstein')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
// -- NOT --
// 取反
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);
(5)数学运算符
可以对数字和字符串使用加法运算符。 只能对数字使用减法、乘法和除法运算符。 也可以使用模数(%)和指数幂(^)运算符。 强制执行标准运算符优先级。
// 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
(6)赋值运算符
若要给对象设置属性,请使用赋值运算符(=)。这通常在对setValue的调用中完成,但也可以在对getValue的调用中完成。
// 定义Parser,可以定义全局的parser
ExpressionParser parser = new SpelExpressionParser();
Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
parser.parseExpression("Name").setValue(context, inventor, "Aleksandar Seovic");
System.out.println(inventor.getName()); // Aleksandar Seovic
// 或者这样赋值
String aleks = parser.parseExpression(
"Name = 'Aleksandar Seovic2'").getValue(context, inventor, String.class);
System.out.println(inventor.getName()); // Aleksandar Seovic2
8、获取类的类型
可以使用特殊的T运算符来指定java.lang.Class的实例(类型)。静态方法也是通过使用这个操作符来调用的。
StandardEvaluationContext使用TypeLocator来查找类型,StandardTypeLocator(可以替换)是基于对java.lang包的理解而构建的。所以java.lang中类型的T()引用不需要使用全限定名,但是其他包中的类,必须使用全限定名。
ExpressionParser parser = new SpelExpressionParser();
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);
9、调用类构造器
使用new运算符调用构造函数。除了基本类型(int、float等)和String之外,所有类型都应该使用完全限定的类名。
Inventor einstein = p.parseExpression(
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
.getValue(Inventor.class);
//创建一个新的Inventor,并且添加到members的list中
p.parseExpression(
"Members.add(new org.spring.samples.spel.inventor.Inventor(
'Albert Einstein', 'German'))").getValue(societyContext);
10、SpEL变量
(1)基本使用
可以使用#variableName语法在表达式中引用变量。通过在EvaluationContext实现上使用setVariable方法来设置变量
ExpressionParser parser = new SpelExpressionParser();
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
context.setVariable("newName", "Mike Tesla"); // 设置变量
// 获取变量newName,并将其赋值给name属性
parser.parseExpression("Name = #newName").getValue(context, tesla);
System.out.println(tesla.getName()); // "Mike Tesla"
(2)#this 和 #root变量
this变量引用当前的评估对象(根据该评估对象解析非限定引用)。
root变量总是被定义并引用根上下文对象。虽然#this可能会随着表达式的组成部分的计算而变化,但是#root总是指根。
// 创建一个Integer数组
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();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
context.setVariable("primes", primes);
// numbers > 10 的 list
// evaluates to [11, 13, 17]
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(
"#primes.?[#this>10]").getValue(context);
System.out.println(primesGreaterThanTen);
11、调用类静态方法
// 方法定义的方式
Method method = ...;
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("myFunction", method);
// 准备一个要调用的目标方法
public class StringUtils {
public static String reverseString(String input) {
StringBuilder backwards = new StringBuilder(input.length());
for (int i = 0; i < input.length(); i++) {
backwards.append(input.charAt(input.length() - 1 - i));
}
return backwards.toString();
}
}
// 调用目标静态方法
public static void main(String[] args) throws NoSuchMethodException {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 获取要调用的方法
context.setVariable("reverseString",
StringUtils.class.getDeclaredMethod("reverseString", String.class));
// 调用
String helloWorldReversed = parser.parseExpression(
"#reverseString('hello')").getValue(context, String.class);
}
12、Bean引用
如果已经用bean解析器配置了评估上下文,则可以使用@符号从表达式中查找bean。
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());
// 将调用MyBeanResolver 的 resolve(context,"something")
Object bean = parser.parseExpression("@something").getValue(context);
// 注意!MyBeanResolver 可以使用系统自带的BeanFactoryResolver,写成:
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
// BeanFactoryResolver的resolve方法,就是通过Bean的名称来获取Bean:
@Override
public Object resolve(EvaluationContext context, String beanName) throws AccessException {
try {
return this.beanFactory.getBean(beanName);
}
catch (BeansException ex) {
throw new AccessException("Could not resolve bean reference against BeanFactory", ex);
}
}
要访问工厂bean本身,应该在bean名称前加上&符号:
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());
// 将调用MyBeanResolver 的 resolve(context,"something")
Object bean = parser.parseExpression("&foo").getValue(context);
13、三元运算符(If-Then-Else)
// 使用示例
String falseString = parser.parseExpression(
"false ? 'trueExp' : 'falseExp'").getValue(String.class);
// name属性设置值
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"
14、Elvis操作符
Elvis运算符是三元运算符语法的缩写,用于Groovy语言中。使用三元运算符语法时,通常需要将一个变量重复两次,如下例所示:
String name = "Elvis Presley";
String displayName = (name != null ? name : "Unknown");
可以使用Elvis运算符(因与Elvis的发型相似而得名)优化。以下示例显示了如何使用Elvis运算符:
ExpressionParser parser = new SpelExpressionParser();
String name = parser.parseExpression("name?:'Unknown'").getValue(String.class);
System.out.println(name); // 'Unknown'
更复杂的实例:
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
String name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, tesla, String.class);
System.out.println(name); // Nikola Tesla
tesla.setName(null);
name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, tesla, String.class);
System.out.println(name); // Elvis Presley
15、安全导航操作员
安全导航操作符用于避免NullPointerException,来自Groovy语言。通常,当引用一个对象时,可能需要在访问该对象的方法或属性之前验证它不为null。为了避免这种情况,安全导航运算符返回null,而不是引发异常。以下示例显示了如何使用安全导航运算符:
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));
String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
System.out.println(city); // Smiljan
tesla.setPlaceOfBirth(null);
city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
System.out.println(city); // null - does not throw NullPointerException!!!
16、集合选择
// 语法.?[selectionExpression]
List<Inventor> list = (List<Inventor>) parser.parseExpression(
"Members.?[Nationality == 'Serbian']").getValue(societyContext);
// 返回value小于27的值
Map newMap = parser.parseExpression("map.?[value<27]").getValue();
除了返回所有选定的元素之外,还可以只检索第一个或最后一个值。要获得匹配选择的第一个条目,语法是: .^[选择表达式].要获得最后一个匹配的选择,语法是: .$[选择表达式]。
17、集合投影
// 语法:.![projectionExpression]
// returns ['Smiljan', 'Idvor' ]
List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]");
18、表达式模板
// 通常使用#{}作为模板,与字符串拼接起来
String randomPhrase = parser.parseExpression(
"random number is #{T(java.lang.Math).random()}",
new TemplateParserContext()).getValue(String.class);
// evaluates to "random number is 0.7038186818312008"
// TemplateParserContext 的定义
public class TemplateParserContext implements ParserContext {
public String getExpressionPrefix() {
return "#{";
}
public String getExpressionSuffix() {
return "}";
}
public boolean isTemplate() {
return true;
}
}
三、练习实例
公用实体类
Society
public class Society {
private String name;
public static String Advisors = "advisors";
public static String President = "president";
private List<Inventor> members = new ArrayList<Inventor>();
private Map officers = new HashMap();
public void setOfficers(Map map) {
this.officers = map;
}
public List getMembers() {
return members;
}
public Map getOfficers() {
return officers;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isMember(String name) {
for (Inventor inventor : members) {
if (inventor.getName().equals(name)) {
return true;
}
}
return false;
}
}
Inventor
public class Inventor {
private String name;
private String nationality;
private String[] inventions;
private Date birthdate;
private PlaceOfBirth placeOfBirth;
public Inventor(String name, String nationality) {
GregorianCalendar c= new GregorianCalendar();
this.name = name;
this.nationality = nationality;
this.birthdate = c.getTime();
}
public Inventor(String name, Date birthdate, String nationality) {
this.name = name;
this.nationality = nationality;
this.birthdate = birthdate;
}
public Inventor() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public Date getBirthdate() {
return birthdate;
}
public void setBirthdate(Date birthdate) {
this.birthdate = birthdate;
}
public PlaceOfBirth getPlaceOfBirth() {
return placeOfBirth;
}
public void setPlaceOfBirth(PlaceOfBirth placeOfBirth) {
this.placeOfBirth = placeOfBirth;
}
public void setInventions(String[] inventions) {
this.inventions = inventions;
}
public String[] getInventions() {
return inventions;
}
}
PlaceOfBirth
public class PlaceOfBirth {
private String city;
private String country;
public PlaceOfBirth(String city) {
this.city=city;
}
public PlaceOfBirth(String city, String country) {
this(city);
this.country = country;
}
public String getCity() {
return city;
}
public void setCity(String s) {
this.city = s;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
SPEL01
Test01
public class Test01 {
@Test
public void test01() {
// 字面量表达式
// 创建1个SpEl解析器SpelExpressionParser(它负责解析字符串)
SpelExpressionParser parser = new SpelExpressionParser();
// 使用SpEl解析器解析1个字符串, 返回1个Expression表达式对象(它负责计算解析的字符串)
Expression expression = parser.parseExpression("'halo'");
// 使用Expression表达式对象的getValue方法获得结果
Object value = expression.getValue();
System.out.println(value);
}
@Test
public void test02() {
// 调用对象的方法
// 创建1个SpEl解析器SpelExpressionParser(它负责解析字符串)
SpelExpressionParser parser = new SpelExpressionParser();
// 使用SpEl解析器解析1个字符串, 返回1个Expression表达式对象(它负责计算解析的字符串)
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
// 使用Expression表达式对象的getValue方法获得结果
String value = (String) exp.getValue();
System.out.println(value);
}
@Test
public void test03() {
// 通过点操作符来访问对象的属性
// 创建1个SpEl解析器SpelExpressionParser(它负责解析字符串)
SpelExpressionParser parser = new SpelExpressionParser();
// 使用SpEl解析器解析1个字符串, 返回1个Expression表达式对象(它负责计算解析的字符串)
Expression exp = parser.parseExpression("'Hello World'.bytes");
// 使用Expression表达式对象的getValue方法获得结果
byte[] value = (byte[]) exp.getValue();
System.out.println(value.length);
}
@Test
public void test04() {
// 通过点操作符来访问对象的多层属性
// 创建1个SpEl解析器SpelExpressionParser(它负责解析字符串)
SpelExpressionParser parser = new SpelExpressionParser();
// 使用SpEl解析器解析1个字符串, 返回1个Expression表达式对象(它负责计算解析的字符串)
Expression exp = parser.parseExpression("'Hello World'.bytes.length");
// 使用Expression表达式对象的getValue方法获得结果
int value = (int )exp.getValue();
System.out.println(value);
}
@Test
public void test05() {
// 调用构造方法和成员方法
// 创建1个SpEl解析器SpelExpressionParser(它负责解析字符串)
SpelExpressionParser parser = new SpelExpressionParser();
// 使用SpEl解析器解析1个字符串, 返回1个Expression表达式对象(它负责计算解析的字符串)
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
// 使用Expression表达式对象的getValue方法获得结果
String value = (String )exp.getValue();
System.out.println(value);
// 这样就不用强转了
String expValue = exp.getValue(String.class);
System.out.println(expValue);
}
@Test
public void test06() {
// SpEL更常见的用法是提供一个字符串表达式,该字符串表达式针对特定的对象实例(也叫根对象)进行求值
// 示例: 查询根对象属性, 并与字符串比较
// 创建1个SpEl解析器SpelExpressionParser(它负责解析字符串)
SpelExpressionParser parser = new SpelExpressionParser();
// 使用SpEl解析器解析1个字符串, 返回1个Expression表达式对象(它负责计算解析的字符串)
// 这里会理解为root对象的name属性
Expression exp = parser.parseExpression("name");
// 创建1个对象, 后面把它作为rootObject
Inventor rootObject = new Inventor("Nikola Tesla", new GregorianCalendar(1856, 7, 9).getTime(), "Serbian");
// 使用Expression表达式对象的getValue方法获得结果
// 这里传入了1个rootObject对象
String value = (String)exp.getValue(rootObject);
System.out.println(value);
}
@Test
public void test07() {
// spring el为EvaluationContext接口提供了2个实现:
// SimpleEvaluationContext(功能受限)
// StandardEvaluationContext(更加通用)
// 创建1个SpEl解析器SpelExpressionParser(它负责解析字符串)
SpelExpressionParser parser = new SpelExpressionParser();
// 创建1个对象, 后面把它作为rootObject
Simple simple = new Simple();
simple.booleanList.add(true);
// 创建1个 SimpleEvaluationContext,并指定为只读属性绑定
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 使用SpEl解析器解析1个字符串, 返回1个Expression表达式对象(它负责计算解析的字符串)
//(这里完成对对simple对象的booleanList属性的第1个属性进行赋值)
//(注意: 1. 使用Expression#setValue实现赋值
// 2. 指定根对象, 其实就是表达式中没有限定的都从根对象上找
// 3. 会完成自动类型转换, 其实就是false由字符串变成了布尔值)
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");
Boolean b = simple.booleanList.get(0);
System.out.println(b);
}
@Test
public void test08() {
// 可以使用SpelParserConfiguration来配置SpEl解析器
// 1. 开启自动null初始化
// 2. 开启自动集合扩容
SpelParserConfiguration config = new SpelParserConfiguration(true,true);
// 创建1个SpEl解析器SpelExpressionParser(它负责解析字符串)
SpelExpressionParser parser = new SpelExpressionParser(config);
// 使用SpEl解析器解析1个字符串, 返回1个Expression表达式对象(它负责计算解析的字符串)
Expression expression = parser.parseExpression("list[3]");
// 显然, 这里的demo未初始化它的list属性
Demo demo = new Demo();
System.out.println(demo.list); // 输出: null
// 使用Expression表达式对象的getValue方法获得结果
Object o = expression.getValue(demo);
System.out.println(o);
System.out.println(demo.list.size()); // 输出: 4
}
@Test
public void test09() {
// SpEl提供了3种编译模式: SpelCompilerMode 枚举类中
// 在选定1种模式之后, 使用SpelParserConfiguration配置到SpelExpressionParser解析器中
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, this.getClass().getClassLoader());
// 创建1个SpEl解析器SpelExpressionParser(它负责解析字符串)
SpelExpressionParser parser = new SpelExpressionParser(config);
// 使用SpEl解析器解析1个字符串, 返回1个Expression表达式对象(它负责计算解析的字符串)
Expression exp = parser.parseExpression("payload");
// 使用Expression表达式对象的getValue方法获得结果
MyMessage message = new MyMessage();
Object payload = exp.getValue(message);
System.out.println(payload);
}
}
Demo类
class Demo {
public List<String> list;
}
MyMessage类
public class MyMessage {
public byte[] payload;
}
Simple类
class Simple {
public List<Boolean> booleanList = new ArrayList<Boolean>();
}
SPEL02
xml配置文件中使用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 在spring的配置文件中, 可以使用 #{ <expression string> } 的形式, 来使用el表达式 -->
<!-- 可以调用类的静态方法给bean的属性赋值 -->
<bean id="numberGuess" class="com.zzhua.spel02.NumberGuess">
<property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>
<!-- other properties -->
</bean>
<!-- 可以通过bean的名字来引用容器中的bean, 包括像: environment, systemProperties, systemEnvironment -->
<bean id="taxCalculator" class="com.zzhua.spel02.TaxCalculator">
<property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>
<!-- 也可以应用其它bean -->
<property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>
<!-- other properties -->
</bean>
</beans>
anno注解中使用
@Configuration
@ComponentScan
public class FieldValueTestBean {
// 可以在属性、方法、构造器参数 中使用@Value注解, 并使用SpEl表达式
@Value("#{ systemProperties['user.region'] }")
private String defaultLocale;
private MovieFinder movieFinder;
private final CustomerPreferenceDao customerPreferenceDao;
@Value("#{ systemProperties['user.region'] }")
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
public String getDefaultLocale() {
return this.defaultLocale;
}
@Autowired
public void configure(MovieFinder movieFinder,
@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
this.movieFinder = movieFinder;
this.defaultLocale = defaultLocale;
}
public FieldValueTestBean(CustomerPreferenceDao customerPreferenceDao,
@Value("#{systemProperties['user.country']}") String defaultLocale) {
this.customerPreferenceDao = customerPreferenceDao;
this.defaultLocale = defaultLocale;
}
}
SPEL03
Test01
public class Test01 {
@Test
public void test01() {
// 字面量表达式
//(支持字符串、数字、布尔、null, 其中字符串使用前后共2个单引号声明, 如果要在字符串中包含单引号,那就要连续用2个单引号来表示)
ExpressionParser parser = new SpelExpressionParser();
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();
String helloWorld2 = (String) parser.parseExpression("'''Hello World'").getValue();
System.out.println(helloWorld); // Hello World
System.out.println(helloWorld2);// 'Hello World
double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();
System.out.println(avogadrosNumber); // 6.0221415E23
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();
System.out.println(maxValue); // 2147483647
boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
System.out.println(trueValue); // true
Object nullValue = parser.parseExpression("null").getValue();
System.out.println(nullValue); // null
}
@Test
public void test02() {
// 访问属性
//(注意: 属性名的首字母大小写随意, 因为首字母不敏感)
ExpressionParser parser = new SpelExpressionParser();
Inventor rootObject = new Inventor("Nikola Tesla", new GregorianCalendar(1856, 7, 9).getTime(), "Serbian");
rootObject.setPlaceOfBirth(new PlaceOfBirth("北京", "中国"));
SimpleEvaluationContext context = SimpleEvaluationContext
.forReadWriteDataBinding()
// 指定root对象
.withRootObject(rootObject)
.build();
// 字符串表达式中, 凡是不知道的属性, 就从context的rootObject中找
int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context);
System.out.println(year); // 1856
String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);
System.out.println(city); // 北京
// 字符串表达式中, 凡是不知道的属性, 就从rootObject中找, 那干脆直接用rootObject就好了
int year2 = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(rootObject);
System.out.println(year2); // 1856
String city2 = (String) parser.parseExpression("placeOfBirth.City").getValue(rootObject);
System.out.println(city2); // 北京
}
@Test
public void test03() {
// 通过中括号来访问数组、集合、map
ExpressionParser parser = new SpelExpressionParser();
// 给rootObject的inventions属性赋值
Inventor rootObject = new Inventor("Nikola Tesla", new GregorianCalendar(1856, 7, 9).getTime(), "Serbian");
String[] inventions = {"灯泡1", "灯泡2", "灯泡3"};
rootObject.setInventions(inventions);
SimpleEvaluationContext context = SimpleEvaluationContext
.forReadWriteDataBinding()
// 指定root对象
.withRootObject(rootObject)
.build();
// 访问 Inventor 的 inventions属性
// 字符串表达式中, 凡是不知道的属性, 就从context的rootObject中找
String invention2 = parser.parseExpression("inventions[2]").getValue(context, String.class);
// 这里指定的rootObject参数, 比context中的rootObject优先级会更高
String invention1 = parser.parseExpression("inventions[2]").getValue(context, rootObject, String.class);
System.out.println(invention1); // 灯泡3
System.out.println(invention2); // 灯泡3
// 访问 society 的 members 属性, Member的 inventions 属性
Society society = new Society();
society.getMembers().add(rootObject);
// 字符串表达式中, 凡是不知道的属性, 就从context的rootObject中找
String name = parser.parseExpression("Members[0].Name").getValue(context, society, String.class);
// 字符串表达式中, 凡是不知道的属性, 就从context的rootObject中找
String invention = parser.parseExpression("Members[0].Inventions[1]").getValue(context, society, String.class);
System.out.println(name); // Nikola Tesla
System.out.println(invention); // 灯泡2
// 访问 map 中的数据
Inventor inventor = new Inventor("Idvor", new GregorianCalendar(1856, 7, 9).getTime(), "Serbian");
inventor.setPlaceOfBirth(new PlaceOfBirth("cCity", "cCountry"));
society.getOfficers().put("president", inventor);
SimpleEvaluationContext societyContext = SimpleEvaluationContext
.forReadWriteDataBinding()
.withRootObject(society)
.build();
Inventor pupin = parser.parseExpression("Officers['president']").getValue(societyContext, Inventor.class);
System.out.println(pupin); // com.zzhua.entity.Inventor@2a2d45ba
String city = parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(societyContext, String.class);
System.out.println(city); // cCity
Inventor tempInventor = new Inventor("kkk", new GregorianCalendar(1856, 7, 9).getTime(), "Serbian");
tempInventor.setPlaceOfBirth(new PlaceOfBirth("zz", "kk"));
society.getOfficers().put("advisors", Arrays.asList(tempInventor));
Object contry = parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").getValue(societyContext);
System.out.println(contry); // kk
// 使用SpEl设置为jj, 注意使用SimpleEvaluationContext时, 一定要选择可读可写的那个方法, 才能使用setValue, 否则会报错
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext, "jj");
System.out.println(parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").getValue(societyContext));
System.out.println(contry); // jj
}
}
SPEL04
InlineListsTest
public class InlineListsTest {
@Test
public void test01() {
// 可以在字符串表达式中通过 {} 表示 list集合({}表达式代表个空集合)
SpelExpressionParser parser = new SpelExpressionParser();
SimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Expression exp = parser.parseExpression("{1,2,3,4}");
List<Object> numbers1 = (List<Object>) exp.getValue();
System.out.println(Arrays.toString(numbers1.toArray())); // [1, 2, 3, 4]
List<Object> numbers2 = (List<Object>) exp.getValue(context);
System.out.println(Arrays.toString(numbers2.toArray())); // [1, 2, 3, 4]
List<Object> numbers3 = (List<Object>) exp.getValue((Object) null); // 指定rootObject
System.out.println(Arrays.toString(numbers3.toArray())); // [1, 2, 3, 4]
}
}
InlineMaps
public class InlineMaps {
@Test
public void test01() {
// 可以在字符串表达式中通过 {key:value} 表示 map 集合, 其中map的key可以不使用单引号({:}表达式代表个空的map集合)
SpelExpressionParser parser = new SpelExpressionParser();
SimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Expression exp = parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}");
Map map = (Map)exp.getValue(context);
System.out.println(map); // {name=Nikola, dob=10-July-1856}
Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);
System.out.println(mapOfMaps); // {name={first=Nikola, last=Tesla}, dob={day=10, month=July, year=1856}}
}
}
ArrayConstructionTest
public class ArrayConstructionTest {
@Test
public void test01() {
// 可以使用与java相似的语法, 在字符串表达式中声明数组(最多构建二维数组, 不能声明多维数组)
SpelExpressionParser parser = new SpelExpressionParser();
SimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// -- 1
Expression exp1 = parser.parseExpression("new int[4]");
int[] numbers1 = (int[])exp1.getValue(context);
System.out.println(Arrays.toString(numbers1)); // [0, 0, 0, 0]
// --- 2
Expression exp2 = parser.parseExpression("new int[]{1,2,3}");
int[] numbers2 = (int[])exp2.getValue(context);
System.out.println(Arrays.toString(numbers2)); // [1, 2, 3]
// --- 3
Expression exp3 = parser.parseExpression("new int[4][5]");
int[][] numbers3 = (int[][]) exp3.getValue(context);
System.out.println(Arrays.toString(numbers3)); // [[I@7ca48474, [I@337d0578, [I@59e84876, [I@61a485d2]
}
}
MethodsTest
public class MethodsTest {
@Test
public void test01() {
// 可以通过 字符串表达式 调用方法, 同时也支持方法参数
SpelExpressionParser parser = new SpelExpressionParser();
/*SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding()
.withMethodResolvers(DataBindingMethodResolver.forInstanceMethodInvocation())
.build();*/
StandardEvaluationContext context = new StandardEvaluationContext();
Expression exp = parser.parseExpression("'abc'.substring(1, 3)");
Object value1 = exp.getValue();
System.out.println(value1); // bc
// 如果使用SimpleEvaluationContext的话, 这里会报错, 因此使用StandardEvaluationContext
//(不过也可以给SimpleEvaluationContext配上1个DataBindingMethodResolver也可以解决这个报错问题)
Object value2 = exp.getValue(context);
System.out.println(value2); // bc
// ---
SimpleEvaluationContext societyContext = SimpleEvaluationContext
.forReadWriteDataBinding()
.withMethodResolvers(DataBindingMethodResolver.forInstanceMethodInvocation())
.withRootObject(new Society())
.build();
// 调用rootObject(即society对象)的isMember方法哦
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(societyContext, Boolean.class);
System.out.println(isMember); // false
}
}
OperatorsTest
public class OperatorsTest {
@Test
public void test01() {
// 支持 比较运算符(注意: 任何值都比null要大)
SpelExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("2 == 2");
// ---
Boolean value1 = exp.getValue(Boolean.class);
System.out.println(value1); // true
// ---
SimpleEvaluationContext context2 = SimpleEvaluationContext.forReadWriteDataBinding().build();
Boolean value2 = exp.getValue(context2, Boolean.class);
System.out.println(value2); // true
// ---
SimpleEvaluationContext context3 = SimpleEvaluationContext.forReadWriteDataBinding().build();
Boolean value3 = exp.getValue(context3, null, Boolean.class);
System.out.println(value3); // true
// --------
System.out.println(parser.parseExpression("2 < -5.0").getValue(Boolean.class)); // false
System.out.println( parser.parseExpression("'black' < 'block'").getValue(Boolean.class)); // true
// -------- 验证: 任何值都比null要大
System.out.println(parser.parseExpression("null").getValue()); // null
System.out.println(parser.parseExpression("null == null").getValue()); // true
System.out.println(parser.parseExpression("null > null").getValue()); // false
System.out.println(parser.parseExpression("null < -1").getValue()); // true
System.out.println(parser.parseExpression("null < 'a'").getValue()); // true
}
@Test
public void test02() {
// 支持 instanceof 和 正则表达式的matches匹配操作
SpelExpressionParser parser = new SpelExpressionParser();
// ---
// instanceof使用示例(注意原始类型会被包装, 如: 1 instanceof T(int) 是false, 而1 instanceof T(Integer)是true)
Expression exp1 = parser.parseExpression("'xyz' instanceof T(Integer)");
boolean value1 = exp1.getValue(Boolean.class);
System.out.println(value1); // false
System.out.println(parser.parseExpression("1 instanceof T(int)").getValue()); // false
System.out.println(parser.parseExpression("1 instanceof T(Integer)").getValue()); // true
System.out.println(parser.parseExpression("1 instanceof T(com.zzhua.entity.Society)").getValue()); // false
// ---
// 正则匹配示例
Expression exp2 = parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'");
boolean value2 = exp2.getValue(Boolean.class);
System.out.println(value2); // true
// 补充说明: 符号都可以使用对应的字母组合符号, 可以避免一些问题, 并且不区分大小写
// lt (<)
// gt (>)
// le (<=)
// ge (>=)
// eq (==)
// ne (!=)
// div (/)
// mod (%)
// not (!)
}
@Test
public void test03() {
// 支持逻辑操作符: and (&&)、or (||)、not (!)
SpelExpressionParser parser = new SpelExpressionParser();
// --- AND(可将下面的and换成or)
Expression exp1 = parser.parseExpression("true and false");
Object value1 = exp1.getValue();
System.out.println(value1); // false
SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
Object value2 = exp1.getValue(context);
System.out.println(value2); // false
// --
Expression exp3 = parser.parseExpression("isMember('Nikola Tesla') and isMember('Mihajlo Pupin')");
Society rootObject = new Society();
rootObject.getMembers().add(new Inventor("Nikola Tesla",""));
rootObject.getMembers().add(new Inventor("Mihajlo Pupin",""));
SimpleEvaluationContext societyContext = SimpleEvaluationContext.forReadWriteDataBinding()
.withRootObject(rootObject)
.withMethodResolvers(DataBindingMethodResolver.forInstanceMethodInvocation())
.build();
boolean value3 = exp3.getValue(societyContext, Boolean.class);
System.out.println(value3); // true
// !的用法示例
System.out.println(parser.parseExpression("!true").getValue()); // false
System.out.println(parser.parseExpression("!false").getValue()); // true
System.out.println(parser.parseExpression("! false").getValue()); // true
System.out.println(parser.parseExpression("!! false").getValue()); // true
}
@Test
public void test04() {
// 支持算术运算符
SpelExpressionParser parser = new SpelExpressionParser();
int two = parser.parseExpression("1 + 1").getValue(Integer.class);
System.out.println(two); // 2
String testString = parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class);
System.out.println(testString); // test string
double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class);
System.out.println(d); // -9000.0
int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6
System.out.println(six); // 6
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class);
System.out.println(twentyFour);
int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2
System.out.println(minusTwo);
double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0
System.out.println(one);
int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3
System.out.println(three);
int one2 = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1
System.out.println(one2);
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21
System.out.println(minusTwentyOne);
}
@Test
public void test05() {
// 支持赋值运算符
//(如果需要给1个属性赋值, 可以使用=这个操作符;
// 可以通过调用Expression#setValue方法来实现;
// 也可以在Expression#getValue中使用=操作符来实现;)
SpelExpressionParser parser = new SpelExpressionParser();
Inventor inventor = new Inventor();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
// 给inventor(即rootObject)的name属性赋值
parser.parseExpression("Name").setValue(context, inventor, "Aleksandar Seovic");
System.out.println(inventor.getName()); // Aleksandar Seovic
// 给inventor(即rootObject)的name属性赋值的第二种方式
String aleks = parser.parseExpression("Name = 'Aleksandar Seovic2'").getValue(context, inventor, String.class);
System.out.println(inventor.getName()); // Aleksandar Seovic2
}
}
TypesTest
public class TypesTest {
@Test
public void test01() {
// 可以使用 T 这个操作符来指定1个实例对象所属的类, 也可以通过这个操作符来调用这个类的静态方法
// (StandardEvaluationContext 使用TypeLocator 来查找类, 对于在java.lang包下的类,不需要使用全限定名, 其他类则须使用全限定名)
SpelExpressionParser parser = new SpelExpressionParser();
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
System.out.println(dateClass); // class java.util.Date
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
System.out.println(stringClass); // class java.lang.String
boolean trueValue = parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR").getValue(Boolean.class);
System.out.println(trueValue); // true
}
}
ConstructorsTest
public class ConstructorsTest {
@Test
public void test01() {
// 支持使用new操作符来调用构造器, 应该都要使用全限定名除了基本类型和String之外
SpelExpressionParser parser = new SpelExpressionParser();
Inventor einstein = parser.parseExpression("new com.zzhua.entity.Inventor('Albert Einstein', 'German')").getValue(Inventor.class);
System.out.println(einstein.getName()); // Albert Einstein
}
}
VariablesTest
public class VariablesTest {
@Test
public void test01() {
// 可以使用 #变量名 的方式来引用对应的变量
//(变量名可以通过调用EvaluationContext#setVariable方法来设置)
//(合理的变量名应当由字母、数字、下划线、$组成)
SpelExpressionParser parser = new SpelExpressionParser();
Inventor rootObject = new Inventor("Nikola Tesla", "Serbian");
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
// 这里设置变量名
context.setVariable("newName", "Mike Tesla");
// 这里在表达式中使用 #变量名 来引用 设置到context中的变量
parser.parseExpression("Name = #newName").getValue(context, rootObject);
System.out.println(rootObject.getName()); // Mike Tesla
}
@Test
public void test02() {
// #this 总是引用当前计算对象
// #root 总是引用rootObject
SpelExpressionParser parser = new SpelExpressionParser();
List<Integer> primes = new ArrayList<Integer>();
primes.addAll(Arrays.asList(2,3,5,7,11,13,17));
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 设置变量
context.setVariable("primes", primes);
// 找出所有大于10的
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context);
System.out.println(Arrays.toString(primesGreaterThanTen.toArray())); // [11, 13, 17]
}
}
FunctionTest
public class FunctionTest {
@Test
public void test01() throws NoSuchMethodException {
// 支持 用户自定义方法,
// 具体来说就是可以通过EvaluationContext#setVariable来注册1个方法, 然后在字符串表达式中调用
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// 注册1个方法(与注册变量使用的是同一个方法)
context.setVariable("reverseString",StringUtils.class.getDeclaredMethod("reverseString", String.class));
// 在表达式中通过 #注册的方法名 来调用对应的方法
String helloReversed = parser.parseExpression("#reverseString('hello')").getValue(context, String.class);
System.out.println(helloReversed); // olleh
}
}
BeanReferencesTest
public class BeanReferencesTest {
@Test
public void test01() {
// 如果EvaluationContext配置了BeanResolver, 那么可以使用 @符号来查找容器中的bean
//(如果是1个FactoryBean, 并且需要访问bean本身, 那么需要使用 &符号来引用这个bean)
SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.registerBean("society", Society.class);
applicationContext.refresh();
context.setBeanResolver(new BeanResolver() {
@Override
public Object resolve(EvaluationContext context, String beanName) throws AccessException {
return applicationContext.getBean(beanName);
}
});
System.out.println(applicationContext.getBean(Society.class).getName()); // null
// 通过 @bean的名字 来引用从BeanResolver中解析出来的对象
parser.parseExpression("@society.name = 'zzhua'").getValue(context);
System.out.println(applicationContext.getBean(Society.class).getName()); // zzhua
}
}
TernaryOperatorTest
public class TernaryOperatorTest {
@Test
public void test01() {
// 支持使用三元运算符
SpelExpressionParser parser = new SpelExpressionParser();
String falseString = parser.parseExpression("false ? 'trueExp' : 'falseExp'").getValue(String.class);
System.out.println(falseString); // falseExp
// ---
SimpleEvaluationContext societyContext = SimpleEvaluationContext
.forReadWriteDataBinding()
.withRootObject(new Society())
.withMethodResolvers(DataBindingMethodResolver.forInstanceMethodInvocation())
.build();
// 给societyContext中, 指定的rootObject的name属性, 赋值为IEEE
parser.parseExpression("Name").setValue(societyContext, "IEEE");
// 注册变量
societyContext.setVariable("queryName", "Nikola Tesla");
// 凡是没有限定的, 都从rootObject中找; #变量名 从注册的变量中找;
String 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);
System.out.println(queryResultString); // Nikola Tesla is not a member of the IEEE Society
}
}
ElvisOperatorTest
public class ElvisOperatorTest {
@Test
public void test01() {
// 可以使用Elvis 操作符 ?: 来简化 变量是否为null的三元表达式的语法
//(可以在@Value注解中使用elvis操作符, 比如: @Value("#{systemProperties['pop3.port'] ?: 25}"))
ExpressionParser parser = new SpelExpressionParser();
Inventor rootObject = new Inventor();
// rootObject的name属性是否为null, 为null的话就取Unknown, 不为null的话就取rootObject的name属性
String name = parser.parseExpression("name?:'Unknown'").getValue(rootObject, String.class);
System.out.println(name); // Unknown
}
}
SafeNavigationOperator
public class SafeNavigationOperator {
@Test
public void test01() {
// 支持使用安全导航符, 用于避免空指针异常。
// (当访问引用对象的属性或方法时, 又不能确定这个被引用的对象是否为null时, 可以使用安全导航符,
// 如果引用对象是null, 那么会返回null, 而不是抛出空指针异常)
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));
String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
System.out.println(city); // Smiljan
// 将rootObject的placeOfBirth置为null
tesla.setPlaceOfBirth(null);
// rootObject的placeOfBirth是否为空, 如果为空, 则返回null, 如果不为空, 则访问它的city属性
city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
System.out.println(city); // null - 没有抛出NullPointerException!!!
String value = parser.parseExpression("placeOfBirth?.city?.length").getValue(context, tesla, String.class);
System.out.println(value); // null
}
}
CollectionSelection
public class CollectionSelection {
@Test
public void test01() {
// 集合选择能够从1个集合中过滤某些元素添加到1个新的集合中;
// 可以使用 .?[选择表达式] 来实现集合选择;
// 对于list集合, 选择表达式中获取的是每个元素;
// 对于map集合, 选择表达式中获取的是每个entry(即key-value对);
// 如果只需要新集合中的第1个元素, 则使用 .^[selectionExpression];
// 如果只需要新集合中的末位元素, 则使用 .$[selectionExpression];
SpelExpressionParser parser = new SpelExpressionParser();
Society society = new Society();
society.getMembers().add(new Inventor("Nikola Tesla", "Serbian"));
society.getMembers().add(new Inventor("Nikola Tesla2", "Serbian2"));
SimpleEvaluationContext societyContext = SimpleEvaluationContext.forReadWriteDataBinding().withRootObject(society).build();
// rootObject的members属性是个集合, 然后对这个集合中的元素作筛选, 中括号里面的上下文其实就是#this, 筛选出国籍为Serbian
List<Inventor> list = (List<Inventor>) parser.parseExpression("Members.?[Nationality == 'Serbian']").getValue(societyContext);
System.out.println(list.size()); // 1
List<Inventor> list2 = (List<Inventor>) parser.parseExpression("Members.?[#this.Nationality == 'Serbian']").getValue(societyContext);
System.out.println(list2.size()); // 1
// ---
Society society2 = new Society();
society2.getOfficers().put("a", 26);
society2.getOfficers().put("b", 27);
society2.getOfficers().put("c", 28);
SimpleEvaluationContext context = SimpleEvaluationContext
.forReadWriteDataBinding()
.withRootObject(society2)
.build();
Map newMap1 = (Map) parser.parseExpression("officers.?[value<27]").getValue(context);
System.out.println(newMap1); // {a=26}
Map newMap2 = (Map) parser.parseExpression("officers.?[key=='b']").getValue(context);
System.out.println(newMap2); // {b=27}
society2.setOfficers(null);
// rootObject的officers属性是null, 这里会抛出空指针异常
/*Map newMap3 = (Map) parser.parseExpression("officers?.?[key=='b']").getValue(context);
System.out.println(newMap3); */
// 这样写就对了, 使用安全导航符, 当rootObject的officers属性是null, 直接返回null
Map newMap3 = (Map) parser.parseExpression("officers?.?[key=='b']").getValue(context);
System.out.println(newMap3); // null
}
}
CollectionProjectionTest
public class CollectionProjectionTest {
@Test
public void test() {
// 集合投影就是将集合中的每个元素 都作 同样的处理 , 然后组合到1个新的集合里
SpelExpressionParser parser = new SpelExpressionParser();
Society society = new Society();
Inventor inventor1 = new Inventor("", "");
inventor1.setPlaceOfBirth(new PlaceOfBirth("sh", "ch"));
Inventor inventor2 = new Inventor("", "");
inventor2.setPlaceOfBirth(new PlaceOfBirth("sz", "ch"));
society.getMembers().add(inventor1);
society.getMembers().add(inventor2);
// 针对rootObject中的members属性, 中的每1个元素, 都获取他们的placeOfBirth属性, 然后city属性
List list = (List) parser.parseExpression("Members.![placeOfBirth.city]").getValue(society);
System.out.println(Arrays.toString(list.toArray())); // [sh, sz]
}
}
ExpressionTemplatingTest
public class ExpressionTemplatingTest {
@Test
public void test01() {
// 支持表达式模板, 允许将字面量的字符串和 计算块 混在一起使用, 计算块定义的前后分隔符可以自定义, 最常用的是 #{ }
SpelExpressionParser parser = new SpelExpressionParser();
// 需要指定ParserContext为TemplateParserContext实现
Expression exp = parser.parseExpression("random number is #{T(java.lang.Math).random()}",
new TemplateParserContext("#{","}"));
Object value = exp.getValue();
System.out.println(value); // random number is 0.5179806528476545
}