####使用場合####
假設有這樣一種情況,一個bean的某一個屬性需要在程序運行的時候動態的賦值,使用SpEL將有效的簡化開發。
在文章的結尾有工程源碼,歡迎下載!
SpEL簡介
SpEL是在Spring 3引入的新特性,全稱爲Spring Expression Language,它有許多強大的特性,包括:
- 可以使用bean的ID來引用bean
- 可以通過bean的ID來訪問bean的屬性和調用其方法
- 可以進行關係,邏輯,算術運算
- 正則表達式匹配
- 對集合的操作
通過bean的ID來訪問bean的屬性和調用其方法
需求:一個購物清單(ShopList)用一個java bean封裝,它的價格受到稅率(Tax)影響,稅率用單獨的一個類封裝
兩個java bean的代碼,省略getter和setter:
public class ShopList {
private String name;
private int count;
private double price;
}
public class Tax {
private double ctax;
}
接下來在spring配置文件中配置bean
<bean id="tax" class="com.yonyou.bean.Tax" p:ctax="10"></bean>
<bean id="list" class="com.yonyou.bean.ShopList" p:name="shanpoo" p:count="2" p:price="#{tax.ctax/100 * 36.5}"/>
可以看到p:price使用了#{},說明它是通過SpEL裝配值的,tax.ctax說明這裏使用了id爲tax的ctax屬性,以及後面的算術運算都是SpEL的應用。
我們不僅可以訪問tax的屬性,還可以調用它的方法,比如:p:price=”#{tax.getCtax()/100 * 36.5}”,使用“tax.getCtax()”
null-safe存取器
首先假設tax.getCtax()返回一個字符串,那麼它可以接着調用,形如:tax.getCtax().trim()
但是如果tax.getCtax()返回爲null,就會拋出空指針異常,爲了避免異常,可以加一個“?”避免,即tax.getCtax()?.trim()
訪問靜態方法,靜態變量
此時的SpEL需要使用以下形式訪問靜態方法,靜態變量:
“#{T(類全名).靜態方法}”
使用方法很簡單,舉兩個例子,在Tax加一個靜態方法getCountry()
p:name="#{T(com.yonyou.bean.Tax).country}"
p:name="#{T(com.yonyou.bean.Tax).getCountry()}"
主要說一個小坑:一開始我以爲訪問靜態變量“.country”是訪問類中的country靜態變量,其實訪問的還是getCountry()方法
運算符
SpEL支持絕大多數運算符,讀者注意一下以下幾點即可:
- 不要直接寫”>”,”<”,轉換爲gt,lt
- +可以拼接字符串,字符串使用單引號
- 非運算可以使用“!”或“not”
- 可以使用java中的三元表達式,三元表達式常用於判斷get出來的是否爲null,比如name = vo.getName() == null ?”“:vo.getName(),vo.getName()需要竟然要寫兩遍!(博主的工作中經常這樣寫/(ㄒoㄒ)/~~ ),SpEL中可以這樣寫#{name = vo.getName()?’nothing’},如果vo.getName()爲null就返回nothing,都不用寫vo.getName()==null
SpEL使用正則表達式
比如校驗郵箱:
“#{user.email matches \w{8,12}@\w{3,5}(\.[a-zA-Z]+){1,3}}”
篩選集合
SpEL可以將一個集合的子集裝配到一個bean的屬性中,這個集合可以是list,map,properties,系統變量等
1.util:list
首先簡單說下util:list的作用:定義一個集合,讓所有的bean共用,需要加入util約束,xmlns:util=”http://www.springframework.org/schema/util”
xsi:schemaLocation=”http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.2.xsd”
重新定義兩個java bean
public class Item {
private String good;
private double weight;
}
public class ShopList {
...
private Item onlyOne;
}
在xml創建一個共用的Item集合(id=”its”),並且通過下標去引用集合裏的元素,如“#{its[0]}”,xml中配置如下:
<util:list id="its">
<bean class="com.yonyou.bean.Item" p:good="poke" p:weight="3.34"></bean>
<bean class="com.yonyou.bean.Item" p:good="chicken" p:weight="5.66"></bean>
<bean class="com.yonyou.bean.Item" p:good="dark" p:weight="3.64"></bean>
<bean class="com.yonyou.bean.Item" p:good="egg" p:weight="2.54"></bean>
</util:list>
<bean id="list7" class="com.yonyou.bean.ShopList" p:name="#{tax.getName()?: 'bullshit'}" p:count="2"
p:price="1" p:onlyOne="#{its[0]}"/><!-- 這裏不是用ref裝配 -->
有list的地方通常就有map,set,properties,所以也就有util:map,util:properties了,首先說下util:map
定義一個util:map:
<bean id="it1" class="com.yonyou.bean.Item" p:good="poke" p:weight="3.34"></bean>
<bean id="it2" class="com.yonyou.bean.Item" p:good="chicken" p:weight="5.66"></bean>
<util:map id="itmap">
<entry key="poke" value-ref="it1">
</entry>
<entry key="chicken" value-ref="it2">
</entry>
</util:map>
將key爲chicken的bean注入到ShopList的onlyOne屬性中:
<bean id="list8" class="com.yonyou.bean.ShopList" p:name="#{tax.getName()?: 'bullshit'}" p:count="2" p:price="1" p:onlyOne="#{itmap['chicken']}"/>
我們都知道Properties相對於Map來說,它的key,value都只能是String類型的,所以用法和Map差不多,不過在SpEL中允許直接從外部的一個properties文件中讀取,更爲方便
定義util:properties:
<util:properties id="itprop" location="classpath:spel.properites"/>
bean中使用
<bean id="list9" class="com.yonyou.bean.ShopList" p:name="#{itprop['username']}" p:price="1"/>
SpEL對於key-value的使用不止於此,還可以使用系統環境變量與java啓動參數,分別使用systemEnvironmen和systemProperties,用法如:#{systemEnvironmen[‘HOME’]},#{systemProperties[‘application.home’]}等等
查詢集合成員
購物結賬時,發現錢沒帶夠,此時我只想買重量小於3.5kg的食物,那麼就要篩選購物條目了,只需要“.?[]”的方式即可,我們來查詢下前面的util:list
<bean id="list10" class="com.yonyou.bean.ShopList" p:items="#{its.?[weight gt 3.5]}"/>
打印輸出,發現確實只有小於3.5kg的食物
ShopList [name=null, count=0, price=0.0, items=[Item [good=poke, weight=3.34], Item [good=egg, weight=2.54]], onlyOne=null]
投影集合
我們再給ShopList增加一個屬性:String[] allGood,現在要把util:list裏所有item的good放到這個數組裏,SpEL中使用“.![屬性名]”就可以做到
<bean id="list11" class="com.yonyou.bean.ShopList" p:allGood="#{its.![good]}"/>
打印結果:allGood取到了所有的good值
ShopList [name=null, count=0, price=0.0, items=[], onlyOne=null, allGood=[poke, chicken, dark, egg]]
那個可不可以獲取到所有小於3.5kg的所有條目的good呢?當然可以,結合兩者即可
例如:<bean id="list12" class="com.yonyou.bean.ShopList" p:allGood="#{its.?[weight gt 3.5].![good]}"/>
輸出結果:ShopList [name=null, count=0, price=0.0, items=[], onlyOne=null, allGood=[chicken, dark]]
好了,SIA中的SpEL我用12個小案例展示了一遍,如果大家有看不懂的地方請結合我的源碼看,下面是地址:
http://download.csdn.net/detail/yj7758423/9751253