属性可以认为是声明在 pom 文档中的变量,当某一字段频繁出现在文档中时,将此字段声明为属性值则可以更便捷的编写与修改,属性的设置也能帮助开发者快速了解文档配置
属性常使用的方法是用来声明依赖的版本号,当项目存在大量依赖时,想要更改依赖的版本就不必挨个去找 version 标签了,只需要更改属性值即可
属性需要被声明在 properties 标签中,每一个属性值都要用双标签包裹,标签名即为属性名,如下例:
<properties>
<developer>mzzdeveloper>
<updatetime>2022.08.29updatetime>
<spring.version>5.2.10.RELEASEspring.version>
<mybatis.version>3.5.10mybatis.version>
properties>
当然,属性并不只能用来声明版本号,任何你想设置的属性都可以
使用 ${ },在大括号中包裹属性名即可引用属性值,如下例中的依赖版本号:
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>${spring.version}version>
dependency>
dependencies>
如我们熟知的 spring 相关的各种依赖,常常使用相同的版本,像这样配置以后,要修改版本只需更改 spring.version 的属性值即可,不必再更改各个依赖的 version 标签
每个 pom 文件中只能存在一个 properties 标签,设置属性出错的话记得检查下是不是有两个 properties
新建 maven 项目时,maven 自动生成的 pom.xml 文件中可能已经有了 properties 标签,里面写着文档编码,编译环境之类的信息,可以删去,也可以留着。删去之后,有时 maven 会报一个项目编码未设定的 warning,添加 project.build.sourceEncoding 属性,值为 UTF-8 即可
如下例:
<properties>
<first>${second}first>
<second>${third}second>
<third>3ththird>
properties>
声明属性时,属性值可以引用其他属性,且不在意先后顺序,但不能闭环……
同一属性被多次声明,以最后一次声明为准
<properties>
<username>Bobfirst>
<username>Alicefirst>
properties>
这部分内容是写如何让配置文件能够读取 pom 文件中的属性值,比如数据库连接的用户名和密码,可以作为属性放在 pom 文件中,再由配置文件读取
看到这可能会有些疑惑,这样的属性值直接写在配置文件中不就好了吗,何必多次一举?事实上,这是为了后面的多环境开发做铺垫,因为不同的环境中这些属性的值可能会发生变化,此时来回更改配置文件就显得麻烦了,而我们按照环境分别设置属性值后,配置文件也会在不同环境下读取到对应的属性值,就不必更改配置文件
先来看一下 配置文件和 pom 中的属性值,如下
配置文件:
# ./src/main/resources/jdbc.properties
jdbc.driver=${jdbc.driver}
jdbc.url=${jdbc.url}
jdbc.username=${jdbc.username}
jdbc.password=${jdbc.password}
配置文件中读取属性依然用 ${ } 包裹属性名 (SpringBoot 项目中要用 @属性名@,${ }无效)
pom.xml 中的属性:
<properties>
<jdbc.driver>com.mysql.cj.jdbc.Driverjdbc.driver>
<jdbc.url>jdbc:mysql://127.0.0.1:3306/dbjdbc.url>
<jdbc.username>rootjdbc.username>
<jdbc.password>123456jdbc.password>
properties>
接下来只需要在 pom 文件中配置 resources 属性,就能让 Maven 构建项目时对配置文件进行过滤,将属性替换成对应的值
resources 属性要写在 build 标签内,另外,看到 resources 这个复数形式的单词你就知道了,这里面还有若干个 resource 属性,resource 属性中包含 directory 属性和 filtering 属性,分别表示配置文件所在文件夹的相对路径,和过滤开关(设置为 true)。样例如下:
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<filtering>truefiltering>
resource>
resources>
build>
项目构建之后,在 target/classes/ 目录下可以看到构建之后的资源文件

