spring-boot周边游(二)SpEL

KernelDev
• 阅读 6525

写在SpEL之前

EL表达式是JSP中一个十分重要的概念。它允许我们从model中读取数据以及条件性的渲染JSP页面。Spring在3.0的版本中也引入了Spring Expression Language从而使得spring具有更好的可扩展性和跨平台性。
虽然SpEL引擎作为Spring 组合里的表达式解析的基础 ,但它不直接依赖于Spring,可独立使用。这也是SpEL的最大优点。

这一章内容将包括SpEL的使用,并且会举一个例子从配置文件中读取相应的属性。因为最终的项目是为了实现thymeleaf+springboot+mysql, 而很多地方都无形中使用了SpEL,比如Thymeleaf获取model数据,比如项目从config文件中获取常量配置。让我们赶紧来感受一下这个功能的强大吧。

SpEL Operators

spring-boot周边游(二)SpEL

SpEL支持在表达式中使用多种类型的运算符,具体情况如上图所示。SpEL默认的格式为#{expression}。当然,它也支持嵌套一般的属性获取符${properties},如#{${someProperty} + 2}。这些值可以使用@Value("")注释注入到相应的属性上。
下面我们将举一些例子来说明这些运算符的使用

算数运算符

@Value("#{19 + 1}") // add的值为20
private double add; 
 
@Value("#{'String1 ' + 'string2'}") //addString的值为"String1 string2"
private String addString; 
 
@Value("#{20 - 1}") // subtract值为19
private double subtract;
 
@Value("#{10 * 2}") // multiply值为20
private double multiply;
 
@Value("#{36 / 2}") // divide值为19
private double divide;
 
@Value("#{36 div 2}") // div操作等价与/
private double divideAlphabetic; 
 
@Value("#{37 % 10}") // modulo值为7
private double modulo;
 
@Value("#{37 mod 10}") // mod操作等价于%
private double moduloAlphabetic; 
 
@Value("#{2 ^ 9}") // powerOf的值为512
private double powerOf;
 
@Value("#{(2 + 2) * 2 + 9}") // brackets值为17
private double brackets;

这里之所以给/赋予等价符号div是为了让XML配置形式兼容,无需进行转义。

关联和逻辑运算符

@Value("#{1 == 1}") // equal值为true
private boolean equal;
 
@Value("#{1 eq 1}") // eq等价于==
private boolean equalAlphabetic;
 
@Value("#{1 != 1}") // notEqual值为false
private boolean notEqual;
 
@Value("#{1 ne 1}") // ne等价于!=
private boolean notEqualAlphabetic;
 
@Value("#{1 < 1}") // lessThan的值为false
private boolean lessThan;
 
@Value("#{1 lt 1}") // lt等价于<
private boolean lessThanAlphabetic;
 
@Value("#{1 <= 1}") // lessThanOrEqual的值为true
private boolean lessThanOrEqual;
 
@Value("#{1 le 1}") // le等价于<=
private boolean lessThanOrEqualAlphabetic;
 
@Value("#{1 > 1}") // greaterThan的值为false
private boolean greaterThan;
 
@Value("#{1 gt 1}") // gt等价于>
private boolean greaterThanAlphabetic;
 
@Value("#{1 >= 1}") // greaterThanOrEqual的值为true
private boolean greaterThanOrEqual;
 
@Value("#{1 ge 1}") // ge等价于>=
private boolean greaterThanOrEqualAlphabetic;

@Value("#{250 > 200 && 200 < 4000}") // and值为true
private boolean and; 
 
@Value("#{250 > 200 and 200 < 4000}") // and等价于&&
private boolean andAlphabetic;
 
@Value("#{400 > 300 || 150 < 100}") // or的值为true
private boolean or;
 
@Value("#{400 > 300 or 150 < 100}") // or等价于||
private boolean orAlphabetic;
 
@Value("#{!true}") // not值为false
private boolean not;
 
@Value("#{not true}") // not等价于!
private boolean notAlphabetic;

条件运算符

condition ? a : b是指condition成立时值为a,否则为b
这种条件运算符可以用于实现if-else语句,也可以用于判断属性是否为空,并且在属性为空时提供默认值。

@Value("#{2 > 1 ? 'a' : 'b'}") // ternary的值为b
private String ternary;

@Value("#{someBean.someProperty != null ? someBean.someProperty : 'default'}")
private String ternary;

@Value("#{someBean.someProperty ?: 'default'}") // 等价于上式的执行结果
private String elvis;

正则表达式

使用matches语句来判断当前的字符串是否满足特定的正则表达式

@Value("#{'100' matches '\\d+' }") // Will inject true
private boolean validNumericStringResult;
 
@Value("#{'100fghdjf' matches '\\d+' }") // Will inject false
private boolean invalidNumericStringResult;
 
@Value("#{'valid alphabetic string' matches '[a-zA-Z\\s]+' }") // Will inject true
private boolean validAlphabeticStringResult;
 
@Value("#{'invalid alphabetic string #$1' matches '[a-zA-Z\\s]+' }") // Will inject false
private boolean invalidAlphabeticStringResult;
 
@Value("#{someBean.someValue matches '\d+'}") // Will inject true if someValue contains only digits
private boolean validNumericValue;

获取list和map数据类型

假设现在有一个Bean名称为workersHolder,这个组件中有两个fields,一个是workers的链表,这里记录了所有的员工名称,还有一个是salaryByWorkers键值对map,里面存储了员工姓名和其对应的薪水。现在这个bean中初始化了四个员工信息,如何能将这四个员工的信息读取出来?

@Component("workersHolder")
public class WorkersHolder {
    private List<String> workers = new LinkedList<>();
    private Map<String, Integer> salaryByWorkers = new HashMap<>();
 
