####使用场合####
假设有这样一种情况,一个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