Spring-spel表达式

1,Spel 概念

Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL。能在运行时构建复杂表达式、存取对象图属性、对象方法调用等等,并且能与Spring功能完美整合,如能用来配置Bean定义。

表达式语言给静态Java语言增加了动态功能。

SpEL是单独模块,只依赖于core模块,不依赖于其他模块,可以单独使用。

2,语言参考

1,字面值

SpEL支持以下类型的字面量表达。

  • string
  • 数值: integer (int 或 long), 十六进制 (int 或 long), real (float 或 double)
  • boolean 值: true 或 false
  • null
@Test
public void String(){
ExpressionParser parser = new SpelExpressionParser();
//Hello World
System.out.println( (String) parser.parseExpression("'Hello World'").getValue() );
//Tony's Pizza
System.out.println( (String) parser.parseExpression("'Tony''s Pizza'").getValue() );
//6.0221415E23
System.out.println( (Double) parser.parseExpression("6.0221415E+23").getValue() );
//2147483647
System.out.println( (Integer) parser.parseExpression("0x7FFFFFFF").getValue() );
//true
System.out.println( (Boolean) parser.parseExpression("true").getValue() );
//null
System.out.println( parser.parseExpression("null").getValue() );
}

2,对象属性和方法

@Test
public void property(){
ExpressionParser parser = new SpelExpressionParser();
Dog dog = new Dog();
dog.setName("yq");
dog.setFriend(new Friend("yl"));
//通过属性:yq1900
String dogName = (String)parser.parseExpression("name + 1900").getValue(dog);
System.out.println( dogName );
//通过方法:yq1900
String getDogName = (String)parser.parseExpression("getName() + 1900").getValue(dog);
System.out.println(getDogName);
//通过属性:yl
String friendName = (String) parser.parseExpression("friend.name").getValue(dog);
System.out.println( friendName );
//通过属性:yl
String getFriendName = (String) parser.parseExpression("getFriend().getName()").getValue(dog);
System.out.println( getFriendName );
}

3,Array 和 list

数组和 list 都是通过 [下标获取]

@Test
public void array(){
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Dog dog = new Dog();
dog.setPrices(new Integer[]{1,2,3});
dog.setLs(Arrays.asList("pz", "yq", "yl", "xx"));
//2
Integer invention = parser.parseExpression("prices[1]").getValue(
context, dog, Integer.class);
System.out.println(invention);
//yq
String invention1 = parser.parseExpression("ls[1]").getValue(context, dog, String.class);
System.out.println( invention1 );
}

4,Map

map 的内容是通过在括号内指定字面的 key 值来获得的

@Test
public void map(){
ExpressionParser parser = new SpelExpressionParser();
Dog dog = new Dog();
Map<String, String> build = MapUtil.builder("f", "pz").put("s", "yq").put("t", "yl").build();
dog.setLsMap( build );
//yq
String value = parser.parseExpression("lsMap['s']").getValue(dog, String.class);
System.out.println(value);
}

5,构造列表,map

@Test
public void list(){
ExpressionParser parser = new SpelExpressionParser();
//内联列表:[1, 2, 3, 4]
List<Integer> value = (List)parser.parseExpression("{1,2,3,4}").getValue();
System.out.println(value);
//内联Map:
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue();
System.out.println(inventorInfo);
Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue();
System.out.println(mapOfMaps);
//Array 构造:
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue();
// Array with initializer
int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue();
// Multi dimensional array,二维数组不能初始化
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue();
}

6,方法调用

@Test
public void method(){
ExpressionParser parser = new SpelExpressionParser();
//bc
String bc = parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class);
System.out.println(bc);
//Friend{name='yq'}
String isMember = parser.parseExpression("toString()").getValue( new Friend("yq"), String.class );
System.out.println(isMember);
//我和yq是好朋友!
String member = parser.parseExpression("say('yq')").getValue( new Friend("yq"), String.class );
System.out.println(member);
}

7,关系操作符

  • lt (<)
  • gt (>)
  • le (<=)
  • ge (>=)
  • eq (==)
  • ne (!=)
  • div (/)
  • mod (%)
  • not (!)
  • instanceof
  • 基于正则表达式的 matches 运算符
