起初觉得这一章并没有什么好讲的,因为我在工作中也只是运用了其中很基础的一些功能,直到今天去深入学习这一块才发现,其实spring的EL(expressing language)表达式是多么强大.
Spring的EL表达式简称为SpEL,让他OGNL表达式等表达式相似,他与spring直接是互相独立的,比如负责解析字符串的接口(ExpressionParse).可以先看下官方的例子:
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();
官方宣称SpEL表达式支持以下几个功能:
1. 文字表达19. 模板表达式
当然,这不是我们需要重点关注的方式.下面来看下如何在注解中使用SpEl表达式.
1. 简单字符串注入
@Value("spring boot")
private String spring;
这种方法简单粗暴,但是感觉没有什么使用的实际意义.(个人见解,勿喷)
2. 从系统属性中获取并注入
@Value("#{systemProperties['os.name']}")
private String osName;
输出是PC的操作系统,例如Windows 10,他能获取系统的属性值
3. 调用类的方法
@Value("#{T(java.lang.Math).random() * 100}")
private double randomNumber;
输出的是随机的一个0~100的double值,T()中填写的是调用的java中类.他可以直接使用算术运算符计算值
4. 获取类的属性
首先写一个简单的Person类
package com.yczuoxin.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Person {
@Value("zhangsan")
private String pName;
public String getpName() {
return pName;
}
public void setpName(String pName) {
this.pName = pName;
}
}
然后去获取其pName:
@Value("#{person.pName}")
private String pName;
输出的结果就是我们注入进去的"zhangsan",所以SpEL可以直接获取类中的属性.
注意:这里Person类的pName属性是私有的,所以必须提供get方法.不然会报错.但是如果pName是共有方法,则不需要提供get方法也可以获取值.
5. 链式调用方法
还是以Person类来测试
@Value("#{person.getpName().toUpperCase()}")
private String pName;
此时我们输出的结果是"ZHANGSAN",可见成功的调用了String的toUpperCase方法.此时,思维严谨的朋友肯定会问了,如果获取出来的值是null的话,不就空指针了?说的没错,如果是null会抛出org.springframework.beans.factory.UnsatisfiedDependencyException的异常,那么要怎么避免呢?只需要如下地方加一个"?"号就可以解决了.
@Value("#{person.getpName()?.toUpperCase()}")
private String pName;
?号的作用就是在调用方法之前,先判断结果是不是null值,如果是则直接返回null,如果不是,才会继续调用后面的方法.
6. 算术运算
@Value("#{(1+2)>3}")
public boolean count;
输出结果是false,说明SpEL支持算术运算.
7. 三元运算符
@Value("#{(1+2)>3 ? 'yes' : 'no'}")
public String count;
输出结果为no,说明SpEL支持三元运算
8. elvis 运算符(如果有值则输出值,为null则输出默认值),依然用Person类,删掉注解@Value
@Value("#{person.getpName()?:'zhangsan'}")
private String pName;
输出结果为zhangsan,说明SpEL支持elvis 运算符.
9. 集合类型的运用
先改写Person类,在其中加入了age属性,重新toString方法,无参构造和有参构造.
package com.yczuoxin.demo.config;
import org.springframework.stereotype.Component;
@Component
public class Person {
public Person() {
}
public Person(String pName, int age) {
this.pName = pName;
this.age = age;
}
private String pName;
private int age;
public void setpName(String pName) {
this.pName = pName;
}
public String getpName() {
return pName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
然后加入测试bean
package com.yczuoxin.demo.config;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class TestBean {
public List list = Arrays.asList(new Person("zhangsan",19),new Person("lisi",19), new Person("wangwu",20));
public Map map;
public TestBean(){
map = new HashMap<>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
}
}
a. 查询集合下标为2的元素
@Value("#{testBean.list[2]}")
private Person person;
Person{pName='wangwu', age=20}
可见SpEL取出了list中下标为2的对象.
@Value("#{testBean.map[key1]}")
private String value;
value1
在Map中,取出的Map对应key的值.
b. 查询集合中值对应的对象
@Value("#{testBean.list.?[age==19]}")
private List person;
[Person{pName='zhangsan', age=19}, Person{pName='lisi', age=19}]
SpEL取出了age为19的对象.注意要拿list去接收,不然会报错.其中.?[]是查询所有,而.^[]是查询第一个,满足条件的,.$[]是
查询最后一个满足条件的.
c. 集合投影
@Value("#{testBean.list.![pName]}")
private List pNames;
[zhangsan, lisi, wangwu]
SpEL使用.![]进行集合投影,将Person集合中的pName属性都拿了出来,并且塞到了一个新的集合之中,
忘记了最常用的获取配置文件的内容的方法了,在此补上
配置文件
book.name = spring boot
@Value("${book.name}")
private String normal;
spring boot
什么,你的结果不对?,因为你需要在配置类上加上一个注解如下,这个很简单也很常用,就不仔细说了.
package com.yczuoxin.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@PropertySource("classpath:test.properties")
public class Beans {
@Value("${book.name}")
public String name;
public void print(){
System.out.println(name);
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}
}
先记录到这里,是不是感觉SpEL功能特别强大,只是我们工作中没有想到去使用他.所以在这里,我做成一个笔记,到时候说不定项目中可以用到,看起来还会比较高大上.