    public WorkersHolder() {
        workers.add("John");
        workers.add("Susie");
        workers.add("Alex");
        workers.add("George");
 
        salaryByWorkers.put("John", 35000);
        salaryByWorkers.put("Susie", 47000);
        salaryByWorkers.put("Alex", 12000);
        salaryByWorkers.put("George", 14000);
    }
 
    //Getters and setters
}

map采用componentName.mapName['key']读取key对应的value
list采用componentName.listName[index]读取对应index下标的元素
同样也支持对方法的调用,整体的语法其实和JAVA是相似的。

@Value("#{workersHolder.salaryByWorkers['John']}") // Will inject 35000
private Integer johnSalary;
 
@Value("#{workersHolder.salaryByWorkers['George']}") // Will inject 14000
private Integer georgeSalary;
 
@Value("#{workersHolder.salaryByWorkers['Susie']}") // Will inject 47000
private Integer susieSalary;
 
@Value("#{workersHolder.workers[0]}") // Will inject John
private String firstWorker;
 
@Value("#{workersHolder.workers[3]}") // Will inject George
private String lastWorker;
 
@Value("#{workersHolder.workers.size()}") // Will inject 4
private Integer numberOfWorkers;

从上面这些例子我们可以看出,SpEL不仅可以调用属性,还可以访问一些公开的方法,甚至进行正则表达式的匹配,可以说是非常轻量级而且全能了。

至此我们已经了解了如何通过annotation来使用SpEL。其实SpEL还可以通过XML进行配置,甚至可以脱离Spring环境使用,下面可以简单介绍。

XML配置

spring-boot周边游(二)SpEL

这里直接从别的网站上找了一个实例,有兴趣的可以至底下的references中查看,这里就不详细叙述了。

SpEL in Spring 真实场景示例

现在我们的项目有一个需求,结合配置文件,从配置文件中读取我们想要知道的数据,并赋值给类中的变量。这里我们的配置文件采用yaml格式(不熟悉yaml请先参考我的这篇博客)。现在我们先看配置文件的内容。

配置文件名称为application.yml,application-test.yml和application-validate.yml,位于classpath:/resources/config目录底下,其中application.yml是主配置文件,决定选择哪个配置文件作为当前配置。application-test.yml是测试环境的配置文件,application-validate.yml是校验信息的配置文件。内容分别如下所示。

application.yml

#当前活跃的配置文件为application-test和application-validate
spring:
  profiles:
    active: test,validate

application-test.yml

#测试环境的配置内容,这里举的例子是映射到服务器端口号为8080
server:
  port: 8080

...

application-validate.yml

#配置了校验信息
login:
  username:
    notempty: 用户名不可以为空

下面展示了在代码中使用annotation获得配置文件中的值

@Value("${server.port}")
private int port;

@Value("${login.username.notempty}")
private String notEmpty;

当然,为了方便起见,spring还允许我们将所有的配置文件映射到一个专门的JAVA Class中,封装成一bean。这样在需要注入的时候,只需使用@Autowired注释将其引用进来就可以使用。

@Data
@Component
@ConfigurationProperties(prefix = "server")
public class AppConfig{
    private int port;
}

这里需要注意的是还需要在spring-boot的入口文件上加标签

@SpringBootApplication
@EnableConfigurationProperties({AppConfig.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

在调用的类中注入AppConfig

@Autowired
private AppConfig config;

References

项目地址
SpEL官方文档中文版
快速教程
spring-boot自定义配置文件
spring-boot yaml使用方式

spring-boot周边游(二)SpEL
想要了解更多开发技术,面试教程以及互联网公司内推,欢迎关注我的微信公众号!将会不定期的发放福利哦~

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
3年前
springcloud eureka.instance
1.在springcloud中服务的 InstanceID默认值是:${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance\_id:${server.port}},也就是:主机名:应用名:应用端口。如图1
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Spring Bean定义中表达式语言的支持
    SpEL(SpringExpressionLanguage,Spring表达式语言)的一个重要的作用就是扩展Spring容器的功能,允许在Bean定义中使用SpEL。XML配置文件和Annotation中都可以使用SpEL。在XML和Annotation中使用SpEL时,都需要使用{expression}的格式来包装表达式。    例如
Wesley13 Wesley13
3年前
MySQL数据库InnoDB存储引擎Log漫游(1)
作者:宋利兵来源:MySQL代码研究(mysqlcode)0、导读本文介绍了InnoDB引擎如何利用UndoLog和RedoLog来保证事务的原子性、持久性原理,以及InnoDB引擎实现UndoLog和RedoLog的基本思路。00–UndoLogUndoLog是为了实现事务的原子性,
Easter79 Easter79
3年前
Spring之Spel表达式
正常业务场景一般不用这个技术,但需要知道有这么个东西支持Spring。记忆力不好,抄了些套路代码便于以后用到。packagecom.paic.phssp.springtest.spel;importjava.util.Arrays;importjava.util.List;public
Stella981 Stella981
3年前
Spring 必知概念(一)
1、什么是Spring框架?Spring框架有哪些主要模块?Spring框架是一个为Java应用程序的开发提供了综合、广泛的基础性支持的Java平台。Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。Spring框架本身亦是按照设计模式精心打造,这使得我们可以在开发环境中安心的集成Spring框架,不必担心S
Easter79 Easter79
3年前
Spring表达式语言:SpEL
1、Spring表达式语言(简称:SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。2、语法类似于EL:SpEL使用{...}作为定界符,所有在大括号内的字符都被认为是SpEL。3、SpEL为bean的属性进行动态赋值提供了便利。4、通过SpEL可以实现:\通过bean的id对bean进行引用\调用方法以及引用对象