什么是 yaml

YAML 是 “YAML Ain’t Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML的意思其实是 “Yet Another Markup Language”(仍是一种标记语言)。

yaml 基本语法

  • key: value; kv 之间有空格大小写敏感

  • 使用缩进表示层级关系

  • 缩进不允许使用 tab,只允许空格

  • 缩进的空格数不重要,只要相同层级的元素左对齐即可

  • ‘#‘ 表示注释

  • ”与” 表示字符串内容会被转义/不转义

yaml 数据类型

字面量

单个的,不可再分的值。date、boolean、string、number、null 。

k: v

对象

键值对集合。map、hash、set、object

# 行内写法
k: {k1: v1, k2: v2, k3: v3}
# 或者这样子
k: 
  k1: v1
  k2: v2
  k3: v3

数组

一组按次序排列的值。array、list、queue

# 行内写法
k: [v1, v2, v3]
# 或者这样子
k: 
  - v1
  - v2
  - v3

读取 yaml 的配置文件

和之前读取 properties 配置文件一样,通过 ConfigurationProperties 注解来将配置文件中的配置项加载到配置类中。

两个配置类

以下有两个 java 代码,分别是用户类和宠物类。这是用户类

@ConfigurationProperties(prefix = "person")
@Component
@Data
public class Person {
    private String userName;
    private Boolean boss;
    private Date birth;
    private Integer age;
    private Pet pet;
    private String[] interests;
    private List<String> animal;
    private Map<String, Object> score;
    private Set<Double> salarys;
    private Map<String, List<Pet>> allPets;
}

这是宠物类

@Data
public class Pet {
    private String name;
    private Double weight;
}

对应的 yaml 写法

参照上面的基本语法和数据类型,大致就能够写出来对应的 yaml 配置。

person:
  userName: 小赫赫
  boss: true
  birth: 2019/01/01
  age: 23
  pet:
    name: 柯基
    weight: 30.12
  interests:
    - bilibili
    - acgn
    - running
    - coding
  animal:
    - pig
    - cat
    - dog
    - chicken
    - duck
  score:
    java: 100
    webui: 99
    math: 95
  salarys:
    - 1000.0
    - 999.98
    - 999.99
  allPets:
    cat:
      - name: tomcat
        weight: 30
      - name: xixi
        weight: 10
      - name: heihei
        weight: 20
    dog:
      - name: tomdog
        weight: 30
      - name: xiaoqiang
        weight: 40

遇到的疑问

Q1:为什么 interests 、animal 、salarys 这三个写法都是一样的呢?

interests 对应 java 配置类中的属性 interests ,其类型是 String 数组类型。而 animal 类型对应的是 List 集合类型。这两者其实没什么区别,因为 List 集合底层很有可能是数组(也有可能是以链表的形式),所以我认为是没什么区别的。

而 salary 就有区别了,它是集合类型,集合中的元素是不能重复的。所以我们可以测试测试。

我在 animal 中再添加一个 dog

animal:
  - pig
  - cat
  - dog
  - chicken
  - duck
  - dog

我在 salarys 中再添加一个相同的薪资

salarys:
  - 1000.0
  - 999.98
  - 999.99
  - 999.99

得到的结果如下。可以看出,虽然写法一样,但是展示的效果还是取决于配置类中的数据类型是怎样的。

image-20210706115100847

比如 Map 集合是用 kv 来表示的,其实实体类也是可以用 kv 来表示的。

Q2:为什么用 2019-01-01 会转换异常?

在我测试的时候,需要在实体类上配置 @DateTimeFormat 注解,要我们自己来将日期来格式化。它默认的格式为 yyyy/MM/dd HH:mm:ss

@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birth;

Q3:我听说 yaml 中的字符串类型,字符串两端可以不加单引号或者双引号,也可以加,那我觉得没啥区别呀。是不是没什么用呀?

我觉得有用,而且是非常有用。单引号和双引号的区别可以决定将转义字符将其转义,比如,我们可以测试一下,这里有一个 yaml 的配置文件,比如我们将字符串将其用单引号包裹起来会是怎么样的。

person:
  userName: '小赫赫\n大潮吧'

在控制台输出的运行结果如下,可知,使用单引号之后,字符串转义字符的转义功能失效了,直接将 \n 当成字符串打印了。

小赫赫\n大潮吧

如果我将单引号换成双引号,那么它将出现什么样的情况呢?

person:
  userName: "小赫赫\n大潮吧"

在控制台输出的运行结果如下,可知,使用双引号之后,字符串的转义字符的功能是正常的了,所以就换行了。

小赫赫
大潮吧

那我不加呢?不加就和使用单引号一样。

自定义配置类的提示

如果要让我们的自定义的配置类生效,那么非常简单,只需要引入下面的依赖就好了。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

然后,将项目进行重新运行一下,可以看到这里有我们自定义的配置类的提示。但是请看 person.user-name 这个属性,之前我们写的时候是 person.userName 是这样的。其实提示上的写法也是可以的。因为 yaml 会将大写的字字母给变成为 -小写字母 的形式。

除此之外,这个配置类的提示的依赖,似乎在运行的时候起不到任何所用,只在开发的使用才有用。所以可以这样将这个依赖在打包时排除。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <excludes>
            <exclude>
                <groupId>org.springframework.boot</groupId>
                <artifactId>sprng-boot-configuration- processor</artifactId>
            </exclude>
        </excludes>
        <source>1.8</source>
        <target>1.8</target>
        <encoding>UTF-8</encoding>
    </configuration>
</plugin>

当然,不排除也是可以的。只不过会占用几百 k 的空间大小而已。