@Test
public void relational(){
ExpressionParser parser = new SpelExpressionParser();
//true
System.out.println( parser.parseExpression("2 == 2").getValue(Boolean.class) );
//false
System.out.println( parser.parseExpression("2 < -5.0").getValue(Boolean.class) );
//true
System.out.println( parser.parseExpression("'black' < 'block'").getValue(Boolean.class) );
//false
System.out.println( parser.parseExpression("'xyz' instanceof T(Integer)").getValue(Boolean.class) );
//true:对于基本类型,只能到包装类上
System.out.println( parser.parseExpression("1 instanceof T(Integer)").getValue(Boolean.class) );
//false
System.out.println( parser.parseExpression("1 instanceof T(int)").getValue(Boolean.class) );
//true
System.out.println( parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class) );
//false
System.out.println( parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class) );
//false
System.out.println( parser.parseExpression("new java.math.BigDecimal(3) < new java.math.BigDecimal(2)").getValue(Boolean.class) );
}

8,逻辑运算符

  • and (&&)
  • or (||)
  • not (!)
@Test
public void logical(){
ExpressionParser parser = new SpelExpressionParser();
//false
System.out.println( parser.parseExpression("true && false").getValue() );
//true
System.out.println( parser.parseExpression("true || false").getValue() );
//false
System.out.println( parser.parseExpression( "!true" ).getValue() );
}

9,数学操作符

+ = * / % ^

@Test
public void math(){
ExpressionParser parser = new SpelExpressionParser();
System.out.println( parser.parseExpression("1 + 1").getValue(Integer.class)); // 2
System.out.println( parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class)); // 'test string'
System.out.println( parser.parseExpression("1 - -3").getValue(Integer.class)); // 4
System.out.println( parser.parseExpression("1000.00 - 1e4").getValue(Double.class)); // -9000
System.out.println( parser.parseExpression("-2 * -3").getValue(Integer.class)); // 6
System.out.println( parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class)); // 24.0
System.out.println( parser.parseExpression("6 / -3").getValue(Integer.class)); // -2
System.out.println( parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class)); // 1.0
System.out.println( parser.parseExpression("7 % 4").getValue(Integer.class)); // 3
System.out.println( parser.parseExpression("8 / 5 % 2").getValue(Integer.class)); // 1
System.out.println( parser.parseExpression("1+2-3*8").getValue(Integer.class)); // -21
}

10,赋值操作符

= 这通常是在调用 setValue 时进行,但也可以在调用 getValue 时进行。下面的列表显示了使用赋值运算符的两种方式。

@Test
public void assignment(){
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
Dog dog = new Dog();
//yyq
parser.parseExpression("name").setValue(context, dog, "yyq");
System.out.println(dog.getName());
//aiyyq
parser.parseExpression("name = 'aiyyq'").getValue(context, dog, String.class);
System.out.println(dog.getName());
}

11,类型

T(全限定名),除了 lang 包下的不需要全限定名

