Spring SpEL在Flink中的应用-SpEL详解

前言

Spring 表达式语言 Spring Expression Language(简称 SpEL )是一个支持运行时查询和操做对象图的表达式语言 。 语法相似于 EL 表达式 ,但提供了显式方法调用和基本字符串模板函数等额外特性。SpEL 在许多组件中都得到了广泛应用,如 Spring Data、Spring Security、Spring Web Flow 等。它提供了一种非常灵活的方式来查询和操作对象图,从而简化了复杂的业务逻辑和数据操作。本系列文章介绍SpEL与Flink结合应用。


一、SpEL主要功能

  • 属性查询和设置:可以查询和设置对象的属性。例如,#root.name 查询根对象的 "name" 属性。
  • 方法调用:可以调用对象的任意方法。例如,#root.someMethod() 调用根对象的 "someMethod" 方法。
  • 条件表达式:可以使用条件表达式,如 ?>, ?, <, <=, >=, !=, == 来判断值。
  • 布尔和关系运算符:可用于布尔和关系运算。
  • 集合操作:可以用来操作集合,如 size(), contains(), any, all, isEmpty 等。
  • 自定义函数:可以注册自定义函数,并在 SpEL 表达式中调用它们。
  • 类型转换:SpEL 支持类型转换,例如 as 关键字可以用来转换类型。
  • 正则表达式:可以使用正则表达式进行模式匹配。
  • 解析 JSON:SpEL 可以解析 JSON 字符串并查询其内容。

二、POM依赖

首先在 pom.xml 中加入依赖:

XML 复制代码
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-expression</artifactId>
   <version>5.2.0.RELEASE</version>
</dependency>

二、SpEL应用

1.解析字面量

java 复制代码
    private void evaluateLiteralExpresssions() {
        Expression exp = parser.parseExpression("'Hello World'");
        String message = (String) exp.getValue();
        System.out.println(message);
        exp = parser.parseExpression("88");
        Integer value = exp.getValue(Integer.class);
        System.out.println(value*2);
    }

2.直接文本上调用方法

示例展示了在字符串上直接调用Java String类的public方法。

java 复制代码
    private void methodInvocationOnLiterals() {
        Expression exp = parser.parseExpression("'Hello World'.concat('!')");
        String message = (String) exp.getValue();
        println(message);
        exp = parser.parseExpression("'Hello World'.length()");
        Integer size = exp.getValue(Integer.class);
        println(size);
        exp = parser.parseExpression("'Hello World'.split(' ')[0]");
        message = (String)exp.getValue();
        println(message);
    }

3、访问对象属性和方法

java 复制代码
	private void accessingObjectProperties() {
        User user = new User("John", "Doe",  true, "john.doe@acme.com",30);
        Expression exp = parser.parseExpression("firstName");
        println((String)exp.getValue(user));
        exp = parser.parseExpression("isAdmin()==false");
        boolean isAdmin = exp.getValue(user, Boolean.class);
        println(isAdmin);
        exp = parser.parseExpression("email.split('@')[0]");
        String emailId = exp.getValue(user, String.class);
        println(emailId);
        exp = parser.parseExpression("age");
        Integer age = exp.getValue(user, Integer.class);
        println(age);
    }

4、Json表达式

java 复制代码
    public static void jsonExpress(){
        JSONObject json = new JSONObject();
        json.put("age",20);
        StandardEvaluationContext conetxt = new StandardEvaluationContext(json);
        SpelExpressionParser parser = new SpelExpressionParser();
        String el="get('age')>10";
        el="['age']>10";
        Expression exp = parser.parseExpression(el);
        Boolean bb=(Boolean)exp.getValue(conetxt);
        System.out.println(bb);
    }
java 复制代码
    public static void rowExpress(){
        Row row = Row.of("name4", 6000, 104.5d);
        StandardEvaluationContext conetxt = new StandardEvaluationContext(row);
        SpelExpressionParser parser = new SpelExpressionParser();
        String el="getField(2)+getField(2)";
        Expression exp = parser.parseExpression(el);
        Object value = exp.getValue(conetxt);
        Double bb=(Double)value;
        System.out.println(bb);
    }

6、调用自定义函数

注册自定义函数,并调用。日期比较代码示例:

java 复制代码
    public static void compareDate(){
        StandardEvaluationContext context = new StandardEvaluationContext(new SpelMethodUtil());
        context.setVariable("dateOne", new Date());
//        context.setVariable("dateTwo", "2022-01-01");
        //SpEL Parser
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression("compareDate(#dateOne, \"2024-01-01\")");
        Object value = exp.getValue(context);
        System.out.println(value);
    }

自定义函数类

java 复制代码
public class SpelMethodUtil {
    public static final String TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT = "yyyy-MM-dd";
    public static final String TIME_FORMAT = "HH:mm:ss";
 
    public static Integer compareDate(Date date, String strDate){
        Integer result;
        if(date==null&& StringUtils.isBlank(strDate)){
            return 0;
        }else{
            if(date==null || StringUtils.isBlank(strDate)){
                return -2;
            }
        }
        String trimDate=strDate.trim();
        String format = findFormat(trimDate);
        Date date2 = stringToDate(trimDate, format);
        result=date.compareTo(date2);
        return result;
    }
    public static Integer compareDate(Date first, Date second){
        if(first==null&& second==null){
            return 0;
        }else{
            if(first==null || second==null){
                return -2;
            }
        }
        return first.compareTo(second);
    }
    public static Date stringToDate(String dateStr,String format){
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date date=null;
        try {
            date= sdf.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
    /**
     * 查找与输入的字符型日期相匹配的format
     * @param strDate
     * @return
     */
    public static String findFormat(String strDate){
        String result=null;
        String trimDate=strDate.trim();
        int len=trimDate.length();
        String dateRegex = "";
        if(len==TIMESTAMP_FORMAT.length()){
            dateRegex = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$";
            if(trimDate.matches(dateRegex)){
                result=TIMESTAMP_FORMAT;
            }
        }else if(len==DATE_FORMAT.length()){
            dateRegex = "^\\d{4}-\\d{2}-\\d{2}$";
            if(trimDate.matches(dateRegex)){
                result=DATE_FORMAT;
            }
        }else if(len==TIME_FORMAT.length()){
            dateRegex = "^\\d{2}:\\d{2}:\\d{2}$";
            if(trimDate.matches(dateRegex)){
                result=TIME_FORMAT;
            }
        }else{
            throw  new RuntimeException("不可识别的日期格式!"+strDate);
        }
        return result;
    }
    public static Integer addAge(Integer age){
        return age+4;
    }
}

七、执行各种操作符(比较、逻辑、算术)

SpEl支持下面几种操作:

关系比较操作:==, !=, <, <=, >, >=

逻辑操作: and, or, not

算术操作: +, -, /, *, %, ^

java 复制代码
    private void operators() {
        User user = new User("John", "Doe", true,"john.doe@acme.com",  30);
        Expression exp = parser.parseExpression("age > 18");
        println(exp.getValue(user,Boolean.class));
        exp = parser.parseExpression("age < 18 and isAdmin()");
        println(exp.getValue(user,Boolean.class));
    }

总结

通过示例介绍了SpEl中多种应用示例。大家可以利用这些功能实现更加灵活的功能应用。

相关推荐
chen<>10 分钟前
Git原理与应用
大数据·git·elasticsearch·svn
焦耳热科技前沿24 分钟前
西华大学Adv. Sci.:超高温焦耳热冲击制备拓扑缺陷碳,用于催化碳纳米管可控生长
大数据·人工智能·能源·材料工程·电池
故乡de云1 小时前
Google Cloud与AWS大数据AI服务对比:2026年企业选型指南
大数据·人工智能·aws
米粒11 小时前
操作系统原理--处理机调度
大数据
数说星榆1811 小时前
在线高清泳道图制作工具 无水印 PC
大数据·人工智能·架构·机器人·流程图
老胡全房源系统2 小时前
2026年1月适合房产经纪人用的房产中介管理系统
大数据·人工智能·房产经纪人培训
杭州龙立智能科技2 小时前
专业的厂内运输车智能化厂家
大数据·人工智能·python
securitypaper3 小时前
2026年最新发布的 安全生产 行业标准 列表 下载
大数据·安全
Light603 小时前
从“报告”到“能力”——构建智能化、可审计的数据治理闭环——领码 SPARK 数据质量平台白皮书
大数据·分布式·spark
TDengine (老段)3 小时前
嘉环科技携手 TDengine,助力某水务公司构建一体化融合平台
大数据·数据库·科技·物联网·时序数据库·tdengine·涛思数据