我们自动构建的SpringBoot初始项目,使用的配置文件是 application.properties ;但其实官方更推荐我们使用yaml,需要注意配置文件名必须是application.yaml,否则会无法读取(通过前面的学习,读者应该明白,这边之所以规定了读取的文件名,是在自动配置的相关规范中定义的默认值)。
1.配置文件语法格式对比
application.properties语法结构: key = value
server.port=8080
application.yaml语法结构: key:(空格)value
server:
port: 8080
以前的时候,还使用过xml配置:
<server>
<port>8080<port>
</server>
2.yaml语法入门
A.yaml语法规范
1)大小写敏感
2)使用空格缩进表示层级所属关系
3)缩进只能用空格,不允许tab(类比py,py只能选择4个空格或者1个tab,不允许混用)
4)属于同一个层级的元素要求必须左对齐
a:
bc:
d:
#表示 a.bc.d
a:
bc:
d:
#表示 a.bc 和 a.d
5)用#表示注释
B.用yaml赋值
yaml的强大之处在于,可以直接为我们的实体类赋值。yaml支持的数据类型:键值对、数组、普通变量:
1.记住由于我们使用yaml配置文件,因此别忘了在pom.xml配置编译时包含
<resource>
<directory>src/main/resources</directory>
<includes>
<!--记住一定要配置SpringBoot主配置文件的过滤-->
<include>**/*.yaml</include>
<include>**/*.properties</include>
<include>**/*.txt</include>
<include>**/*.xml</include>
</includes>
</resource>
2.Spring建议我们使用yaml注入值时,增加依赖以便提示是否有错
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
引入该依赖后,重启ideal,就会发现我们在用配置文件设置属性时,只要绑定了prefix,就会有提示:
[注]:这只是SpringBoot提供了便利性功能,与业务无关,因此打包的时候最好不要包含它,避免打包出的jar包内多出了一些不影响运行的jar包:
<build>
<plugins>
<!--SpringBoot打包-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</build>
3.构建实体类进行实验
dogbean: &dogbean
name: 小白 #单个不可再分的值:date、boolean、string、null(用~表示)、number等
age: 4 #
personbean:
name: zzt
age: 22
happy: true
birth: 1999/4/14
maps: {k1: v1,k2: v2} #键值对集合 map、set、hash、对象
list: #数组 array、list、queue
- code
- music
#多维数组简单值
mulArr:
-
- zzt
- zjm
-
- zjm
- zzt
#数组复杂对象
dogs:
-
name: 小白
age: 4
-
name: 小黑
age: 5
#值引用
dog:
<<: *dogbean
Dog.java
package com.zzt.vo;
public class Student {
private Integer id;
private String name;
private Integer age;
public Student() {
}
public Student(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
Person.java
@Component
@ConfigurationProperties(prefix = "personbean")
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> list;
private String[][] mulArr;
private Dog[] dogs;
private Dog dog;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getList() {
return list;
}
public void setList(List<Object> list) {
this.list = list;
}
public Dog[] getDogs() {
return dogs;
}
public void setDogs(Dog[] dogs) {
this.dogs = dogs;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String[][] getMulArr() {
return mulArr;
}
public void setMulArr(String[][] mulArr) {
this.mulArr = mulArr;
}
@Override
public String toString() {
System.out.println("多维数组");
for (String[] strings : mulArr) {
for (String string : strings) {
System.out.println(string);
}
}
System.out.println("数组符合对象");
for (Dog dog1 : dogs) {
System.out.println(dog1);
}
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", maps=" + maps +
", list=" + list +
", dog=" + dog +
'}';
}
}
[注]:1.yaml是没有办法像spring配置文件那样做对象引用 -- ref 的,只能做值引用。
2.@ConfigurationProperties(prefix = "personbean")用于指明从yaml文件中的哪个对象获取值。
3.yaml可用~表示赋值null。
4.yaml支持松散绑定,last-name属性等价于lastName。(-符号后紧跟的字母大写)
5.yaml自动根据字段名匹配赋值,而properties需要配合@Value用SPEL取值后赋值。
6.一般来说,我们如果确定只要其中一个或几个值而不是全部,会选择用properties+@Value,但是大多数情况下还是会选择yaml。
7.yaml中可以封装对象(复杂类型),而properties最多支持一个数组,@Value没有办法注入复杂类型。
8.yaml支持JSR-303数据校验,可以在字段增加一层过滤器验证,保证数据的合法性。
4.构建测试
@SpringBootTest
class DemoApplicationTests {
@Autowired
private Person person;
@Autowired
private Dog dog;
@Test
void contextLoads() {
System.out.println(person);
System.out.println(dog);
System.out.println(person.getDog()==dog);
}
}
5.执行结果
3.yaml vs propertie
对比一下使用properties赋值:
A.@PropertySource导入properties、使用SPEL配合@Value手动取值并赋值
这中方式可以将实体类赋值与主配置文件解耦,更清晰,但是比较难以使用。
dog_name=小白
dog_age=4
person_name=zzt
person_age=22
happy=true
birth=1999/4/14
list=code,music
@Component
@PropertySource(value = "classpath:bean.properties")
public class Person {
@Value("${person_name}")
private String name;
@Value("${person_age}")
private Integer age;
@Value("${happy}")
private Boolean happy;
@Value("${birth}")
private Date birth;
// 没有办法用properties赋值
private Map<String,Object> maps;
@Value("${list}")
private List<Object> list;
// 没有办法用properties(正确)赋值
private String[][] mulArr;
// 没有办法用properties赋值
private Dog[] dogs;
// 没有办法用properties赋值
private Dog dog;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getList() {
return list;
}
public void setList(List<Object> list) {
this.list = list;
}
public Dog[] getDogs() {
return dogs;
}
public void setDogs(Dog[] dogs) {
this.dogs = dogs;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String[][] getMulArr() {
return mulArr;
}
public void setMulArr(String[][] mulArr) {
this.mulArr = mulArr;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", maps=" + maps +
", list=" + list +
", dog=" + dog +
'}';
}
}
B.@ConfigurationProperties在主配置的properties指定所属对象,并使用prefix指定对象
application.properties
person.name=zjm
person.age=23
person.happy=true
person.birth=1998/5/23
person.list=wwz,zyf,zzt
person.dog.name=小黑
person.dog.age=4
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> list;
private String[][] mulArr;
private Dog[] dogs;
private Dog dog;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getList() {
return list;
}
public void setList(List<Object> list) {
this.list = list;
}
public Dog[] getDogs() {
return dogs;
}
public void setDogs(Dog[] dogs) {
this.dogs = dogs;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String[][] getMulArr() {
return mulArr;
}
public void setMulArr(String[][] mulArr) {
this.mulArr = mulArr;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", maps=" + maps +
", list=" + list +
", dog=" + dog +
'}';
}
}
[注]:1.如果一定要使用properties,需要设置文件编码为UTF-8。
执行结果:
2.当同时存在application.properties和application.yaml,如果在两个配置文件中配置了相同的属性,以properties为准,不重复的配置全部采取(SpringBoot先读取properties)。
3.对于字符串类型的值,我们加不加' '和" "都一样,但如果一定要使用,他们之间还是有差距的:单引号具有转义功能,而双引号不具有转义功能
@Component
@ConfigurationProperties(prefix = "personbean")
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> list;
private String[][] mulArr;
private Dog[] dogs;
private Dog dog;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getList() {
return list;
}
public void setList(List<Object> list) {
this.list = list;
}
public Dog[] getDogs() {
return dogs;
}
public void setDogs(Dog[] dogs) {
this.dogs = dogs;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String[][] getMulArr() {
return mulArr;
}
public void setMulArr(String[][] mulArr) {
this.mulArr = mulArr;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", maps=" + maps +
", list=" + list +
", dog=" + dog +
'}';
}
}
personbean:
name: "zzt \n zjm"
双引号会将原本的转义字符按照转义的含义进行输出。
personbean:
name: 'zzt \n zjm'
单引号做的操作实际上是,为我们的转义字符\前面加上一个\,也就是单引号实际上的内容是zzt \\n zjm。
4.JSR-303校验(转载:https://www.jianshu.com/p/554533f88370)
JSR-303用于判断数据的合法性,若数据不合法,则不会进行注入。
A.导入依赖
<!--JSR-303校验-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
B.启动校验 @Validated
@Component
@ConfigurationProperties(prefix = "dogbean")
@Validated
public class Dog {
@Email(message = "邮件地址不合法!")
private String name;
private Integer age;
public Dog() {
}
public Dog(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
C.执行结果
5.SpringBoot多环境切换
在实际开发中,我们会采用多环境的方式,做到开发和测试分离。
A.properties切换环境
使用 spring.profiles.active 选择要使用的环境:
.
没有激活其他环境时,使用的是application.properties中的环境
使用spring.profiles.active可以激活其他环境,配置文件名为 application-环境名.properties。
B.yaml切换环境
yaml多环境是不需要编写多个文件分别激活的,没有配置spring.config.activate.on-profile的环境就是默认环境。