一、簡介
Spring3中引入了Spring表達式語言—SpringEL,SpEL是一種強大,簡潔的裝配Bean的方式,他可以通過運行期間執行的表達式將值裝配到我們的屬性或構造函數當中,更可以調用JDK中提供的靜態常量,獲取外部Properties文件中的的配置
二、用法
1、文本表達式
文本表達式支持: 字符串(需要用單引號聲明)、日期、數字、布爾類型及null
,對數字支持負數、指數及小數, 默認情況下實數使用Double.parseDouble()
進行表達式類型轉換
parser.parseExpression("'hello'").getValue(String.class); // hello , 注意單引號 parser.parseExpression("1.024E+3").getValue(Long.class); // 1024 , 指數形式 parser.parseExpression("0xFFFF").getValue(Integer.class); // 65535 , 十六進制 parser.parseExpression("true").getValue(Boolean.class); // true parser.parseExpression("null").getValue();
2、變量
// 定義變量 String name = "Tom"; EvaluationContext context = new StandardEvaluationContext(); // 表達式的上下文, context.setVariable("myName", name); // 為了讓表達式可以訪問該對象, 先把對象放到上下文中 ExpressionParser parser = new SpelExpressionParser(); // 訪問變量 parser.parseExpression("#myName").getValue(context, String.class); // Tom , 使用變量 // 直接使用構造方法創建對象 parser.parseExpression("new String('aaa')").getValue(String.class); // aaa
3、屬性和方法調用
- 屬性可直接使用屬性名,屬性名首字母大小寫均可(只有首字母可不區分大小寫);
- 數組、列表可直接通過下表形式(
list[index]
)訪問; - map可以直接把key當成索引來訪問(
map[key]
); - 方法可以直接訪問;
// 准備工作 Person person = new Person("Tom", 18); // 一個普通的POJO List<String> list = Lists.newArrayList("a", "b"); Map<String, String> map = Maps.newHashMap(); map.put("A", "1"); map.put("B", "2"); EvaluationContext context = new StandardEvaluationContext(); // 表達式的上下文, context.setVariable("person", person); // 為了讓表達式可以訪問該對象, 先把對象放到上下文中 context.setVariable("map", map); context.setVariable("list", list); ExpressionParser parser = new SpelExpressionParser(); // 屬性 parser.parseExpression("#person.name").getValue(context, String.class); // Tom , 屬性訪問 parser.parseExpression("#person.Name").getValue(context, String.class); // Tom , 屬性訪問, 但是首字母大寫了 // 列表 parser.parseExpression("#list[0]").getValue(context, String.class) // a , 下標 // map parser.parseExpression("#map[A]").getValue(context, String.class); // 1 , key // 方法 parser.parseExpression("#person.getAge()").getValue(context, Integer.class); // 18 , 方法訪問
4、類型
T
操作符可以獲取類型, 可以調用對象的靜態方法
// 獲取類型 parser.parseExpression("T(java.util.Date)").getValue(Class.class); // class java.util.Date // 訪問靜態成員(方法或屬性) parser.parseExpression("T(Math).abs(-1)").getValue(Integer.class); // 1 // 判斷類型 parser.parseExpression("'asdf' instanceof T(String)").getValue(Boolean.class); // true;
5、操作符
Spring EL 支持大多數的數學操作符、邏輯操作符、關系操作符.
- 關系操作符, 包括:
eq(==)
,ne(!=)
,lt()<
,le(<=)
,gt(>)
,ge(>=)
- 邏輯運算符, 包括:
and(&&)
,or(||)
,not(!)
- 數學操作符, 包括: 加(
+
), 減(-
), 乘(*
), 除(/
), 取模(%
), 冪指數(^
) - 其他操作符, 如: 三元操作符,
instanceof
, 賦值(=
), 正則匹配
另外三元操作符有個特殊的用法, 一般用於賦默認值, 比如: parseExpression("#name?:'defaultName'")
, 如果變量name
為空時設置默認值.
parser.parseExpression("1 > -1").getValue(Boolean.class); // true parser.parseExpression("1 gt -1").getValue(Boolean.class); // true parser.parseExpression("true or true").getValue(Boolean.class); // true parser.parseExpression("true || true").getValue(Boolean.class); // true parser.parseExpression("2 ^ 3").getValue(Integer.class); // 8 parser.parseExpression("true ? true : false").getValue(Boolean.class); // true parser.parseExpression("#name ?: 'default'").getValue(context, String.class); // default parser.parseExpression("1 instanceof T(Integer)").getValue(Boolean.class); // true parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class); // true parser.parseExpression("#person.name").getValue(context, String.class); // Tom , 原來的值 parser.parseExpression("#person.name = 'Jim'").getValue(context, String.class); // Jim , 賦值之后 parser.parseExpression("#person.name").getValue(context, String.class); // Jim, 賦值起了作用
6、避免空指針
當訪問一個對象的屬性或方法時, 若該對象為null
, 就會出現空指針異常. 安全導航會判斷對象是否為null
,如果是的話, 就返回null
而不是拋出空指針異常. 使用方式就是在對象后面加個?
. 如下:
// 使用這種表達式可以避免拋出空指針異常 parser.parseExpression("#name?.toUpperCase()").getValue(context, String.class); // null
7、#this
變量
有個特殊的變量#this
來表示當前的對象. 常用於集合的過濾
// this 使用示例 parser.parseExpression("{1, 3, 5, 7}.?[#this > 3]").getValue(); // [5, 7]
8、集合選擇
可以使用選擇表達式對集合進行過濾或一些操作,從而生成一個新的符合選擇條件的集合, 有如下一些形式:
?[expression]
: 選擇符合條件的元素^[expression]
: 選擇符合條件的第一個元素$[expression]
: 選擇符合條件的最后一個元素![expression]
: 可對集合中的元素挨個進行處理
對於集合可以配合#this
變量進行過濾, 對於map, 可分別對keySet
及valueSet
分別使用key
和value
關鍵字;
// 集合 parser.parseExpression("{1, 3, 5, 7}.?[#this > 3]").getValue(); // [5, 7] , 選擇元素 parser.parseExpression("{1, 3, 5, 7}.^[#this > 3]").getValue(); // 5 , 第一個 parser.parseExpression("{1, 3, 5, 7}.$[#this > 3]").getValue(); // 7 , 最后一個 parser.parseExpression("{1, 3, 5, 7}.![#this + 1]").getValue(); // [2, 4, 6, 8] ,每個元素都加1 // map Map<Integer, String> map = Maps.newHashMap(); map.put(1, "A"); map.put(2, "B"); map.put(3, "C"); map.put(4, "D"); EvaluationContext context = new StandardEvaluationContext(); context.setVariable("map", map); parser.parseExpression("#map.?[key > 3]").getValue(context); // {4=D} parser.parseExpression("#map.?[value == 'A']").getValue(context); // {1=A} parser.parseExpression("#map.?[key > 2 and key < 4]").getValue(context); // {3=C}
9、模板表達式
模板表達式允許文字和表達式混合使用, 一般選擇使用#{}
作為一個定界符:
parser.parseExpression("他的名字為#{#person.name}", new TemplateParserContext()).getValue(context); // 他的名字為Tom
10、綜合使用
//模板表達式,三元表達式結合使用 parser.parseExpression("#{#person.name!=null?'他的名字叫'+#person.name+'先生':'不知道名字'}", new TemplateParserContext()).getValue(context);