SpringBoot SpringEL表達(dá)式的使用
一、SpringEL-基礎(chǔ)介紹
什么是SpringEL(SpEL)?
- Spring3中引入了Spring表達(dá)式語言—SpringEL,SpEL是一種強(qiáng)大,簡潔的裝配Bean的方式
- SpringEL可以通過運(yùn)行期間執(zhí)行的表達(dá)式將值裝配到我們的屬性或構(gòu)造函數(shù)當(dāng)中
- SpringEL可以調(diào)用JDK中提供的靜態(tài)常量,獲取外部Properties文件中的的配置
為什么要使用SpringEL?
- 平常通過配置文件或Annotaton注入的Bean,其實(shí)都可以稱為靜態(tài)性注入
- 如Bean A中有變量A,它的值需要根據(jù)Bean B的B變量為參考,在這場景下靜態(tài)注入就對這樣的處理顯得非常無力
- 而Spring3增加的SpringEL就可以完全滿足這種需求,而且還可以對不同Bean的字段進(jìn)行計(jì)算再進(jìn)行賦值,功能非常強(qiáng)大
如何使用SpringEL?
- SpringEL從名字來看就能看出和EL是有點(diǎn)關(guān)系的,SpringEL的使用和EL表達(dá)式的使用非常相似
- EL表達(dá)式在JSP頁面更方便的獲取后臺中的值,而SpringEL就是為了更方便獲取Spring容器中的Bean的值
- EL使用${},而SpringEL使用#{}進(jìn)行表達(dá)式的聲明
兩者主要區(qū)別
- $是去找外部配置的參數(shù),將值賦過來
- #是SpEL表達(dá)式,去尋找對應(yīng)變量的內(nèi)容
- 也可以直接使用@value("常量")注入不使用EL,這樣寫法與直接賦值等價(jià)
如果是在Spring中使用可以使用**@PropertySource("classpath:my.properties")**加載對應(yīng)配置文件
二、EL表達(dá)式-基礎(chǔ)使用
# 配置文件
com:
codecoord:
el:
num: 1001
name: el
language:
- java
- spring
- mysql
- linux
# 逗號分隔可以注入列表
language02: java,spring,mysql,linux
使用EL注入簡單值
/**
* 注入簡單值,直接注入不使用EL,EL不支持直接指定常量
* 直接在EL中指定的常量會當(dāng)做配置處理,和直接賦值等價(jià)
*/
@Value("1432516744")
private Integer no;
注入配置文件屬性值
/**
* 注入整型屬性值
*/
@Value("${com.codecoord.el.num}")
private Integer num;
/**
* 注入字符屬性值
*/
@Value("${com.codecoord.el.name}")
private String name;
注入默認(rèn)值
/**
* 注入字符不存在屬性值并指定默認(rèn)值,默認(rèn)值使用過冒號分隔 :
* 注入常量其實(shí)就可以指定一個(gè)不存在的配置然后使用默認(rèn)值,此處skill的值為java
*/
@Value("${com.codecoord.el.skill:java}")
private String skill;
注入列表
- 不支持直接配置文件中數(shù)組語法格式注入列表
- 可以識別使用逗號,分隔的配置,spring默認(rèn)以,分隔
// 錯(cuò)誤寫法:不支持直接注入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;
完整參考如下
配置文件
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中指定的常量會當(dāng)做配置處理,和直接賦值等價(jià)
*/
@Value("1432516744")
private Integer no;
/**
* 注入整型屬性值
*/
@Value("${com.codecoord.el.num}")
private Integer num;
/**
* 注入字符屬性值
*/
@Value("${com.codecoord.el.name}")
private String name;
/**
* 注入字符不存在屬性值并指定默認(rèn)值,默認(rèn)值使用過冒號分隔 :
* 注入常量其實(shí)就可以指定一個(gè)不存在的配置然后使用默認(rèn)值,此處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;
}
向controller中注入配置類,然后訪問接口測試結(jié)果如下
{
"no": 1432516744,
"num": 1001,
"name": "el",
"skill": "java",
"listLanguage02": [
"java",
"spring",
"mysql",
"linux"
],
"strLanguage02": [
"java",
"spring",
"mysql",
"linux"
]
}
三、SpringEL-基礎(chǔ)使用
1、使用SpEL注入簡單值和普通EL注入使用基本一致
2、SpEl注入map
- 配置文件中需要使用雙引號括起來,否則將會注入失敗,key為單引號
# SpEl
spEl:
mapInject: "{'name': 'SpEl', 'website': 'http://www.codeocord.com'}"
java類中先使用${spEl.mapInject}注入字符串值,#{}會解析字符串的值轉(zhuǎn)為map
@Value("#{${spEl.mapInject}}")
private Map<String, String> mapInject;
3、SpEl注入list
- 除了可以通過EL注入listI外,也可以使用#{${}.split('分隔符')}的方式注入List
- 配置文件中例如使用#分隔
spEl: listInject: "44#11#99#100"
java類中先使用${spEl.listInject}注入字符串值,內(nèi)容使用單引號括起來,然后對字符串使用split方法分隔
提示:避免為空情況,可以給一個(gè)默認(rèn)值空串
@Value("#{'${spEl.listInject:}'.split('#')}")
private List<String> listInject;
4、動(dòng)態(tài)注入
上述注入都是靜態(tài)注入,SpEl支持從Spring容器中注入信息,稱為動(dòng)態(tài)注入。動(dòng)態(tài)注入類如下
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-無參數(shù)";
}
public String showProperty(String name) {
return "showProperty-" + name;
}
@Data
@AllArgsConstructor
static class City {
private String name;
private long population;
}
}
SpEl支持和不支持操作
- 支持動(dòng)態(tài)注入實(shí)例,類似于對象自動(dòng)注入
- SPL不支持直接注入配置文件中的配置
- 支持調(diào)用靜態(tài)和實(shí)例方法
- 靜態(tài)方法:@Value("#{T(package.ClassName).ConstFieldName")
- 支持調(diào)用靜態(tài)類或常量
- 支持運(yùn)算符運(yùn)算
- 支持操作集合
- 支持查詢篩選集合和投影
注入完整操作如下
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;
/**
* 調(diào)用無參方法
*/
@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,將不執(zhí)行右邊方法
*/
@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;
/**
* 對數(shù)字類型進(jìn)行運(yùn)算,spElConstant擁有num屬性
*/
@Value("#{3 * T(java.lang.Math).PI + spElConstant.num}")
private double operation;
/**
* 進(jìn)行邏輯運(yùn)算
*/
@Value("#{spElConstant.num > 100 and spElConstant.num <= 200}")
private boolean logicOperation;
/**
* 進(jìn)行或非邏輯操作
*/
@Value("#{not (spElConstant.num == 100) or spElConstant.num <= 200}")
private boolean logicOperation2;
/**
* 使用三元運(yùn)算符
*/
@Value("#{spElConstant.num > 100 ? spElConstant.num : spElConstant.num + 100}")
private Integer logicOperation3;
/**
* 獲取下標(biāo)為0的元素
*/
@Value("#{spElConstant.product[0]}")
private String str;
/**
* 獲取下標(biāo)為0元素的大寫形式
*/
@Value("#{spElConstant.product[0]?.toUpperCase()}")
private String upperStr;
/**
* 獲取map中key為hello的value
*/
@Value("#{spElConstant.productMap['hello']}")
private String mapValue;
/**
* 根據(jù)product下標(biāo)為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;
}
注入結(jié)果
{
"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-無參數(shù)",
"method2": "showProperty-Hell SpringEL",
"method3": "SHOWPROPERTY-無參數(shù)",
"method4": "SHOWPROPERTY-無參數(shù)",
"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文件
<!-- 首先通過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在使用時(shí)僅僅是一個(gè)字符串,不易于排錯(cuò)與測試,也沒有IDE檢查我們的語法,當(dāng)出現(xiàn)錯(cuò)誤時(shí)較難檢測,復(fù)雜的表達(dá)式不建議通過SpringEL方式注入。在非必要情況下,不推薦使用SpEl的復(fù)雜注入,清晰可讀的代碼更為重要且有利于排查問題
四、屬性自動(dòng)注入
上述都是通過指定字段進(jìn)行注入,可以通過@ConfigurationProperties指定前綴進(jìn)行自動(dòng)注入
org.springframework.boot.context.properties.ConfigurationProperties
配置類
user:
id: ${random.uuid}
name: autowire
address: unknown
website: www.codecoord.com
age: ${random.int}
自動(dòng)屬性注入類
- 通過prefix指定前端為user,然后將會把user.后的類型按照名稱進(jìn)行注入
- 注意必須要提供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再次強(qiáng)制注入,問題出現(xiàn)在如果UserConfig為第三方j(luò)ar包內(nèi)的配置類,則可能出現(xiàn)屬性沒有注入情況,所以可以指定注入
到此這篇關(guān)于SpringBoot SpringEL表達(dá)式的使用的文章就介紹到這了,更多相關(guān)SpringEL表達(dá)式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Trie樹(字典樹)的介紹及Java實(shí)現(xiàn)
Trie樹,又稱字典樹或前綴樹,關(guān)于它的結(jié)構(gòu)就不詳細(xì)介紹了。Trie樹在單詞統(tǒng)計(jì)、前綴匹配等很多方面有很大用處。下面這篇文章主要介紹了Trie樹,以及Java實(shí)現(xiàn)如何Trie樹,有需要的朋友可以參考借鑒,下面來一起看看吧。2017-02-02
Hystrix?Turbine聚合監(jiān)控的實(shí)現(xiàn)詳解
微服務(wù)架構(gòu)下,?個(gè)微服務(wù)往往部署多個(gè)實(shí)例,如果每次只能查看單個(gè)實(shí)例的監(jiān)控,就需要經(jīng)常切換很不?便,在這樣的場景下,我們可以使??Hystrix?Turbine?進(jìn)?聚合監(jiān)控,它可以把相關(guān)微服務(wù)的監(jiān)控?cái)?shù)據(jù)聚合在?起,便于查看2022-09-09
Java中jar包運(yùn)行后顯示:沒有主清單屬性的解決方案
這篇文章主要介紹了Java中jar包運(yùn)行后顯示:沒有主清單屬性的解決方案,文中給大家分析了三個(gè)主要原因,并通過代碼示例和圖文講解的非常詳細(xì),需要的朋友可以參考下2024-04-04
Map按單個(gè)或多個(gè)Value排序當(dāng)Value相同時(shí)按Key排序
Map可以先按照value進(jìn)行排序,然后按照key進(jìn)行排序。 或者先按照key進(jìn)行排序,然后按照value進(jìn)行排序,這樣操作都行,這篇文章主要介紹了Map按單個(gè)或多個(gè)Value排序,當(dāng)Value相同時(shí)按Key排序,需要的朋友可以參考下2023-02-02
Java 獲取本機(jī)的IP與MAC地址實(shí)現(xiàn)詳解
這篇文章主要介紹了Java 獲取本機(jī)的IP與MAC地址實(shí)現(xiàn)詳解的相關(guān)資料,需要的朋友可以參考下2016-09-09

