当前位置:

首页 > 编程开发 > SpringBoot SpringEL表达式怎么使用

SpringBoot SpringEL表达式怎么使用

一、SpringEL-基础介绍什么是SpringEL(SpEL)?Spring3中引入了Spring表达式语言―SpringEL,SpEL是一种强大,简洁的装配Bean的方式SpringEL可以通过运行期间执行的表达式将值装配到我们的属性或构造函数当中SpringEL可以调用JDK中提供的静态常量,获取外部Properties文件中的的配置为什么要使用SpringEL?平常通过配置文件或Annotaton注入的Bean,其实都可以称为静态性注入如BeanA中有变量A,它的值需要根据BeanB的B变量为参考

本文目录

    一、SpringEL-基础介绍

    什么是SpringEL(SpEL)?

    • Spring3中引入了Spring表达式语言―SpringEL,SpEL是一种强大,简洁的装配Bean的方式

    • SpringEL可以通过运行期间执行的表达式将值装配到我们的属性或构造函数当中

    • SpringEL可以调用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使用#{}进行表达式的声明

    两者主要区别

    • $是去找外部配置的参数,将值赋过来

    • #是SpEL表达式,去寻找对应变量的内容

    • 也可以直接使用@value("常量")注入不使用EL,这样写法与直接赋值等价

    如果是在Spring中使用可以使用**@PropertySource("classpath:my.properties")**加载对应配置文件

    二、EL表达式-基础使用

    # 配置文件
    com:
      codecoord:
        el:
          num: 1001
          name: el
          language:
            - java
            - spring
            - mysql
            - linux
          # 逗号分隔可以注入列表
          language02: java,spring,mysql,linux

    使用EL注入简单值

    /**
     * 注入简单值,直接注入不使用EL,EL不支持直接指定常量
     * 直接在EL中指定的常量会当做配置处理,和直接赋值等价
     */
    @Value("1432516744")
    private Integer no;

    注入配置文件属性值

    /**
     * 注入整型属性值
     */
    @Value("${com.codecoord.el.num}")
    private Integer num;
    /**
     * 注入字符属性值
     */
    @Value("${com.codecoord.el.name}")
    private String name;

    注入默认值

    /**
     * 注入字符不存在属性值并指定默认值,默认值使用过冒号分隔 :
     * 注入常量其实就可以指定一个不存在的配置然后使用默认值,此处skill的值为java
     */
    @Value("${com.codecoord.el.skill:java}")
    private String skill;

    注入列表

    • 不支持直接配置文件中数组语法格式注入列表

    • 可以识别使用逗号,分隔的配置,spring默认以,分隔

    // 错误写法:不支持直接注入yml列表格式语法列表
    @Value("${com.codecoord.el.language}")
    private List listLanguage;
    @Value("${com.codecoord.el.language}")
    private String[] strLanguage;
    /**
     * 支持,分隔的注入列表
     */
    @Value("${com.codecoord.el.language02}")
    private List listLanguage02;
    @Value("${com.codecoord.el.language02}")
    private String[] strLanguage02;

    完整参考如下

    配置文件

    server:
      port: 8888
    com:
      codecoord:
        el:
          num: 1001
          name: el
          language:
            - java
            - spring
            - mysql
            - linux
          # 逗号分隔可以注入列表
          language02: java,spring,mysql,linux

    属性配置类

    import lombok.Data;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    @Data
    @Component
    public class ElConfig {
        /**
         * 注入简单值,直接注入不使用EL,EL不支持直接指定常量
         * 直接在EL中指定的常量会当做配置处理,和直接赋值等价
         */
        @Value("1432516744")
        private Integer no;
        /**
         * 注入整型属性值
         */
        @Value("${com.codecoord.el.num}")
        private Integer num;
        /**
         * 注入字符属性值
         */
        @Value("${com.codecoord.el.name}")
        private String name;
        /**
         * 注入字符不存在属性值并指定默认值,默认值使用过冒号分隔 :
         * 注入常量其实就可以指定一个不存在的配置然后使用默认值,此处skill的值为java
         */
        @Value("${com.codecoord.el.skill:java}")
        private String skill;
        /// 不支持直接注入列表
        /*@Value("${com.codecoord.el.language}")
        private List listLanguage;
        @Value("${com.codecoord.el.language}")
        private String[] strLanguage;*/
        /**
         * 支持,分隔的注入列表
         */
        @Value("${com.codecoord.el.language02}")
        private List listLanguage02;
        @Value("${com.codecoord.el.language02}")
        private String[] strLanguage02;
    }

    向controller中注入配置类,然后访问接口测试结果如下

    {
     "no": 1432516744,
     "num": 1001,
     "name": "el",
     "skill": "java",
     "listLanguage02": [
      "java",
      "spring",
      "mysql",
      "linux"
     ],
     "strLanguage02": [
      "java",
      "spring",
      "mysql",
      "linux"
     ]
    }

    三、SpringEL-基础使用

    1、使用SpEL注入简单值和普通EL注入使用基本一致
    2、SpEl注入map

    • 配置文件中需要使用双引号括起来,否则将会注入失败,key为单引号

    # SpEl
    spEl:
      mapInject: "{"name": "SpEl", "website": "http://www.codeocord.com"}"

    java类中先使用${spEl.mapInject}注入字符串值,#{}会解析字符串的值转为map

    @Value("#{${spEl.mapInject}}")
    private Map mapInject;

    3、SpEl注入list

    • 除了可以通过EL注入listI外,也可以使用#{${}.split("分隔符")}的方式注入List

    • 配置文件中例如使用#分隔

    spEl:
      listInject: "44#11#99#100"

    java类中先使用${spEl.listInject}注入字符串值,内容使用单引号括起来,然后对字符串使用split方法分隔
    提示:避免为空情况,可以给一个默认值空串

    @Value("#{"${spEl.listInject:}".split("#")}")
     private List listInject;

    4、动态注入

    上述注入都是静态注入,SpEl支持从Spring容器中注入信息,称为动态注入。动态注入类如下 

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @Component
    @Data
    public class SpElConstant {
        private String name = "SpElConstant-name";
        private String nickname = "tianxin";
        private int num = 100;
        private List product = new ArrayList() {{
            add("huaweiMate30Pro");
            add("xiaomi10x5g");
        }};
        private Map productMap = new HashMap() {{
            put("huaweiMate30Pro", "5999");
            put("xiaomi10x5g", "4999");
        }};
        private List cityList = new ArrayList() {{
            add(new City("深圳", 1000L));
            add(new City("杭州", 2000L));
            add(new City("贵阳", 900L));
        }};
    
        public String showProperty() {
            return "showProperty-无参数";
        }
    
        public String showProperty(String name) {
            return "showProperty-" + name;
        }
    
        @Data
        @AllArgsConstructor
        static class City {
            private String name;
            private long population;
        }
    }

    SpEl支持和不支持操作

    • 支持动态注入实例,类似于对象自动注入

    • SPL不支持直接注入配置文件中的配置

    • 支持调用静态和实例方法

      • 静态方法:@Value("#{T(package.ClassName).ConstFieldName")

    • 支持调用静态类或常量

    • 支持运算符运算

    • 支持操作集合

    • 支持查询筛选集合和投影

    注入完整操作如下

    import lombok.Data;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    import java.util.Map;
    
    @Data
    @Component
    public class SpElConfig {
        /// 不支持直接注入配置文件值
        /*@Value("#{com.codecoord.el.num}")
        private Integer num;*/
        /**
         * 对象注入
         */
        @Value("#{spElConstant}")
        private SpElConstant spElConstant;
        /**
         * 注入ID为spElConstant Bean中的STR常量/变量
         */
        @Value("#{spElConstant.name}")
        private String name;
        /**
         * 调用无参方法
         */
        @Value("#{spElConstant.showProperty()}")
        private String method1;
        /**
         * 有参接收字符串的方法
         */
        @Value("#{spElConstant.showProperty("Hell SpringEL")}")
        private String method2;
        /**
         * 方法返回的String为大写
         */
        @Value("#{spElConstant.showProperty().toUpperCase()}")
        private String method3;
        /**
         * 若使用method3这种方式,若果showProperty返回为null
         * 将会抛出NullPointerException,可以使用以下方式避免
         * 使用?.符号代表若然左边的值为null,将不执行右边方法
         */
        @Value("#{spElConstant.showProperty()?.toUpperCase()}")
        private String method4;
        /**
         * 注入math常量
         */
        @Value("#{T(java.lang.Math).PI}")
        private double pi;
        /**
         * 用random方法获取返回值
         */
        @Value("#{T(java.lang.Math).random()}")
        private double random;
        /**
         * 获取文件路径符号
         */
        @Value("#{T(java.io.File).separator}")
        private String separator;
        /**
         * 拼接字符串
         */
        @Value("#{spElConstant.nickname + " " + spElConstant.name}")
        private String concatString;
        /**
         * 对数字类型进行运算,spElConstant拥有num属性
         */
        @Value("#{3 * T(java.lang.Math).PI + spElConstant.num}")
        private double operation;
        /**
         * 进行逻辑运算
         */
        @Value("#{spElConstant.num > 100 and spElConstant.num <= 200}")
        private boolean logicOperation;
        /**
         * 进行或非逻辑操作
         */
        @Value("#{not (spElConstant.num == 100) or spElConstant.num <= 200}")
        private boolean logicOperation2;
        /**
         * 使用三元运算符
         */
        @Value("#{spElConstant.num > 100 ? spElConstant.num : spElConstant.num + 100}")
        private Integer logicOperation3;
        /**
         * 获取下标为0的元素
         */
        @Value("#{spElConstant.product[0]}")
        private String str;
        /**
         * 获取下标为0元素的大写形式
         */
        @Value("#{spElConstant.product[0]?.toUpperCase()}")
        private String upperStr;
        /**
         * 获取map中key为hello的value
         */
        @Value("#{spElConstant.productMap["hello"]}")
        private String mapValue;
        /**
         * 根据product下标为0元素作为key获取testMap的value
         */
        @Value("#{spElConstant.productMap[spElConstant.product[0]]}")
        private String mapStrByproduct;
        /**
         * 注入人口大于等于1000人口的城市
         */
        @Value("#{spElConstant.cityList.?[population >= 1000]}")
        private List cityList;
        /**
         * 注入人口等于900人口的城市
         */
        @Value("#{spElConstant.cityList.?[population == 900]}")
        private SpElConstant.City city;
        /**
         * 注入人口大于等于1000人口的城市,且只保留城市名称
         */
        @Value("#{spElConstant.cityList.?[population >= 1000].![name]}")
        private List cityName;
    }

    注入结果

    {
     "spElConstant": {
      "name": "SpElConstant-name",
      "nickname": "tianxin",
      "num": 100,
      "product": [
       "huaweiMate30Pro",
       "xiaomi10x5g"
      ],
      "productMap": {
       "xiaomi10x5g": "4999",
       "huaweiMate30Pro": "5999"
      },
      "cityList": [
       {
        "name": "深圳",
        "population": 1000
       },
       {
        "name": "杭州",
        "population": 2000
       },
       {
        "name": "贵阳",
        "population": 900
       }
      ]
     },
     "name": "SpElConstant-name",
     "method1": "showProperty-无参数",
     "method2": "showProperty-Hell SpringEL",
     "method3": "SHOWPROPERTY-无参数",
     "method4": "SHOWPROPERTY-无参数",
     "pi": 3.141592653589793,
     "random": 0.19997238292235787,
     "separator": "",
     "concatString": "tianxin SpElConstant-name",
     "operation": 109.42477796076938,
     "logicOperation": false,
     "logicOperation2": true,
     "logicOperation3": 200,
     "str": "huaweiMate30Pro",
     "upperStr": "HUAWEIMATE30PRO",
     "mapValue": null,
     "mapStrByproduct": "5999",
     "cityList": [
      {
       "name": "深圳",
       "population": 1000
      },
      {
       "name": "杭州",
       "population": 2000
      }
     ],
     "city": {
      "name": "贵阳",
      "population": 900
     },
     "cityName": [
      "深圳",
      "杭州"
     ]
    }

    Spring操作外部Properties文件

    
    
    
    public class TestSpringEL {
     // 注意db为xml文件中声明的id
     @Value("#{db["jdbc.url"]}")
     private String propertiesValue;
    }

    SpringEL在使用时仅仅是一个字符串,不易于排错与测试,也没有IDE检查我们的语法,当出现错误时较难检测,复杂的表达式不建议通过SpringEL方式注入。在非必要情况下,不推荐使用SpEl的复杂注入,清晰可读的代码更为重要且有利于排查问题

    四、属性自动注入

    上述都是通过指定字段进行注入,可以通过@ConfigurationProperties指定前缀进行自动注入

    org.springframework.boot.context.properties.ConfigurationProperties

    配置类

    user:
      id: ${random.uuid}
      name: autowire
      address: unknown
      website: www.codecoord.com
      age: ${random.int}

    自动属性注入类

    • 通过prefix指定前端为user,然后将会把user.后的类型按照名称进行注入

    • 注意必须要提供setter方法

    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    @Component
    @ConfigurationProperties(prefix = "user")
    @Data
    public class UserConfig {
        private String id;
        private String name;
        private String address;
        private String website;
        private Integer age;
    }

    可以通过@EnableConfigurationProperties(value = UserConfig.class)将UserConfig再次强制注入,问题出现在如果UserConfig为第三方jar包内的配置类,则可能出现属性没有注入情况,所以可以指定注入

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    springBoot项目常用目录有哪些
    springBoot项目常用目录有哪些

    springBoot项目常用目录springBoot项目的目录结构及名规范介绍基于SpringBoot开发时的目录结构及命名规范,通过介绍能够为你解决,在实际项目中如何规划目录结构?如何命名目录更规范?各个目录分别代表什么含义?等三个问题。目录说明servicex//项目名|-admin-ui//管理服务前端代码(一般将UI和SERVICE放到一个工程中,便于管理)|-servicex-auth//模块1|-servicex-common//模块2|-servicex-gateway//模块3|-serv

    解析SpringBoot和SpringMVC之间的异同
    解析SpringBoot和SpringMVC之间的异同

    解析SpringBoot和SpringMVC之间的异同SpringBoot和SpringMVC是Java领域中非常重要的开发框架。虽然它们都属于Spring框架的一部分,但是在使用和功能上有一些明显的区别。本文将对SpringBoot和SpringMVC进行比较,解析它们之间的异同。首先,让我们来了解一下SpringBoot。SpringBo

    探索SpringCloud和SpringBoot在微服务领域的不同应用方式
    探索SpringCloud和SpringBoot在微服务领域的不同应用方式

    近年来,随着云计算和分布式架构的兴起,微服务架构的应用越来越广泛。而SpringCloud和SpringBoot作为Java开发中的两个重要框架,对于微服务的实现起到了重要的作用。然而,很多人对于它们在微服务领域的不同应用方式还存在一定的疑惑。本文将从不同的角度探索SpringCloud和SpringBoot在微服务中的应用方式。首先,我们来了解一下Spri

    SpringBoot和SpringMVC有何区别?
    SpringBoot和SpringMVC有何区别?

    SpringBoot与SpringMVC的不同之处在哪里?SpringBoot和SpringMVC是两个非常流行的Java开发框架,用于构建Web应用程序。尽管它们经常分别被使用,但它们之间的不同之处也是很明显的。首先,SpringBoot可以被看作是一个Spring框架的扩展或者增强版。它旨在简化Spring应用程序的初始化和配置过程,以帮助开发人

    比较SpringBoot和SpringMVC的异同
    比较SpringBoot和SpringMVC的异同

    SpringBoot和SpringMVC都是Java开发中常用的框架,但它们之间有一些明显的差异。本文将探究这两个框架的特点和用途,并对它们的差异进行比较。首先,我们来了解一下SpringBoot。SpringBoot是由Pivotal团队开发的,它旨在简化基于Spring框架的应用程序的创建和部署。它提供了一种快速、轻量级的方式来构建独立的、可执行

    SpringBoot与SpringMVC的不同点是什么?
    SpringBoot与SpringMVC的不同点是什么?

    SpringBoot和SpringMVC是Java开发中常用的两个框架,它们都是由Spring框架所提供的,但在功能和使用方式上有着一些区别。本文将分别介绍SpringBoot和SpringMVC的特点和区别。一、SpringBoot的特点:简化配置:SpringBoot通过约定优于配置的原则,大大简化了项目的配置过程。它可以自动配置项目所需要的参数,开发人

    比较和选择指南:SpringCloud与SpringBoot的功能比较
    比较和选择指南:SpringCloud与SpringBoot的功能比较

    SpringCloud和SpringBoot是目前Java领域中最热门的开源框架,它们分别提供了一套完善的微服务架构和快速构建应用程序的解决方案。本文将对它们的功能进行比较,并给出选择指南,以帮助读者了解它们的优势和适用场景。SpringBoot是一个用于开发Java应用程序的框架,它提供了一个简化的开发流程,集成了大量常用的功能和组件,减少了开发者的工作量

    SpringCloud与SpringBoot:分析它们之间的相似与不同
    SpringCloud与SpringBoot:分析它们之间的相似与不同

    深入剖析SpringCloud和SpringBoot的异同引言:在构建企业级应用程序时,Spring框架已经成为开发者们的首选。它提供了一种简单而强大的方式来构建独立于平台的应用程序。Spring框架由两个核心模块组成:SpringBoot和SpringCloud。虽然它们都可以帮助开发者快速搭建应用程序,但它们的目标和用途存在一些差异。本文将深入剖析Spr

    从架构角度看SpringCloud与SpringBoot的差异
    从架构角度看SpringCloud与SpringBoot的差异

    从架构角度看SpringCloud与SpringBoot的差异引言:在当今的互联网时代,构建分布式系统已经成为了一种必要的需求。而SpringBoot和SpringCloud正是为了满足这个需求而诞生的。尽管它们都是由Spring框架所提供的解决方案,但从架构角度来看,它们存在着一些重要的差异。本文将从架构的角度出发,对SpringBoot和SpringCl

    Java API 开发中使用 SpringBoot 的利弊分析
    Java API 开发中使用 SpringBoot 的利弊分析

    JavaAPI开发中使用SpringBoot的利弊分析随着互联网的快速发展和技术的不断更新迭代,Java技术在开发中的广泛应用引起了人们的重视。而SpringBoot作为一种微服务架构的解决方案,已经逐渐成为Java开发中的热门选择。那么,在JavaAPI开发中使用SpringBoot,到底有哪些利弊呢?下面来分析一下。利:简化开发

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。