1. 程式人生 > >spring boot 配置檔案properties,yml語法學習及屬性獲取@ConfigurationProperties和@Value

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?
  1. Spring 表示式語言(簡稱SpEL):是一個支援執行時查詢和操作物件圖的強大的表示式語言。

  2. 語法類似於 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是不支援的,這是非常重要的一點。*