文本表達式支持字符串、 日期 、 數字(正數 、 實數及十六進制數) 、 布爾類型及 null。其中的字符表達式可以使用單引號來表示,形如:'Deniro'
。若是表達式中包含單引號或者雙引號字符,那麼可使用轉義字符 /
。java
ExpressionParser parser
= new SpelExpressionParser();
//字符串解析
String str = (String) parser.parseExpression("'你好'").getValue();
System.out.println(str);
//整型解析
int intVal = (Integer) parser.parseExpression("0x2F").getValue();
System.out.println(intVal);
//雙精度浮點型解析
double doubleVal = (Double) parser.parseExpression("4329759E+22").getValue();
System.out.println(doubleVal);
//布爾型解析
boolean booleanVal = (boolean) parser.parseExpression("true").getValue();
System.out.println(booleanVal);
複製代碼
輸出結果:正則表達式
你好 47 4.329759E28 truespring
數字支持負數 、小數、科學記數法、八進制數和十六進制數 。 默認狀況下,實數使用 Double.parseDouble()
進行表達式類型轉換 。數組
在 SpEL 中,咱們可使用對象屬性路徑(形如類名.屬性名.屬性名
)來訪問對象屬性的值。安全
假設有一個帳號類,Account.java:bash
public class Account {
private String name;
private int footballCount;
private Friend friend;
public Account(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setFootballCount(int footballCount) {
this.footballCount = footballCount;
}
public void addFriend(Friend friend) {
this.friend = friend;
}
public int getFootballCount() {
return footballCount;
}
public Friend getFriend() {
return friend;
}
}
複製代碼
它包含姓名 name、足球數 footballCount 和一個朋友 friend 屬性。friend 屬性是一個 Friend 類:ui
public class Friend {
private String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
複製代碼
解析對象屬性表達式:this
//初始化對象
Account account=new Account("Deniro");
account.setFootballCount(10);
account.addFriend(new Friend("Jack"));
//解析器
ExpressionParser parser
= new SpelExpressionParser();
//解析上下文
EvaluationContext context=new StandardEvaluationContext(account);
//獲取不一樣類型的屬性
String name= (String) parser.parseExpression("Name").getValue(context);
System.out.println(name);
int count= (Integer) parser.parseExpression("footballCount+1").getValue(context);
System.out.println(count);
//獲取嵌套類中的屬性
String friend= (String) parser.parseExpression("friend.name").getValue(context);
System.out.println(friend);
複製代碼
輸出結果:lua
Deniro 11 Jackspa
數組表達式支持 Java 建立數組的語法,形如 new int[]{3,4,5}
,數組項之間以逗號做爲分隔符。**注意:**目前還不支持多維數組。Map 表達式以鍵值對的方式來定義,形如 {name:'deniro',footballCount:10}
。
//解析器
ExpressionParser parser
= new SpelExpressionParser();
//解析一維數組
int[] oneArray = (int[]) parser.parseExpression("new int[]{3,4,5}").getValue();
System.out.println("一維數組開始:");
for (int i : oneArray) {
System.out.println(i);
}
System.out.println("一維數組結束");
//這裏會拋出 SpelParseException
// int[][] twoArray = (int[][]) parser.parseExpression("new int[][]{3,4,5}{3,4,5}")
// .getValue();
//解析 list
List list = (List) parser.parseExpression("{3,4,5}").getValue();
System.out.println("list:" + list);
//解析 Map
Map map = (Map) parser.parseExpression("{account:'deniro',footballCount:10}")
.getValue();
System.out.println("map:" + map);
//解析對象中的 list
final Account account = new Account("Deniro");
Friend friend1 = new Friend("Jack");
Friend friend2 = new Friend("Rose");
List<Friend> friends = new ArrayList<>();
friends.add(friend1);
friends.add(friend2);
account.setFriends(friends);
EvaluationContext context = new StandardEvaluationContext(account);
String friendName = (String) parser.parseExpression("friends[0].name")
.getValue(context);
System.out.println("friendName:" + friendName);
複製代碼
從數組與 List 獲取值,能夠在括號內指定索引來獲取,形如上例中的 friends[0]
。Map 中可經過鍵名來獲取,形如 xxx['xxx']
。
輸出結果:
一維數組開始: 3 4 5 一維數組結束 list:[3, 4, 5] map:{account=deniro, footballCount=10} friendName:Jack
SpEL 支持調用有訪問權限的方法,這些方法包括對象方法、靜態方法,並且支持可變方法參數。除此以外,還能夠調用 String 類型中的全部可訪問方法,好比 String.contains('xxx')
。
//解析器
ExpressionParser parser
= new SpelExpressionParser();
//調用 String 方法
boolean isEmpty = parser.parseExpression("'Hi,everybody'.contains('Hi')").getValue
(Boolean
.class);
System.out.println("isEmpty:" + isEmpty);
/**
* 調用對象相關方法
*/
final Account account = new Account("Deniro");
EvaluationContext context = new StandardEvaluationContext(account);
//調用公開方法
parser.parseExpression("setFootballCount(11)").getValue(context, Boolean
.class);
System.out.println("getFootballCount:" + account.getFootballCount());
//調用私有方法,拋出 SpelEvaluationException: EL1004E: Method call: Method write() cannot be found on net.deniro.spring4.spel.Account type
// parser.parseExpression("write()").getValue(context,Boolean
// .class);
//調用靜態方法
parser.parseExpression("read()").getValue(context, Boolean
.class);
//調用待可變參數的方法
parser.parseExpression("addFriendNames('Jack','Rose')").getValue(context, Boolean
.class);
複製代碼
**注意:**調用對象的私有方法會拋出異常。
輸出結果:
isEmpty:true getFootballCount:11 讀書 friendName:Jack friendName:Rose
SpEL 支持 Java 標準操做符:等於、不等於、小於、小等於、大於、大等於、正則表達式和 instanceof 操做符。
//解析器
ExpressionParser parser
= new SpelExpressionParser();
//數值比較
boolean result=parser.parseExpression("2>1").getValue(Boolean.class);
System.out.println("2>1:"+result);
//字符串比較
result=parser.parseExpression("'z'>'a'").getValue(Boolean.class);
System.out.println("'z'>'a':"+result);
//instanceof 運算符
result=parser.parseExpression("'str' instanceof T(String)").getValue(Boolean.class);
System.out.println("'str' 是否爲字符串 :"+result);
result=parser.parseExpression("1 instanceof T(Integer)").getValue(Boolean.class);
System.out.println("1 是否爲整型 :"+result);
//正則表達式
result=parser.parseExpression("22 matches '\\d{2}'").getValue(Boolean.class);
System.out.println("22 是否爲兩位數字 :"+result);
複製代碼
輸出結果:
2>1:true 'z'>'a':true 'str' 是否爲字符串 :true 1 是否爲整型 :true 22 是否爲兩位數字 :true
T(Java 包裝器類型)
,如整型 T(Integer)
。**注意:**不能使用原生類型,若是這樣 T(int)
會返回錯誤的判斷結果。邏輯操做符支持如下操做:
邏輯操做符 | 說明 |
---|---|
and 或 && |
與操做 |
or 或 \|\| |
或操做 |
! |
非操做 |
注意: 在 SpEL 中,不只支持 Java 標準的邏輯操做符,還支持 and 與 or 關鍵字。
//解析器
ExpressionParser parser
= new SpelExpressionParser();
//與操做
boolean result=parser.parseExpression("true && true").getValue(Boolean.class);
System.out.println("與操做:"+result);
//或操做
result=parser.parseExpression("true || false").getValue(Boolean.class);
System.out.println("或操做:"+result);
parser.parseExpression("true or false").getValue(Boolean.class);
System.out.println("或操做(or 關鍵字):"+result);
//非操做
result=parser.parseExpression("!false").getValue(Boolean.class);
System.out.println("非操做:"+result);
//拋出 SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from java.lang.Integer to java.lang.Boolean
//parser.parseExpression("!0").getValue(Boolean.class);
複製代碼
輸出結果:
與操做:true 或操做:true 或操做(or 關鍵字):true 非操做:true
**注意:**邏輯操做符先後運算結果必須是布爾類型,不然會拋出 SpelEvaluationException。
SpEL 支持 Java 運算操做符,並遵照運算符優先級規則:
運算操做符 | 說明 | 支持的操做數類型 |
---|---|---|
+ | 加法 | 數字、字符串或日期 |
- | 減法 | 數字或日期 |
* | 乘法 | 數字 |
/ |
除法 | 數字 |
% | 取模 | 數字 |
^ | 指數冪 | 數字 |
//加法運算
Integer iResult = parser.parseExpression("2+3").getValue(Integer.class);
System.out.println("加法運算:" + iResult);
String sResult = parser.parseExpression("'Hi,'+'everybody'").getValue(String.class);
System.out.println("字符串拼接運算:" + sResult);
//減法運算
iResult = parser.parseExpression("2-3").getValue(Integer.class);
System.out.println("減法運算:" + iResult);
//乘法運算
iResult = parser.parseExpression("2*3").getValue(Integer.class);
System.out.println("乘法運算:" + iResult);
//除法運算
iResult = parser.parseExpression("4/2").getValue(Integer.class);
System.out.println("除法運算:" + iResult);
Double dResult = parser.parseExpression("4/2.5").getValue(Double.class);
System.out.println("除法運算:" + dResult);
//求餘運算
iResult = parser.parseExpression("5%2").getValue(Integer.class);
System.out.println("求餘運算:" + iResult);
複製代碼
輸出結果:
加法運算:5 字符串拼接運算:Hi,everybody 減法運算:-1 乘法運算:6 除法運算:2 除法運算:1.6 求餘運算:1
安全導航操做符來源於 Groovy 語言,使用它可以避免空指針異常。通常在訪問對象時,須要驗證該對象是否爲空,使用安全導航操做符就能避免繁瑣的空對象驗證方法。它的格式是在獲取對象屬性操做符「.
」 以前加一個 「?
」。
final Account account = new Account("Deniro");
account.addFriend(new Friend("Jack"));
//解析器
ExpressionParser parser
= new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext(account);
String friendName=parser.parseExpression("friend?.name").getValue(context,String
.class);
System.out.println("friendName:"+friendName);
//設置爲 null
account.setFriend(null);
friendName=parser.parseExpression("friend?.name").getValue(context,String
.class);
//打印出 null
System.out.println("friendName:" + friendName);
複製代碼
輸出結果:
friendName:Jack friendName:null
這裏會先判斷 friend 對象是否爲空;若是爲空,則返回 "null" 字符串;不然返回須要的屬性值。
SpEL 支持標準的 Java 三元操做符:<表達式 1>?<表達式 2>:<表達式 3>
ExpressionParser parser
= new SpelExpressionParser();
boolean result=parser.parseExpression("(1+2) == 3?true:false").getValue(Boolean
.class);
System.out.println("result:"+result);
}
複製代碼
輸出結果:
result:true
Elvis 操做符是在 Groovy 中使用的三元操做符簡化版。
在三元操做符中,咱們通常須要寫兩次變量名,好比下面代碼段中的 title:
String title="News";
String actualTitle=(title!=null)?title:"tip";
複製代碼
使用 Elvis 操做符後,能夠將上述代碼段簡寫爲:
title?:"tip"
複製代碼
SpEL 支持的 Elvis 操做符格式是:<var>?:<value>
,若是 var 變量爲 null,那就取 value 值,不然就取自身的值。因此 Elvis 操做符很適合用於設置默認值。
示例:
final Account account = new Account("Deniro");
//解析器
ExpressionParser parser
= new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext(account);
String friendName=parser.parseExpression("name?:'無名'").getValue(context,String
.class);
System.out.println("friendName:"+friendName);
//設置名字爲 null
account.setName(null);
friendName=parser.parseExpression("name?:'無名'").getValue(context,String
.class);
System.out.println("friendName:" + friendName);
複製代碼
輸出結果:
friendName:Deniro friendName:無名
能夠經過賦值表達式來設置屬性的值,效果等同於調用 setValue() 方法。
final Account account = new Account("Deniro");
//解析器
ExpressionParser parser
= new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext(account);
String name=parser.parseExpression("name='Jack'").getValue(context,String
.class);
System.out.println("name:"+name);
複製代碼
類型操做符 T 能夠從類路徑加載指定類名稱(全限定名)所對應的 Class 的實例,格式爲:T(全限定類名)
,效果等同於 ClassLoader#loadClass()
。
ExpressionParser parser
= new SpelExpressionParser();
//加載 java.lang.Integer
Class integerClass=parser.parseExpression("T(Integer)").getValue(Class
.class);
System.out.println(integerClass==java.lang.Integer.class);
//加載 net.deniro.spring4.spel.Account
Class accountClass=parser.parseExpression("T(net.deniro.spring4.spel.Account)")
.getValue(Class
.class);
System.out.println(accountClass==net.deniro.spring4.spel.Account.class);
//調用類靜態方法
double result = (double) parser.parseExpression("T(Math).abs(-2.5)").getValue();
System.out.println("result:" + result);
複製代碼
輸出結果:
true true result:2.5
咱們還能夠直接經過 T 操做符調用類的靜態方法,格式爲 T(全限定類名).靜態方法名
,好比上面例子中求某數的絕對值 T(Math).abs(-2.5)
。
SpEL 中會使用 StandardTypeLocator#findType() 方法來加載類。 findType 方法定義以下:
public Class<?> findType(String typeName) throws EvaluationException {
String nameToLookup = typeName;
try {
return ClassUtils.forName(nameToLookup, this.classLoader);
}
catch (ClassNotFoundException ey) {
// try any registered prefixes before giving up
}
for (String prefix : this.knownPackagePrefixes) {
try {
nameToLookup = prefix + '.' + typeName;
return ClassUtils.forName(nameToLookup, this.classLoader);
}
catch (ClassNotFoundException ex) {
// might be a different prefix
}
}
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
}
複製代碼
可使用 new 操做符來建立一個新對象 。 除了基本類型(如整型、布爾型等)和字符串以外,建立其它類須要指明全限定類名( 包括包路徑 ) 。
Account account=parser.parseExpression("new net.deniro.spring4.spel.Account" +
"('Deniro')").getValue(Account.class);
System.out.println("name:"+account.getName());
複製代碼
輸出結果:
name:Deniro
能夠經過 #變量名
來引用在 EvaluationContext 中定義的變量。經過 EvaluationContext#setVariable(name, val)
便可定義新的變量;name 表示變量名,val 表示變量值。
若是變量是集合,好比 list,那麼能夠經過 #scores.[#this]
來引用集合中的元素。
Account account = new Account("Deniro");
ExpressionParser parser
= new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext(account);
//定義一個新變量,名爲 newVal
context.setVariable("newVal", "Jack");
//獲取變量 newVal 的值,並賦值給 User 的 name 屬性
parser.parseExpression("name=#newVal").getValue(context);
System.out.println("getName:" + account.getName());
//this 操做符表示集合中的某個元素
List<Double> scores = new ArrayList<>();
scores.addAll(Arrays.asList(23.1, 82.3, 55.9));
context.setVariable("scores", scores);//在上下文中定義 scores 變量
List<Double> scoresGreat80 = (List<Double>) parser.parseExpression("#scores.?[#this>80]")
.getValue(context);
System.out.println("scoresGreat80:" + scoresGreat80);
複製代碼
輸出結果:
getName:Jack scoresGreate80:[82.3]
可使用選擇表達式來過濾集合,從而生成一個新的符合選擇條件的集合 。它的語法是 ?[selectionExpression]
。選擇符合條件的結果集的第一個元素的語法爲 ^ [selectionExpression]
,選擇最後一個元素的語法爲 $[selectionExpression]
。選擇表達式也可應用於 Map 。
//過濾 list 集合中的元素
final StandardEvaluationContext listContext = new
StandardEvaluationContext(list);
List<Integer> great4List = (List<Integer>) parser.parseExpression("?[#this>4]")
.getValue(listContext);
System.out.println("great4List:" + great4List);
//獲取匹配元素中的第一個值
Integer first = (Integer) parser.parseExpression("^[#this>2]")
.getValue(listContext);
System.out.println("first:" + first);
//獲取匹配元素中的最後一個值
Integer end = (Integer) parser.parseExpression("$[#this>2]")
.getValue(listContext);
System.out.println("end:" + end);
複製代碼
輸出結果:
list:[3, 4, 5] great4List:[5] first:3 end:5
對於 List 和 Set ,是針對集合中的每個元素進行比較的;而對於 Map,則能夠指定是元素的鍵(key)仍是元素的值進行比較的。
//過濾 Map
Map<String, Double> rank = new HashMap<>();
rank.put("Deniro", 96.5);
rank.put("Jack", 85.3);
rank.put("Lily", 91.1);
context.setVariable("Rank", rank);
//value 大於 90
Map<String,Double> rankGreat95= (Map<String, Double>) parser.parseExpression
("#Rank.?[value>90]").getValue(context);
System.out.println("rankGreat95:" + rankGreat95);
//key 按字母順序,排在 L 後面
Map<String,Double> afterL= (Map<String, Double>) parser.parseExpression
("#Rank.?[key>'L']").getValue(context);
System.out.println("afterL:"+afterL);
複製代碼
輸出結果:
rankGreat95:{Deniro=96.5, Lily=91.1} nameOrder:{Lily=91.1}
經過表達式 ![projectionExpression]
,咱們能夠判斷集合中每個元素是否符合表達式規則。
List list = (List) parser.parseExpression("{3,4,5}").getValue();
System.out.println("list:" + list);
List<Boolean> isgreat4=(List<Boolean>)parser.parseExpression("![#this>3]")
.getValue(list);
System.out.println("isgreat4:" + isgreat4);
複製代碼
輸出結果:
isgreat4:[false, true, true]
也能夠對 Map 對象進行相似判斷。