Home >Java >javaTutorial >How to use SpringBoot SpringEL expressions

How to use SpringBoot SpringEL expressions

WBOY
WBOYforward
2023-05-15 12:04:061693browse

1. SpringEL-Basic Introduction

What is SpringEL (SpEL)?

  • Spring3 introduced the Spring expression language-SpringEL. SpEL is a powerful and concise way to assemble beans

  • SpringEL can be passed The expression executed during runtime assembles the value into our properties or constructors

  • SpringEL can call the static constants provided in the JDK to obtain the configuration in the external Properties file

Why use SpringEL?

  • Beans that are usually injected through configuration files or Annotaton can actually be called static injection

  • If there is variable A in Bean A, its value needs to be based on the B variable of Bean B. In this scenario, static injection is very powerless for such processing

  • The SpringEL added by Spring3 can fully meet this demand, and can also calculate and assign values ​​to the fields of different Beans. It is very powerful.

How to use SpringEL?

  • You can tell from the name that SpringEL is somewhat related to EL. The use of SpringEL is very similar to the use of EL expressions

  • EL expressions are more convenient to obtain the value in the background in the JSP page, and SpringEL is to more conveniently obtain the value of the Bean in the Spring container

  • EL uses ${}, while SpringEL uses #{}Declare the expression

The main difference between the two

  • $ is to find the parameters of the external configuration and assign the value

  • # is a SpEL expression to find the content of the corresponding variable

  • You can also directly use @value ("constant") to inject without using EL , this way of writing is equivalent to direct assignment

If used in Spring, you can use **@PropertySource("classpath:my.properties")** to load the corresponding configuration file

2. EL Expression-Basic Usage

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

Use EL to inject simple values

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

Inject configuration file attribute values

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

Inject default values

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

Injection list

  • Does not support the array syntax format injection list in the direct configuration file

  • Can identify comma-separated configurations , spring is separated by, by default

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

The complete reference is as follows

Configuration file

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

Attribute configuration class

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<String> listLanguage;
    @Value("${com.codecoord.el.language}")
    private String[] strLanguage;*/
    /**
     * 支持,分隔的注入列表
     */
    @Value("${com.codecoord.el.language02}")
    private List<String> listLanguage02;
    @Value("${com.codecoord.el.language02}")
    private String[] strLanguage02;
}

To the controller Inject the configuration class, and then access the interface test results as follows

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

3. SpringEL-Basic usage

1. Using SpEL to inject simple values ​​is basically the same as using ordinary EL injection
2. SpEl injection map

  • The configuration file needs to be enclosed in double quotes, otherwise the injection will fail. The key is single quotes

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

java class first Use ${spEl.mapInject} to inject a string value. #{} will parse the string value and convert it into map

@Value("#{${spEl.mapInject}}")
private Map<String, String> mapInject;

3. SpEl injects list

  • In addition to In addition to injecting listI through EL, you can also use #{${}.split("separator")} to inject List

  • into the configuration file. For example, use # to separate

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

In the java class, first use ${spEl.listInject} to inject the string value, enclose the content in single quotes, and then use the split method to separate the string
Tips: Avoid empty situations, You can give a default value of an empty string

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

4. Dynamic injection

The above injections are all static injections. SpEl supports injecting information from the Spring container, which is called dynamic injection. Dynamic injection classes are as follows

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<String> product = new ArrayList<String>() {{
        add("huaweiMate30Pro");
        add("xiaomi10x5g");
    }};
    private Map<String, String> productMap = new HashMap<String, String>() {{
        put("huaweiMate30Pro", "5999");
        put("xiaomi10x5g", "4999");
    }};
    private List<City> cityList = new ArrayList<City>() {{
        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 supports and does not support operations

  • Supports dynamic injection instances, similar to automatic object injection

  • SPL does not support direct injection of configuration in the configuration file

  • Supports calling static and instance methods

    • Static method: @Value( "#{T(package.ClassName).ConstFieldName")

  • Supports calling static classes or constants

  • Supports operator operations

  • Support operation collections

  • Support query filtering collections and projections

Inject the complete operation as follows

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<SpElConstant.City> cityList;
    /**
     * 注入人口等于900人口的城市
     */
    @Value("#{spElConstant.cityList.?[population == 900]}")
    private SpElConstant.City city;
    /**
     * 注入人口大于等于1000人口的城市,且只保留城市名称
     */
    @Value("#{spElConstant.cityList.?[population >= 1000].![name]}")
    private List<String> cityName;
}

Injection results

{
 "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 operates external Properties files

<!-- 首先通过applicaContext.xml中<util:properties>增加properties文件 -->
<!-- 注意需要引入Spring的util schemea命名空间和注意id属性,id属性将在SpringEL中使用 -->
<util:properties id="db" location="classpath:application.properties"/>
public class TestSpringEL {
 // 注意db为xml文件中声明的id
 @Value("#{db["jdbc.url"]}")
 private String propertiesValue;
}

SpringEL is just a string when used, which is not easy to debug and test, and there is no IDE to check our Grammar, it is difficult to detect when an error occurs, and it is not recommended to inject complex expressions through SpringEL. It is not recommended to use SpEl's complex injection unless necessary. Clear and readable code is more important and helpful for troubleshooting

4. Automatic attribute injection

The above are all done through specified fields For injection, you can specify the prefix through @ConfigurationProperties for automatic injection

org.springframework.boot.context.properties.ConfigurationProperties

Configuration class

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

Automatic property injection class

  • Specify the front end as user through prefix , and then the type after user. will be injected according to the name

  • Note that the setter method must be provided

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包内的配置类,则可能出现属性没有注入情况,所以可以指定注入

The above is the detailed content of How to use SpringBoot SpringEL expressions. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete