前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring-SpEL表达式[通俗易懂]

Spring-SpEL表达式[通俗易懂]

作者头像
Java架构师必看
发布2022-08-26 08:56:38
8580
发布2022-08-26 08:56:38
举报
文章被收录于专栏:Java架构师必看

大家好,我是架构君,一个会写代码吟诗的架构师。今天说一说Spring-SpEL表达式[通俗易懂],希望能够帮助大家进步!!!

SpEL表达式

代码语言:txt
复制
- [简介](https://javajgs.com/#_1)
- [用法](https://javajgs.com/#_18)
    - [1. 注解@Value](https://javajgs.com/#1_Value_20)
    - [2. XML配置](https://javajgs.com/#2_XML_25)
    - [3. Expression](https://javajgs.com/#3_Expression_34)
- [表达式语法](https://javajgs.com/#_83)
    - [1. 引用Bean、属性和方法(必须是public修饰的)](https://javajgs.com/#1_Beanpublic_84)
    - [2. 运算符](https://javajgs.com/#2__93)
    - [3. 调用静态方法或静态属性](https://javajgs.com/#3__110)
    - [4. 获取容器内的变量](https://javajgs.com/#4__117)
    - [5. 方法调用](https://javajgs.com/#5__129)
    - [6. Elvis运算符](https://javajgs.com/#6_Elvis_139)
    - [7. 安全保证](https://javajgs.com/#7__146)
    - [8. 直接使用 java 代码 new/instance of](https://javajgs.com/#8__java__newinstance_of_153)
    - [9. 集合定义/访问/修改/选择](https://javajgs.com/#9__159)
    - [10. Bean引用](https://javajgs.com/#10_Bean_190)

简介

Spring Expression Language(缩写为SpEL)是一种强大的表达式语言。在Spring 产品组合中,它是表达式计算的基础。它支持在运行时查询和操作对象图,它可以与基于 XML 和基于注解的 Spring 配置还有 bean 定义一起使用。由于它能够在运行时动态分配值,因此可以为我们节省大量Java代码。

依赖:

代码语言:javascript
复制
		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.0.5.RELEASE</version>
        </dependency>

只听到从架构师办公室传来架构君的声音:

人如风后入江云,情似雨馀粘地絮。有谁来对上联或下联?

用法

SpEL有三种用法,一种是在注解@Value中;一种是XML配置;最后一种是在代码块中使用Expression。

1. 注解@Value

代码语言:javascript
复制
@Value("#{表达式}")
public String port;

2. XML配置

代码语言:javascript
复制
<bean id="xxx" class="com.lizq.xxx">
    <!-- 同@Value,#{}内是表达式的值,可放在property或constructor-arg内 -->
    <property name="port" value="#{表达式}">
</bean>

3. Expression

代码语言:javascript
复制
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class SpelTest { 
   
    public static void main(String[] args) { 
   
        String skipExpress1 = "${value1==value2}";
        String skipExpress2 = "${value1==value2 and value2 == value3}";
        Map map = new HashMap<>();
        map.put("value1", "val_1");
        map.put("value2", "val_1");
        map.put("value3", "val_3");
        Boolean b1 = SpelTest.expressionParsing(skipExpress1, map);
        System.out.println(b1);
        Boolean b2 = SpelTest.expressionParsing(skipExpress2, map);
        System.out.println(b2);
    }

    public static Boolean expressionParsing(String skipExpress, Map map) { 
   
        if (skipExpress != null && !"".equals(skipExpress) && map.isEmpty()) { 
   
            return false;
        }
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();

        TemplateParserContext templateParserContext = new TemplateParserContext("${", "}");
        PropertyAccessor propertyAccessor = new MapAccessor();
        context.setVariables(map);
        context.setPropertyAccessors(Arrays.asList(propertyAccessor));

        SpelExpression expression = (SpelExpression) parser.parseExpression(skipExpress, templateParserContext);
        expression.setEvaluationContext(context);
        boolean value = expression.getValue(map, boolean.class);
        return value;
    }
}

表达式语法

1. 引用Bean、属性和方法(必须是public修饰的)

代码语言:javascript
复制
<!-- 引用其他对象的属性 -->
<property name="userName" value="#{user.name}" />
<!-- 引用其他对象的方法 -->
<property name="userPrint" value="#{user.print()}" />

2. 运算符

算术运算符:+,-,*,/,%,^

代码语言:javascript
复制
<!-- 1000 -->
<property name="num" value="#{10^3}" />
<!-- 2021年1月 -->
<property name="yearMonth" value="#{2021+'年'+1+'月'}" />

比较运算符:<,>,==,<=,>=,lt,gt,eq,le,ge

逻辑运算符:and,or,not,&&,||,!

三目运算符:?true:false

正则表达式:matches

代码语言:javascript
复制
<!-- true -->
<property name="emailBool" value="#{email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}'}" />

3. 调用静态方法或静态属性

通过 T() 调用一个类的静态方法,它将返回一个 Class Object,然后再调用相应的方法或属性:

代码语言:javascript
复制
<!-- 3.141592653589793 -->
<property name="PI" value="#{T(java.lang.Math).PI}" />

4. 获取容器内的变量

可以使用“#bean_id”来获取。有两个特殊的变量,可以直接使用。

  1. this:使用当前正在计算的上下文
  2. root:引用容器的root对象
代码语言:javascript
复制
String result2 = parser.parseExpression("#root").getValue(ctx, String.class);  
String s = new String("获取容器内的变量");
ctx.setVariable("str",s);
//取id为abc的bean,然后调用其中的substring方法 
parser.parseExpression("#str.substring(0,1)").getValue(ctx, String.class);

5. 方法调用

与Java代码没有什么区别,可见上面的例子

可以自定义方法,如下:

代码语言:javascript
复制
Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class); 
ctx.registerFunction("parseInt1", parseInt);
ctx.setVariable("parseInt2", parseInt);

“registerFunction” 和 “setVariable” 都可以注册自定义函数,但是两个方法的含义不一样,推荐使用 “registerFunction” 方法注册自定义函数。

6. Elvis运算符

是三目运算符的特殊写法,可以避免null报错的情况

代码语言:javascript
复制
// name != null? name : "other" 简写为
name ? : "other"

7. 安全保证

为了避免操作对象本身可能为null,取属性时报错,定义语法

语法: “对象?.变量|方法”

代码语言:javascript
复制
list?.size()

8. 直接使用 java 代码 new/instance of

此方法只能是java.lang 下的类才可以省略包名

代码语言:javascript
复制
Expression exp = parser.parseExpression("new Spring('Hello World')");

9. 集合定义/访问/修改/选择

定义:使用“{表达式,……}”定义List,如“{1,2,3}”

访问:SpEL目前支持所有集合类型和字典类型的元素访问。语法:

代码语言:javascript
复制
“集合[索引]”、“map[key]”

修改:可以使用赋值表达式或Expression接口的setValue方法修改;

代码语言:javascript
复制
//赋值语句
int result = parser.parseExpression("#array[1] = 3").getValue(context, int.class);
//serValue方法
parser.parseExpression("#array[2]").setValue(context, 4);

选择:通过一定的规则对及格进行筛选,构造出另一个集合

代码语言:javascript
复制
语法:“(list|map).?[选择表达式]”
**注意**:选择表达式结果必须是boolean类型,如果true则选择的元素将添加到新集合中,false将不添加到新集合中

选择:根据集合中的元素中通过选择来构造另一个集合,该集合和原集合具有相同数量的元素

代码语言:javascript
复制
语法:“SpEL使用“(list|map).![投影表达式]”
// 从userlist下筛选出age>18的子集合,再将他们的name字段投为新的list
@Value("#{userlist.?[age>18].![name]}")
private ArrayList<String> usernames;

10. Bean引用

SpEL 支持使用“@”符号来引用 Bean,在引用Bean时需要使用 BeanResolver 接口实现来查找 Bean,Spring 提供 BeanFactoryResolver 实现;

代码语言:javascript
复制
public void testBeanExpression() { 
   
	ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
	ctx.refresh();
	ExpressionParser parser = new SpelExpressionParser();
	StandardEvaluationContext context = new StandardEvaluationContext();
	context.setBeanResolver(new BeanFactoryResolver(ctx));

	Properties result1 = parser.parseExpression("@systemProperties").getValue(context, Properties.class);
	Assert.assertEquals(System.getProperties(), result1);
}

参考文献:

https://www.jianshu.com/p/e0b50053b5d3

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-08-252,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpEL表达式
  • 简介
  • 用法
    • 1. 注解@Value
      • 2. XML配置
        • 3. Expression
        • 表达式语法
          • 1. 引用Bean、属性和方法(必须是public修饰的)
            • 2. 运算符
              • 3. 调用静态方法或静态属性
                • 4. 获取容器内的变量
                  • 5. 方法调用
                    • 6. Elvis运算符
                      • 7. 安全保证
                        • 8. 直接使用 java 代码 new/instance of
                          • 9. 集合定义/访问/修改/选择
                            • 10. Bean引用
                            相关产品与服务
                            容器服务
                            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档