@Test
public void type(){
ExpressionParser parser = new SpelExpressionParser();
//class java.util.Date
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
System.out.println(dateClass);
//class java.lang.String
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
System.out.println(stringClass);
//true
boolean trueValue = parser.parseExpression(
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
.getValue(Boolean.class);
System.out.println(trueValue);
}

12,构造方法

你可以通过使用 new 操作符来调用构造函数。除了位于 java.lang 包中的类型(Integer、Float、String 等),你应该对所有类型使用全路径的类名。

@Test
public void construct(){
ExpressionParser parser = new SpelExpressionParser();
//Dog{name='yq'}
Dog dog = parser.parseExpression("new com.demo.spel.Dog('yq')").getValue(Dog.class);
System.out.println(dog);
}

13,变量

通过使用 #variableName 语法来引用表达式中的变量。变量是通过使用 EvaluationContext 实现上的 setVariable 方法来设置的。

@Test
public void variable(){
ExpressionParser parser = new SpelExpressionParser();
Dog pz = new Dog("pz");
//创建一个变量
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
context.setVariable("pName", "yq");
//引用变量
parser.parseExpression("name = #pName").getValue(context, pz);
System.out.println(pz);
}

14,方法

@Test
public void methodVariable() throws NoSuchMethodException {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("getName", Dog.class.getMethod("convert", String.class));
context.setVariable("getName11", Dog.class.getMethod("convert11", String.class));
//静态方法:gxayq
String value = parser.parseExpression("#getName('gxa')").getValue(context, String.class);
System.out.println( value );
//非静态方法:gxaaayq
String value1 = parser.parseExpression("#getName('gxaaa')").getValue(context, new Dog(), String.class);
System.out.println( value1 );
}

15,三元运算符

@Test
public void ternary(){
ExpressionParser parser = new SpelExpressionParser();
System.out.println( parser.parseExpression(
"false ? 'trueExp' : 'falseExp'").getValue(String.class) );
}

16,埃尔维斯(Elvis)运算符

在三元运算符语法中,你通常要将一个变量重复两次 -> (name != null ? name : "Unknown")
改进 elvis -> (name?:'Unknown')

@Test
public void elvis(){
ExpressionParser parser = new SpelExpressionParser();
//相当于 name != null ? name : "Unknown"
String name = parser.parseExpression("name?:'Unknown'").getValue(new Dog(), String.class);
System.out.println(name);
//@Value("#{systemProperties['pop3.port'] ?: 25}")
//这将注入一个系统属性 pop3.port(如果它被定义了),如果没有则注入25。
}

17,安全导航操作

安全导航操作,语法 ?
安全导航操作符是用来避免 NullPointerException 的,访问对象之前验证为 null,安全导航操作符返回null,而不是抛出一个异常

@Test
public void navigation(){
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Dog dog = new Dog();
//null
System.out.println( parser.parseExpression("friend?.name").getValue(context, dog, String.class) );
// EL1007E: Property or field 'name' cannot be found on null
System.out.println( parser.parseExpression("friend.name").getValue(context, dog, String.class) );
}

18,Collection Selection(选择)

语法 : .?[selectionExpression]

Selection 是一个强大的表达式语言功能,它让你通过从一个源集合的条目中进行选择,将其转化为另一个集合。
对于数组和任何实现 java.lang.Iterable 或 java.util.Map 的东西,都支持选择。对于一个列表或数组,选择标准是针对每个单独的元素进行评估的。对于一个Map,选择标准是针对每个Map entry(Java类型 Map.Entry 的对象)进行评估的。每个map entry都有它的 key 和 value,可以作为属性在选择中使用。

@Test
public void collectionSelection(){
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
List<Integer> list = new ArrayList<>();
list.addAll(Arrays.asList(4,6,1,2,4,0,3,9,8));
context.setVariable("list", list);
//[4, 1, 2, 4, 0, 3]
List<Integer> list1 = (List)parser.parseExpression("#list.?[#this<5]").getValue(context);
System.out.println(list1);
//{yl=2, yq=2, pz=5}
Friend friend = new Friend();
friend.setMap(MapUtil.builder("pz", 5).put("yq", 2).put("yl", 2).put("xx", 1).build());
System.out.println( parser.parseExpression("map.?[value>1]").getValue(friend) );
//获取匹配的第一个:{yl=2}
System.out.println( parser.parseExpression("map.^[value>1]").getValue(friend) );
//获取匹配的最后一个:{pz=5}
System.out.println( parser.parseExpression("map.$[value>1]").getValue(friend) );
}

19,collection Projection(投影)

语法 .![]

投影让一个集合驱动一个子表达式的评估,其结果是一个新的集合,类似 stream 的 list.stream().map()

@Test
public void collectionProjection(){
ExpressionParser parser = new SpelExpressionParser();
Friend friend = new Friend();
friend.setMap(MapUtil.builder("pz", 5).put("yq", 2).put("yl", 2).put("xx", 1).build());
//[xx, yl, yq, pz]
List<String> value = (List) parser.parseExpression("map.![key]").getValue(friend);
System.out.println(value);
}

20,表达式模板化

@Test
public void template(){
ExpressionParser parser = new SpelExpressionParser();
String value = parser.parseExpression(
"random number is #{T(java.lang.Math).random()}",
new TemplateParserContext()
).getValue(String.class);
System.out.println( value );
}

3,Bean 定义中的表达式

为了指定一个默认值,你可以在字段、方法和方法或构造函数参数上放置 @Value 注解。

1,通过字段设置默认值

public class FieldValueTestBean {
@Value("#{ systemProperties['user.region'] }")
private String defaultLocale;
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
public String getDefaultLocale() {
return this.defaultLocale;
}
}

2,在一个属性setter方法上

public class PropertyValueTestBean {
private String defaultLocale;
@Value("#{ systemProperties['user.region'] }")
public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}
public String getDefaultLocale() {
return this.defaultLocale;
}
}

3,自动装配的方法和构造函数也可以使用 @Value 注解

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;
}
// ...
}
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;
}
// ...
}

本文作者:Hi.PrimaryC

本文链接:https://www.cnblogs.com/cnff/p/17566014.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   primaryC  阅读(223)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.