SpEL表达式的首要目标是通过计算获得某个值。在计算这个数值的过程中,会使用到其他的值并会对这些值进行操作。最简单的SpEL求值或许是对字面值、Bean的属性或者某个类的常量进行求值。
SpEL表达式使用#{}作为取值运算符。
一、字面值
1、最简单的SpEL表达式或许仅包含一个字面值:
<property name="count" value="#{5}"/>
2、非SpEL表达式的值混用:
<property name="message" value="Thevalueis#{5}"/>
3、浮点型数字一样可以出现在SpEL表达式中:
<property name="frequency" value="#{89.7}"/>
4、String类型的字面值可以使用单引号或双引号作为字符串的界定符。将一个String类型的字面值装配到Bean的一个属性中:
<property name="name" value="#{'Chuck'}"/>
<property name='name' value='#{"Chuck"}'/>
5、装配布尔型的true和false:
<property name="enabled" value="#{false}"/>
二、引用bean、properties和方法
1、在SpEL表达式中使用BeanID将一个Bean装配到另一个Bean的属性中:
<property name="instrument" value="#{saxophone}"/>
等效于:
<property name="instrument" ref="saxophone"/>
2、将一个bean的属性装配到另一个bean的属性中:
<bean id="carl" class="com.springinaction.springidol.Instrumentalist">
<property name="song" value="#{kenny.song}"/>
</bean>
通过这种方式装配carlBean的song属性,其实等价于执行下面的示例代码:
Instrumentalist carl=new Instrumentalist();
carl.setSong(kenny.getSong());
3、调用一个bean的方法,将其返回值装配到另一个bean属性中:
<property name="song" value="#{songSelector.selectSong()}"/>
<property name="song" value="#{songSelector.selectSong().toUpperCase()}"/>
在SpEL中避免抛出讨厌的空指针异常(NullPointerException)的方法是使用null-safe存取器:
<property name="song" value="#{songSelector.selectSong()?.toUpperCase()}"/>
现在我们使用?.运算符代替点(.)来访问toUpperCase()方法。在访问右边方法之前,该运算符会确保左边项的值不会为null。所以,如果selectSong()返回null值,SpEL不再尝试调用toUpperCase()方法。
三、操作类
在SpEL中,使用T()运算符会调用类作用域的方法和常量。例如,在SpEL中使用Java的Math类,我们可以像下面的示例这样使用T()运算符:T(java.lang.Math)
1、把PI的值装配到Bean的一个属性中:
<propert yname="multiplier" value="#{T(java.lang.Math).PI}"/>
2、使用T()运算符也可以调用静态方法,将一个随机数(在0到1之间)装配到Bean的一个属性中:
<property name="randomNumber" value="#{T(java.lang.Math).random()}"/>
四、进行基础数学运算
1、两个数字相加,可以像下面那样使用+运算符:
<property name="adjustedAmount" value="#{counter.total+42}"/>
2、-运算符执行减法运算:
<property name="adjustedAmount" value="#{counter.total-20}"/>
3、*运算符执行乘法运算:
<property name="circumference" value="#{2*T(java.lang.Math).PI*circle.radius}"/>
4、/运算符执行除法运算:
<property name="average" value="#{counter.total/counter.count}"/>
5、%运算符执行求余运算:
<property name="remainder" value="#{counter.total%counter.count}"/>
6、不同于Java,SpEL还提供了乘方运算,如下所示:
<property name="area" value="#{T(java.lang.Math).PI*circle.radius^2}"/>
7、特别提一下+运算符,它还可以执行字符串连接。如下所示:
<property name="fullName" value="#{performer.firstName+''+performer.lastName}"/>
五、比较值
1、比较两个值是否相等:
<propertyname="equal"value="#{counter.total==100}"/>
2、类似地,小于(<)和大于(>)运算符用于比较不同的值。而且SpEL还提供了大于等于(>=)和小于等于(<=)运算符。
不过,在Spring的XML配置文件中使用小于等于和大于等于符号时,会报错,这是因为这两个符号在XML中有特殊含义。当在XML中使用SpEL时,最好对这些运算符使用SpEL的文本替代方式(textualalternatives),如下所示:
<property name="hasCapacity" value="#{counter.total le 100000}"/>
在这里,le运算符代表小于等于。其他的文本型比较运算符如表2.6所示。
3、使用and运算符,如下所示:
<property name="largeCircle" value="#{shape.kind=='circle' and shape.perimeter gt 10000}"/>
4、布尔类型的表达式求反,有两种运算符可以选择:符号型的!或者文本型的not。使用!运算符,如下所示:
<property name="outOfStock" value="#{!product.available}"/>
与使用not运算符是等价的:
<property name="outOfStock" value="#{notproduct.available}"/>
六、条件表达式
1、用SpEL的三元运算符(?:):
<property name="instrument" value="#{songSelector.selectSong()=='JingleBells'?piano:saxophone}"/>
虽然以上配置可以正常工作,但这里kenny.song的引用重复了两次。SpEL提供了三元运算符的变体来简化表达式:
<property name="song" value="#{kenny.song?:'Greensleeves'}"/>
在以上示例中,如果kenny.song不为null,那么表达式的求值结果是ken-ny.song,否则就是“Greensleeves”。
2、SpEL的正则表达式
假设我们想判断一个字符串是否是有效的邮件地址。在这种场景下,我们可以使用matches运算符,如下所示:
<property name="validEmail" value="#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.com'}"/>
七、筛选集合
SpEL还可以从集合的成员中提取某些属性放到一个新的集合中
假设我们定义了一个City类,如下所示(因为篇幅原因我们删除了getter/setter方法):
package com.habuma.spel.cities;
public class City{
private String name;
private String state;
private int population;
}
通过Spring的元素定义的一个City的List集合:
<util:list id="cities">
<bean class="com.habuma.spel.cities.City" p:name="Chicago" p:state="IL" p:population="2853114"/>
<bean class="com.habuma.spel.cities.City" p:name="Atlanta" p:state="GA" p:population="537958"/>
<bean class="com.habuma.spel.cities.City" p:name="Dallas" p:state="TX" p:population="1279910"/>
<bean class="com.habuma.spel.cities.City" p:name="Houston" p:state="TX" p:population="2242193"/>
<bean class="com.habuma.spel.cities.City" p:name="Odessa" p:state="TX" p:population="90943"/>
<bean class="com.habuma.spel.cities.City" p:name="ElPaso" p:state="TX" p:population="613190"/>
<bean class="com.habuma.spel.cities.City" p:name="Jal" p:state="NM" p:population="1996"/>
<bean class="com.habuma.spel.cities.City" p:name="LasCruces" p:state="NM" p:population="91865"/>
</util:list>
1、中括号([])运算符会始终通过索引访问集合中的成员。
从集合中提取一个成员,并将它装配到某个属性中:
<property name="chosenCity" value="#{cities[2]}"/>
假设你随机选择一个city:
<property name="chosenCity" value="#{cities[T(java.lang.Math).random()*cities.size()]}"/>
2、[]运算符同样可以用来获取java.util.Map集合中的成员,通过key获取:
假设City对象以其名字作为键放入Map集合中,获取键为Dallas的entry:
<propertyname="chosenCity"value="#{cities['Dallas']}"/>
3、[]运算符的另一种用法是从java.util.Properties集合中获取值
通过<util:properties>
元素在Spring中加载一个properties配置文件,如下所示:
<util:properties id="settings" location="classpath:settings.properties"/>
使用SpEL从settings Bean中访问一个名为twitter.accessToken的属性,如下所示:
<property name="accessToken" value="#{settings['twitter.accessToken']}"/>