1、SpEL
1.1、简介
Spring Expression Language,Spring表达式语言,简称SpEL。支持运行时查询并可以操作对象图。
和JSP页面上的EL表达式、Struts2中用到的OGNL表达式一样,SpEL根据JavaBean风格的getXxx()、setXxx()方法定义的属性访问对象图,完全符合我们熟悉的操作习惯。
Spring3中引入了Spring表达式语言—SpringEL,SpEL是一种强大,简洁的装配Bean的方式,他可以通过运行期间执行的表达式将值装配到我们的属性或构造函数当中,更可以调用JDK中提供的静态常量,获取外部Properties文件中的的配置 为什么要使用SpringEL? 我们平常通过配置文件或Annotaton注入的Bean,其实都可以称为静态性注入,试想一下,若然我Bean A中有变量A,它的值需要根据Bean B的B变量为参考,在这场景下静态注入就对这样的处理显得非常无力,而Spring3增加的SpringEL就可以完全满足这种需求,而且还可以对不同Bean的字段进行计算再进行赋值,功能非常强大
如何使用SpringEL?
SpringEL从名字来看就能看出,和EL是有点关系的,SpringEL的使用和EL表达式的使用非常相似,EL表达式在JSP页面更方便的获取后台中的值,而SpringEL就是为了更方便获取Spring容器中的Bean的值,EL使用${},而SpringEL使用#{}进行表达式的声明
1.2、基本语法
SpEL使用#{…}作为定界符,所有在大框号中的字符都将被认为是SpEL表达式。
使用SpringEL注入简单值
public class El{
/**
* @Value注解相当于xml中的<property>标签
* SpringEl同样支持在xml中<property>中编写
*/
@Value("#{5}")//注入简单的值,输出为5
private int num;
//注入id为testConstant的Bean
@Value("#{tsetConstant}")
private TestConstant constant;
//注入id为testConstant bean中的str常量/变量
@Value("#{testConstant.str}")
private String str;
}
使用SpringEL调用方法
public class TestSpringEL {
/*
* TestConstant类中有两个方法重载,
* 返回值为String类型
*/
// 调用无参方法
@Value("#{testConstant.showProperty}")
private String method1;
// 有参接收字符串的方法
@Value("#{testConstant.showProperty('Hello')}")
private String method2;
/*
* 若然希望方法返回的String为大写
*/
@Value("#{testConstant.showProperty().toUpperCase()}")
private String method3;
/*
* 若使用method3这种方式,若然showProperty返回为null,
* 将会抛出NullPointerException,可以使用以下方式避免
*/
@Value("#{testConstant.showProperty()?.toUpperCase}")
private String method4;
/*
* 使用?.符号代表若然左边的值为null,将不执行右边方法,
* 读者可以灵活运用在其他场景,只要左边可能返回null,
* 即可使用上面示例中的?.
*/
}
SpringEL调用静态类或常量
public class TestSpringEL {
/*
* 注入JDK中的工具类常量或调用工具类的方法
*/
// 获取Math的PI常量
@Value("#{T(java.lang.Math).PI")
private double pi;
// 调用random方法获取返回值
@Value("#{T(java.lang.Math).random()}")
private double ramdom;
// 获取文件路径符号
@Value("#{T(java.io.File).separator}")
private String separator;
}
SpringEL运算
public class TestSpringEL {
/*
* 使用SpringEL进行运算及逻辑操作
*/
// 拼接字符串
@Value("#{testConstant.nickname + ' ' + testConstant.name}")
private String concatString;
// 对数字类型进行运算,testConstant拥有num属性
@Value("#{ 3 * T(java.lang.Math).PI + testConstant.num}")
private double operation;
// 进行逻辑运算
@Value("#{testConstant.num > 100 and testConstant.num <= 200}")
private boolean logicOperation;
// 进行或非逻辑操作
@Value("#{ not testConstant.num == 100 or testConstant.num <= 200}")
private boolean logicOperation2;
// 使用三元运算符
@Value("#{testConstant.num > 100 ? testConstant.num : testConstant.num + 100}")
private Integer logicOperation3;
}
SpringEL使用正则表达式
public class TestSpringEL {
// 验证是否邮箱地址正则表达式
@Value("#{testConstant.STR match '\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+'}")
private boolean regularExpression;
}
SpringEL操作集合
public class TestSpringEL {
/*
* TestConstant类中拥有名为testList的List变量, 和名为testMap的Map
*/
// 获取下标为0的元素
@Value("#{testConstant.testList[0]}")
private String str;
// 获取下标为0元素的大写形式
@Value("#{testConstant.testList[0]?.toUpperCase()}")
private String upperStr;
// 获取map中key为hello的value
@Value("#{testConstant.testMap['hello']}")
private String mapValue;
// 根据testList下标为0元素作为key获取testMap的value
@Value("#{testConstant.testMap[testConstant.testList[0]]}")
private String mapStrByTestList;
}
Spring操作外部Properties文件
首先通过applicaContext.xml中util:properties增加properties文件
<!-- 注意需要引入Spring的util schemea命名空间和注意id属性,id属性将在SpringEL中使用 -->
<util:properties id="test"location="classpath:application.properties"/>
public class TestSpringEL {
// 注意test为xml文件中声明的id
@Value("#{test['jdbc.url']}")
private String propertiesValue;
}
SpringEL查询筛选集合和投影
public class TestSpringEL {
/*
* 声明City类,有population属性 testContants拥有名叫cityList的City类List集合
*/
// 过滤testConstant中cityList集合population属性大于1000的全部数据注入到本属性
@Value("#{testConstant.cityList.?[population > 1000]}")
private List<City> cityList;
// 过滤testConstant中cityList集合population属性等于1000的第一条数据注入到本属性
@Value("#{testConstant.cityList.^[population == 1000]}")
private City city;
// 过滤testConstant中cityList集合population属性小于1000的最后一条数据注入到本属性
@Value("#{testConstant.cityList.$[population < 1000]}")
private City city2;
/*
* 首先为city增加name属性,代表城市的名称
*/
/*
* 假如我们在过滤城市集合后只想保留城市的名称,
* 可以使用如下方式进行投影
*/
@Value("#{testConstant.cityList.?[population > 1000].![name]}")
private List<String> cityName;
1.3、使用字面量
●整数: <property name="count" value="#{5}"/>
●小数:<property name="frequency" value="#{89.7}"/>
●科学计数法:<property name="capacity" value="#{1e4}"/>
●String类型的字面量可以使用单引号或者双引号作为字符串的定界符号
<property name=“name” value="#{'Chuck'}"/>
<property name='name' value='#{"Chuck"}'/>
●Boolean:<property name="enabled" value="#{false}"/>
1.4、引用其他bean
<bean id="emp04" class="com.zy.parent.bean.Employee">
<property name="empId" value="1003"/>
<property name="empName" value="Kate"/>
<property name="age" value="21"/>
<property name="detp" value="#{dept}"/>
</bean>
1.5、引用其他bean的属性值作为自己某个属性的值
<bean id="emp05" class="com.zy.parent.bean.Employee">
<property name="empId" value="1003"/>
<property name="empName" value="Kate"/>
<property name="age" value="21"/>
<property name="deptName" value="#{dept.deptName}"/>
</bean>
1.6、调用非静态方法
<!-- 创建一个对象,在SpEL表达式中调用这个对象的方法 -->
<bean id="salaryGenerator" class="com.atguigu.spel.bean.SalaryGenerator"/>
<bean id="employee" class="com.zy.spel.bean.Employee">
<!-- 通过对象方法的返回值为属性赋值 -->
<property name="salayOfYear" value="#{salaryGenerator.getSalaryOfYear(5000)}"/>
</bean>
1.7、调用静态方法
<bean id="employee" class="com.zy.spel.bean.Employee">
<!-- 在SpEL表达式中调用类的静态方法 -->
<property name="circle" value="#{T(java.lang.Math).PI*20}"/>
</bean>
1.8、运算符
①算术运算符:+、-、*、/、%、^
②字符串连接:+
③比较运算符:<、>、==、<=、>=、lt、gt、eq、le、ge
④逻辑运算符:and, or, not, |
⑤三目运算符:判断条件?判断结果为true时的取值:判断结果为false时的取值
⑥正则表达式:matches
优点
:SpringEL功能非常强大,在Annotation的方式开发时可能感觉并不强烈,因为可以直接编写到源代码来实现SpringEL的功能,但若然是在XML文件中进行配置,SpringEL可以弥补XML静态注入的不足,从而实现更强大的注入 缺点
:SpringEL在使用时仅仅是一个字符串,不易于排错与测试,也没有IDE检查我们的语法,当出现错误时较难检测