spring boot 配置文件properties,yml语法学习及属性获取@ConfigurationProperties和@Value

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/yu0_zhang0/article/details/83745056

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._%+-]+@[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是不支持的,这是非常重要的一点。*

猜你喜欢

转载自blog.csdn.net/yu0_zhang0/article/details/83745056