什么是SpEL
Spring 表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。 语法类似于 EL表达式:SpEL 使用 #{…}作为定界符,所有在大框号中的字符都将被认为是 SpEL。SpEL 为 bean 的属性进行动态赋值提供了便利 通过 SpEL 可以实现:
通过 bean 的 id 对 bean 进行引用 调用方法以及引用对象中的属性计算表达式的值正则表达式的匹配
SpEL很重要的一个功能就是能够实现 动态赋值
字面量表达式
字面量的表示:
整数:
小数:
科学计数法:
String可以使用单引号或者双引号作为字符串的定界符号: 或
Boolean:
以上的用法其实没有什么意义,并不能体现出SpEL的强大,这里些出来只是简单介绍下用法而已。
SpEL使用
举个例子:
先创建三个类
Address类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package
com.spring.spel;
public
class
Address {
private
String province;
private
String city;
public
String getProvince() {
return
province;
}
public
void
setProvince(String province) {
this
.province = province;
}
public
String getCity() {
return
city;
}
public
void
setCity(String city) {
this
.city = city;
}
@Override
public
String toString() {
return
"Address [province="
+ province +
", city="
+ city +
"]"
;
}
}
|
Car类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
package
com.spring.spel;
public
class
Car {
private
String brand;
private
double
price;
//轮胎的周长
private
double
tyrePerimeter;
public
String getBrand() {
return
brand;
}
public
void
setBrand(String brand) {
this
.brand = brand;
}
public
double
getPrice() {
return
price;
}
public
void
setPrice(
double
price) {
this
.price = price;
}
public
double
getTyrePerimeter() {
return
tyrePerimeter;
}
public
void
setTyrePerimeter(
double
tyrePerimeter) {
this
.tyrePerimeter = tyrePerimeter;
}
@Override
public
String toString() {
return
"Car [brand="
+ brand +
", price="
+ price +
", tyrePerimeter="
+ tyrePerimeter +
"]"
;
}
}
|
Person类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package
com.spring.spel;
public
class
Person {
private
String name;
private
Car car;
private
String city;
private
String info;
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
public
Car getCar() {
return
car;
}
public
void
setCar(Car car) {
this
.car = car;
}
public
String getCity() {
return
city;
}
public
void
setCity(String city) {
this
.city = city;
}
public
String getInfo() {
return
info;
}
public
void
setInfo(String info) {
this
.info = info;
}
@Override
public
String toString() {
return
"Person [name="
+ name +
", car="
+ car +
", city="
+ city
+
", info="
+ info +
"]"
;
}
}
|
bean配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<!-- 使用spel赋字面值 -->
<bean
class
=
"com.spring.spel.Address"
id=
"address"
>
<property name=
"province"
value=
"#{'安徽'}"
></property>
<property name=
"city"
value=
"#{'合肥'}"
></property>
</bean>
<!-- 使用spel引用类的静态属性 -->
<bean
class
=
"com.spring.spel.Car"
id=
"car"
>
<property name=
"brand"
value=
"bmw"
></property>
<property name=
"price"
value=
"350000"
></property>
<!-- 引用Math类的静态属性PI -->
<property name=
"tyrePerimeter"
value=
"#{T(java.lang.Math).PI * 80}"
></property>
</bean>
<bean
class
=
"com.spring.spel.Person"
id=
"person"
>
<property name=
"name"
value=
"tom"
></property>
<!-- 使用spel引用其他的bean -->
<property name=
"car"
value=
"#{car}"
></property>
<!-- 使用spel引用其他bean的属性 -->
<property name=
"city"
value=
"#{address.city}"
></property>
<!-- 使用spel语法判断 -->
<property name=
"info"
value=
"#{car.price > 300000 ? '金领' : '白领'}"
></property>
</bean>
|
测试类:
1
2
3
4
5
6
7
8
9
|
ApplicationContext ctx =
new
ClassPathXmlApplicationContext(
"beans-spel.xml"
);
Address address = (Address) ctx.getBean(
"address"
);
System.out.println(address);
Car car = (Car) ctx.getBean(
"car"
);
System.out.println(car);
Person person = (Person) ctx.getBean(
"person"
);
System.out.println(person);
|
总结:
#{T(java.lang.Math).PI :使用java类的静态属性#{car}: 使用spel引用其他的bean#{address.city}:使用spel引用其他bean的属性#{car.price > 300000 ? '金领' : '白领'}:使用spel条件判断
SpEL其他用法:
调用其他bean实例的方法,还可以连缀操作
1
|
<property name=
"city"
value=
"#{address.getCity().getXxx}"
></property>
|
算数运算符:+, -, *, /, %, ^:
加号还可以用作字符串连接:
比较运算符: eq(==),lt(<),le(<=),gt(>),ge(>=) 括号里面外面的都可以使用逻辑表达式:and,or,not或!。SpEL支持正则表达式匹配
1
|
<property name=
"validEmail"
value=
"#{admin.email matches '[a-zA-Z0-9._%+_]+@[a-zA-Z0-9.-]+\\.com'}"
></property>
|
注解使用SpEl
利用@Value注解可以给实体属性赋默认值
@Value可以使用SpEL表达式,例如:
1
2
3
4
5
|
@Value
(
"#{'福建'}"
)
private
String province;
@Value
(
"#{'福州'}"
)
private
String city;
|
使用前需要开启注解扫描器:
1
|
<context:component-scan base-
package
=
"com.spring"
></context:component-scan>
|
单个装饰器的使用:装饰器的执行原理
#1.定义两个装饰器(闭包函数,装饰函数都可以称呼),功能是给字体进行加粗和倾斜的标签。
def makeBold(fn):
print("BBBBB"*5)
def wrapped():
print("bbbbb"*5)
return "<b>" + fn() + "</b>"
return wrapped
def makeItalic(fn):
print("IIIII"*5)
def wrapped():
print("iiiiii" * 5)
return "<i>" + fn() + "</i>"
return wrapped
#2.装饰器的使用,直接@加上函数名的形式,放到需要装饰的函数头上即可。
@makeBold #效果等同于test_Bold=makeBold(test_Bold),装饰器放在一个函数上,相当于将这个函数当成参数传递给装饰函数
def test_Bold():
print("test_Bold"*5)
return "this is the test_Bold"
@makeItalic #效果等同于test_Italic=makeItalic(test_Italic),装饰器放在一个函数上,相当于将这个函数当成参数传递给装饰函数
def test_Italic():
print("test_Itali" * 5)
return "this is the test_Italic"
下面实现对上面的单个装饰器代码的测试:
1.1直接上面运行程序,什么不调用,也不操作,发现也有结果。
'''执行结果如下:
BBBBBBBBBBBBBBBBBBBBBBBBB
IIIIIIIIIIIIIIIIIIIIIIIII
'''
原因分析:
直接执行python程序,不调用任何方法,发现makeBold与makeItalic函数里面的第一个print函数也执行了。因为@makeBold其效果等同于test_Bold=makeBold( test_Bold ),所以程序执行时,从上到下加载执行到函数体上方的标识符@makeBold@makeItalic时,相当于执行了test_Bold=makeBold(test_Bold),test_Italic=makeBold(test_Italic),所以相当于调用了makeBold和makeItlic这两个函数,所以依次执行了这两个函数中第一个print语句。因为@makeBold在前,所以结果就是上面的BBBB....和IIIIIII....(其实这两个函数还有返回值,返回值分别是这两个函数内部的闭包,只是这里没有显示出来而已)