文章目錄
- 推薦
- 一、概述
- 1、什么是SpEL
- 2、SpEL能做什么
- 二、SpEL表達式使用
- 1、文字表達式
- 2、屬性, 數組, List, Map,和 索引
- (1)屬性操作
- (2)數組和List
- (3)Map
- 3、內嵌List
- 4、內嵌Map
- 5、構建數組
- 6、調用類的方法
- 7、SpEL操作符
- (1)標準運算符
- (2)instanceof 和 正則表達式的匹配操作符
- (3)操作符的英文等價標識
- (4)邏輯運算符
- (5)數學運算符
- (6)賦值運算符
- 8、獲取類的類型
- 9、調用類構造器
- 10、SpEL變量
- (1)基本使用
- (2)#this 和 #root變量
- 11、調用類靜態方法
- 12、Bean引用
- 13、三元運算符(If-Then-Else)
- 14、Elvis操作符
- 15、安全導航操作員
- 16、集合選擇
- 17、集合投影
- 18、表達式模板
- 三、練習實例
- 公用實體類
- Society
- Inventor
- PlaceOfBirth
- SPEL01
- Test01
- Demo類
- MyMessage類
- Simple類
- SPEL02
- xml配置文件中使用
- anno注解中使用
- SPEL03
- Test01
- SPEL04
- InlineListsTest
- InlineMaps
- ArrayConstructionTest
- MethodsTest
- OperatorsTest
- TypesTest
- ConstructorsTest
- VariablesTest
- FunctionTest
- BeanReferencesTest
- TernaryOperatorTest
- ElvisOperatorTest
- SafeNavigationOperator
- CollectionSelection
- CollectionProjectionTest
- ExpressionTemplatingTest
推薦
Spring SPEL表達式語言的深入學習與使用【一萬字】
Spring SpEL表達式的使用
Spring-SpEL表達式超級詳細使用全解
spring-expressions官方文檔
下面文檔基本就是官方文檔的翻譯,源自: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); // 2String testString = parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class); // 'test string'// Subtraction
int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000// Multiplication
int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0// Division
int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0// Modulus
int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3int 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 Teslatesla.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); // Smiljantesla.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 {@Testpublic 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);}@Testpublic 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);}@Testpublic 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);}@Testpublic 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);}@Testpublic 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);}@Testpublic void test06() {// SpEL更常見的用法是提供一個字符串表達式,該字符串表達式針對特定的對象實例(也叫根對象)進行求值// 示例: 查詢根對象屬性, 并與字符串比較// 創建1個SpEl解析器SpelExpressionParser(它負責解析字符串)SpelExpressionParser parser = new SpelExpressionParser();// 使用SpEl解析器解析1個字符串, 返回1個Expression表達式對象(它負責計算解析的字符串)// 這里會理解為root對象的name屬性Expression exp = parser.parseExpression("name");// 創建1個對象, 后面把它作為rootObjectInventor 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);}@Testpublic void test07() {// spring el為EvaluationContext接口提供了2個實現:// SimpleEvaluationContext(功能受限)// StandardEvaluationContext(更加通用)// 創建1個SpEl解析器SpelExpressionParser(它負責解析字符串)SpelExpressionParser parser = new SpelExpressionParser();// 創建1個對象, 后面把它作為rootObjectSimple 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);}@Testpublic 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}@Testpublic 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/beanshttp://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;}@Autowiredpublic 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 {@Testpublic 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 WorldSystem.out.println(helloWorld2);// 'Hello Worlddouble avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();System.out.println(avogadrosNumber); // 6.0221415E23int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();System.out.println(maxValue); // 2147483647boolean trueValue = (Boolean) parser.parseExpression("true").getValue();System.out.println(trueValue); // trueObject nullValue = parser.parseExpression("null").getValue();System.out.println(nullValue); // null}@Testpublic 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); // 1856String 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); // 1856String city2 = (String) parser.parseExpression("placeOfBirth.City").getValue(rootObject);System.out.println(city2); // 北京}@Testpublic void test03() {// 通過中括號來訪問數組、集合、mapExpressionParser 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); // 燈泡3System.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 TeslaSystem.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@2a2d45baString city = parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(societyContext, String.class);System.out.println(city); // cCityInventor 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 {@Testpublic 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); // 指定rootObjectSystem.out.println(Arrays.toString(numbers3.toArray())); // [1, 2, 3, 4]}}
InlineMaps
public class InlineMaps {@Testpublic 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 {@Testpublic void test01() {// 可以使用與java相似的語法, 在字符串表達式中聲明數組(最多構建二維數組, 不能聲明多維數組)SpelExpressionParser parser = new SpelExpressionParser();SimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();// -- 1Expression exp1 = parser.parseExpression("new int[4]");int[] numbers1 = (int[])exp1.getValue(context);System.out.println(Arrays.toString(numbers1)); // [0, 0, 0, 0]// --- 2Expression exp2 = parser.parseExpression("new int[]{1,2,3}");int[] numbers2 = (int[])exp2.getValue(context);System.out.println(Arrays.toString(numbers2)); // [1, 2, 3]// --- 3Expression 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 {@Testpublic 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 {@Testpublic 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)); // falseSystem.out.println( parser.parseExpression("'black' < 'block'").getValue(Boolean.class)); // true// -------- 驗證: 任何值都比null要大System.out.println(parser.parseExpression("null").getValue()); // nullSystem.out.println(parser.parseExpression("null == null").getValue()); // trueSystem.out.println(parser.parseExpression("null > null").getValue()); // falseSystem.out.println(parser.parseExpression("null < -1").getValue()); // trueSystem.out.println(parser.parseExpression("null < 'a'").getValue()); // true}@Testpublic 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); // falseSystem.out.println(parser.parseExpression("1 instanceof T(int)").getValue()); // falseSystem.out.println(parser.parseExpression("1 instanceof T(Integer)").getValue()); // trueSystem.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 (!)}@Testpublic 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); // falseSimpleEvaluationContext 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()); // falseSystem.out.println(parser.parseExpression("!false").getValue()); // trueSystem.out.println(parser.parseExpression("! false").getValue()); // trueSystem.out.println(parser.parseExpression("!! false").getValue()); // true}@Testpublic void test04() {// 支持算術運算符SpelExpressionParser parser = new SpelExpressionParser();int two = parser.parseExpression("1 + 1").getValue(Integer.class);System.out.println(two); // 2String testString = parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class);System.out.println(testString); // test stringdouble d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class);System.out.println(d); // -9000.0int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6System.out.println(six); // 6double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class);System.out.println(twentyFour);int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2System.out.println(minusTwo);double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0System.out.println(one);int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3System.out.println(three);int one2 = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1System.out.println(one2);int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21System.out.println(minusTwentyOne);}@Testpublic 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 {@Testpublic 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.DateClass stringClass = parser.parseExpression("T(String)").getValue(Class.class);System.out.println(stringClass); // class java.lang.Stringboolean 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 {@Testpublic 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 {@Testpublic 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}@Testpublic void test02() {// #this 總是引用當前計算對象// #root 總是引用rootObjectSpelExpressionParser 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 {@Testpublic 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 {@Testpublic 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() {@Overridepublic 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 {@Testpublic 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屬性, 賦值為IEEEparser.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 {@Testpublic 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 {@Testpublic 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置為nulltesla.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 {@Testpublic 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, 篩選出國籍為SerbianList<Inventor> list = (List<Inventor>) parser.parseExpression("Members.?[Nationality == 'Serbian']").getValue(societyContext);System.out.println(list.size()); // 1List<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, 直接返回nullMap newMap3 = (Map) parser.parseExpression("officers?.?[key=='b']").getValue(context);System.out.println(newMap3); // null}}
CollectionProjectionTest
public class CollectionProjectionTest {@Testpublic 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 {@Testpublic 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}