diff --git a/spring/spring boot/spel.md b/spring/spring boot/spel.md index cb1256d..c4731eb 100644 --- a/spring/spring boot/spel.md +++ b/spring/spring boot/spel.md @@ -13,6 +13,34 @@ - [为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 @@ -192,6 +220,385 @@ public class MovieRecommender { } ``` +## 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 primes = new ArrayList(); +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 primesGreaterThanTen = + (List) 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 list = (List) + 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" +``` + + + + +