spring boot 配置檔案properties,yml語法學習及屬性獲取@ConfigurationProperties和@Value
1 概述
SpringBoot使用一個全域性的配置檔案,配置檔名是固定的;當我們建立一個專案時會在resource目錄下出現一個預設的配置檔案application.properties
我們可以在裡面進行一些引數的配置,當然還有另外一種方式yml檔案application.yml
(YAML Ain’t Markup Language),他們之間寫法不同,作用都是一樣的,下面我們就來進行學習,可以根據自己的愛好進行選擇。
配置檔案的作用:修改SpringBoot自動配置的預設值;SpringBoot在底層都給我們自動配置好;
我們寫一個簡單的例子看看它們之間的區別:配置埠號
- application.properties
server.port=8081
- application.yaml
server:
port: 8081
那如果是以前的xml呢?
<server>
<port>8081</port>
</server>
以前的配置檔案;大多都使用的是 xxxx.xml檔案;而YAML:以資料為中心,比json、xml等更適合做配置檔案;但是剛開始使用的時候一定要注意語法問題,一不小心少個空格就會報錯哈。
2 YML語法
1、基本語法
k:(空格)v:表示一對鍵值對 (空格必須有)
以空格的縮排來控制層級關係;只要是左對齊的一列資料,都是同一個層級的,空格可以是一個或者多個,但是同一層級一定要對齊。
server:
port: 8081
path: /hello
屬性和值也是大小寫敏感;
2、值的寫法
字面量:普通的值(數字,字串,布林)
k: v:字面直接來寫;
字串預設不用加上單引號或者雙引號;
-
“”:雙引號;不會轉義字串裡面的特殊字元;特殊字元會作為本身想表示的意思
name: “zhangsan \n lisi”:輸出;zhangsan 換行 lisi -
‘’:單引號;會轉義特殊字元,特殊字元最終只是一個普通的字串資料
name: ‘zhangsan \n lisi’:輸出;zhangsan \n lisi
物件、Map(屬性和值)(鍵值對):
k: v:在下一行來寫物件的屬性和值的關係;注意縮排
物件還是k: v的方式
friends:
name: zhangsan
age: 20
行內寫法:
friends: {name: zhangsan,age: 18}
陣列(List、Set):
用- 值表示陣列中的一個元素
pets:
- cat
- dog
- pig
行內寫法
pets: [cat,dog,pig]
3 通過配置檔案注入屬性 @ConfigurationProperties
- person實體類
package cn.zhangyu.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
* 將配置檔案中配置的每一個屬性的值,對映到這個元件中
* @ConfigurationProperties:告訴SpringBoot將本類中的所有屬性和配置檔案中相關的配置進行繫結;
* prefix = "person":配置檔案中哪個下面的所有屬性進行一一對映
*
* 只有這個元件是容器中的元件,才能容器提供的@ConfigurationProperties功能;
* 所以配置@Component註解
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
//人的屬性
private String name;
private int age;
private String sex;
//map
private Map<String , Object> maps;
//list
private List<Dog> list;
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Dog> getList() {
return list;
}
public void setList(List<Dog> list) {
this.list = list;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", maps=" + maps +
", list=" + list +
", dog=" + dog +
'}';
}
}
- Dog實體類
package cn.zhangyu.bean;
public class Dog {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- yml配置屬性
person:
name: zhangsan
age: 20
sex: male
maps: {k1: v1,k2: v2}
list:
- {name: 小黑, age: 22}
- name: 小白
- age: 33
dog:
name: 大黃
age: 12
- 下面通過test類進行測試結果
package cn.zhangyu;
import cn.zhangyu.bean.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot1ApplicationTests {
@Autowired
private Person person;
@Test
public void contextLoads() {
System.out.println(person);
}
}
結果 :
Person{name='zhangsan', age=20, sex='male', maps={k1=v1, k2=v2}, list=[Dog{name='小黑', age=22}, Dog{name='小白', age=0}, Dog{name='null', age=33}], dog=Dog{name='大黃', age=12}}
其中list中放入的是dog類,我們看看結果是什麼樣的:list張放入了三隻狗,dog中如果有多個屬性就要用{ }括起來。
- properties配置檔案
person.name=小明
person.age=20
person.sex=male
person.maps.k1=v1
person.maps.k2=v2
person.list[0].name=小顧
person.list[0].age=22
person.list[1].name=旺財
person.list[1].age=10
person.dog.name=旺旺
person.dog.age=30
- 結果:
Person{name='小明', age=20, sex='male', maps={k1=v1, k2=v2}, list=[Dog{name='小顧', age=22}, Dog{name='旺財', age=10}], dog=Dog{name='旺旺', age=30}}
注意: 這裡大家可能出現亂碼問題因為properties配置檔案在idea中預設utf-8可能會亂碼,但是我們idea的預設設定是gbk,所以要進行修改,如下圖所示:
3 @Value 屬性注入
我們寫個簡單的controller進行測試@Value屬性,@Value屬性可以說增加了屬性注入的靈活性可以單個屬性進行配置。
- HelloController
package cn.zhangyu.bean.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Value("${person.name}")
//@Value("#{person.name}")
private String name;
//計算表示式
@Value("#{11*2}")
private int age;
//引入一個物件
@Value("#{person}")
private Person person;
@RequestMapping(method = RequestMethod.GET ,path = "/sayHello")
public String sayHello(){
return "hello "+ name+" 我的年齡是: "+age+"\n" + person;
}
}
- yml中加一個name屬性
person.name: 小雨
- 看看結果
訪問頁面http://localhost:8081/sayHello
我這裡埠號配置的是8081
結果:hello 小明 我的年齡是: 22
這裡@Value註解是支援SpEL的。
什麼是SpEL?
-
Spring 表示式語言(簡稱SpEL):是一個支援執行時查詢和操作物件圖的強大的表示式語言。
-
語法類似於 EL:SpEL 使用 #{…} 作為定界符 , 所有在大括號中的字元都將被認為是 SpEL , SpEL 為 bean 的屬性進行動態賦值提供了便利。
通過 SpEL 可以實現:
通過 bean 的 id 對 bean 進行引用。
呼叫方式以及引用物件中的屬性。
計算表示式的值
正則表示式的匹配。
1SpEL 實現:
整數:#{8}
小數:#{8.8}
科學計數法:#{1e4}
String:可以使用單引號或者雙引號作為字串的定界符號。
Boolean:#{true}
SpEL引用bean , 屬性和方法:
引用其他物件:#{car}
引用其他物件的屬性:#{car.brand}
呼叫其它方法 , 還可以鏈式操作:#{car.toString()}
呼叫靜態方法靜態屬性:#{T(java.lang.Math).PI}
SpEL支援的運算子號:
算術運算子:+,-,*,/,%,^(加號還可以用作字串連線)
比較運算子:< , > , == , >= , <= , lt , gt , eg , le , ge
邏輯運算子:and , or , not , |
if-else 運算子(類似三目運算子):?:(temary), ?:(Elvis)
正則表示式:#{admin.email matches '[a-zA-Z0-9._%+-][email protected][a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}'}
4 @Value獲取值和@ConfigurationProperties獲取值比較
註解 | @ConfigurationProperties | @Value |
---|---|---|
功能 | 批量注入配置檔案中的屬性 | 一個個指定 |
鬆散繫結(鬆散語法) | 支援 | 不支援 |
SpEL | 不支援 | 支援 |
JSR303資料校驗 | 支援 | 不支援 |
複雜型別封裝 | 支援 | 不支援 |
鬆散繫結 :如果使用@ConfigurationProperties註解一個類其中一個屬性為
private String myName;
我們通過yml進行配置如果我寫成這樣是否可以呢?
person:
my-name: zhangsan
答案是可以的,這就是鬆散繫結 ,我可以寫成my-name
也可以myName
@ConfigurationProperties支援而@Vlaue不支援
JSR303資料校驗:
通過一個例子來看看什麼是JSR303資料校驗
- 我們在person類中加入:
@Validated
和@Email
兩個註解
package cn.zhangyu.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.Email;
import java.util.List;
import java.util.Map;
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
//人的屬性
@Email
private String myName;
private int age;
private String sex;
//map
private Map<String , Object> maps;
//list
private List<Dog> list;
private Dog dog;
public String getMyName() {
return myName;
}
public void setMyName(String myName) {
this.myName = myName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Dog> getList() {
return list;
}
public void setList(List<Dog> list) {
this.list = list;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"myName='" + myName + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", maps=" + maps +
", list=" + list +
", dog=" + dog +
'}';
}
}
啟動後發現報錯:
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'person' to cn.zhangyu.bean.Person failed:
Property: person.myName
Value: zhangsan
Origin: class path resource [application.yml]:6:12
Reason: 不是一個合法的電子郵件地址
這也就是JSR303資料校驗。填寫正確的電子郵件。而@Vlaue是不支援的。
複雜型別:
我們上面知道了@ConfigurationProperties是支援複雜型別的list、map等。 現在我們測試@Value是否支援
@Value("${person.maps}")
private Map<String , Object> maps;
把person中map屬性加上@Value註解啟動發現報錯;
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'person.maps' in value "${person.maps}"
.
所以@ConfigurationProperties是支援複雜型別的list、map等而@Value是不支援的,這是非常重要的一點。*