此时打开文件会发现里面的属性名已经被替换成了属性值
# ./src/main/resources/jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/db
jdbc.username=root
jdbc.password=123456
${project.basedir} 是 Maven 自动设置的内部属性,其值为此项目文件夹,也就是 pom.xml 所在的文件夹,directory 属性中经常以 ${project.basedir} 做前缀,表示在此项目内,如下例:
<build>
<resources>
<resource>
<directory>${project.basedir}/src/main/resourcesdirectory>
<filtering>truefiltering>
resource>
resources>
build>
可以发现,对应相对路径而言,路径中这个 ${project.basedir} 写不写是没有区别的……但写上可读性高一些,与 ${project.basedir} 类似的属性也很多,可以自行了解
父模块中的 resources 属性会被继承给子模块,效果等同于将 resources 内的内容复制了一份给了子模块,而非是父模块中指定父模块内的文件夹,子模块中也指定父模块中的这个文件夹。
比如说父模块 A 中指定${project.basedir}是指项目文件夹 A,而继承给子模块 B 后,就变成了指定项目文件夹 B。
所以 resources 经常放在父模块中且配合 ${project.basedir} 使用,这样就相当于对每个子模块的资源做了处理
此时先提出一个问题,上面所说的 resources 中如果 filtering 的值为 false,那 resources 中的内容就没有作用了吗?或者说 resources 的作用只是为了让配置文件能够读取 pom 中的属性吗?
答案当然不是,事实上 resources 控制了项目中资源文件是否参与构建。不设置 resources 标签时,Maven 构建项目时会默认让 src/main/resources 目录下的所有资源文件参与构建,如果设置了 resources(且 directory 为 src/main/resources),那么效果和不设置 resources 一样……
但这是因为我们还没有了解 includes 和 excludes 两个属性,接下来看一下这两个属性的作用
includes 是 resources 中的属性,它会决定将 directory 文件夹下的哪些资源文件引入并参与构建,如果没有设置 includes 属性,那么 directory 内的所有文件都会被引入
<build>
<resources>
<resource>
<directory>${project.basedir}/src/main/resourcesdirectory>
<includes>
<include>jdbc/include>
<include>*/mybatis-config.*include>
includes>
resource>
resources>
build>
includes 内的 include 表示要引入的文件路径,所有路径均在 directory 下,可以使用通配符,上例中的 * 表示匹配一个字段,效果如下图,引入了 jdbc 文件夹内的所有文件,和任意当前文件夹下的 mybatis-config 开头任意后缀名的文件

excludes 和 includes 类似,只是效果相反,excludes 会将已引入的资源文件中排除指定的文件
<build>
<resources>
<resource>
<directory>${project.basedir}/src/main/resourcesdirectory>
<excludes>
<exclude>jdbc/jdbc2.*exclude>
<exclude>**/*.xmlexclude>
excludes>
resource>
resources>
build>
效果如下图,由于未设置 includes,directory 文件夹内所有文件都被引入,而 excludes 排除了所有 jdbc 下 jdbc 开头任意后缀名文件,以及任意子文件夹下任意前缀的 .xml 文件,** 匹配所有子文件夹及文件,与 * 不同(* 只匹配一个字段,不能匹配子文件夹下的文件)

两个属性同时存在时,效果不变但顺序上,includes 先进行引入,excludes 再进行排除
<build>
<resources>
<resource>
<directory>${project.basedir}/src/main/resourcesdirectory>
<includes>
<include>jdbc/include>
<include>mybatis/include>
includes>
<excludes>
<exclude>*/*2.*exclude>
excludes>
resource>
resources>
build>
如上例中,引入了 jdbc 和 mybatis 两个文件夹下的文件,又排除了任意当前文件夹下前缀以 2 结尾的任意后缀名的文件,效果如下图

此时应该明白了,filtering 属性的只设置为 true,是对参与构建的资源文件进行过滤,而文件是否参与构建,就是由 resources 属性控制着。无论 filtering 的值是什么,resources 都有它自己的作用。