插件主页: https://code.google.com/p/maven-replacer-plugin/
插件介绍:
maven-replacer-plugin:replacer is a build plugin to replace tokens within a file with a given value and fully supports regular expressions.
插件配置和使用示例: https://code.google.com/p/maven-replacer-plugin/wiki/UsageGuide
写这篇文章时的最新版本为:1.5.3
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.3</version>
在pom.xml中添加此插件:
<build>
<plugins>
...
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.3</version>
<executions>
...
</executions>
<configuration>
...
</configuration>
</plugin>
</plugins>
</build>
然后就是增加 executions 和 configuration 配置。
先看executions。在executions里最主要的就是配置 phase 和 goal 了。
phase可以是任意一个phase,典型的有compile, test, package, prepare-resources等等;goal 在replacer插件里只有一个固定的值 replace 。
添加完 executions 后,插件定义看起来如下:
<build>
<plugins>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.3</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
...
</configuration>
</plugin>
</plugins>
</build>
下面定义configuration部分。
根据不同的意图,configuration部分需要不同的定义,下面将一个一个举例。
单个文件输入输出、单个替换
例如有一个文件 a.txt ,里面有内容: This book names {book.name}
想要用真实的内容替换 {book.name},configuration的配置如下:
<configuration>
<file>src/test/resources/a.txt</file>
<outputFile>src/main/resources/a.txt</outputFile>
<regex>false</regex>
<token>{book.name}</token>
<value>Thinkin in Java</value>
</configuration>
参数说明如下:
- file: 指定输入文件
- outputFile: 指定输出文件
- regex: 指定token是否是正则表达式,默认值为true (但是我发现如果不指定regex配置,没有结果,很奇怪,所以必须显式的指定regex)
- token: 要替换的值
- value: 替换后的值
单个文件输入输出、多个替换
有两种方式使用多个替换。
replacements
可以在replacements里列出所有的替换对,例如修改a.txt内容为:This book names {book.name} and author is {author.name}
然后修改configuration如下:
<configuration>
<file>src/test/resources/a.txt</file>
<outputFile>src/main/resources/a.txt</outputFile>
<regex>false</regex>
<replacements>
<replacement>
<token>{author.name}</token>
<value>Bruce Eckel </value>
</replacement>
<replacement>
<token>{book.name}</token>
<value>Thinkin in Java </value>
</replacement>
</replacements>
</configuration>
这里用多个replacement替换了简单的token/value对,每个replacement包含了一个token/value对。
tokenValueMap
也可以使用一个 tokenValueMap 文件来指定所有的替换对,有点像properties文件,例如,同样的上面的例子,可以修改如下:
<configuration>
<file>src/test/resources/a.txt</file>
<outputFile>src/main/resources/a.txt</outputFile>
<regex>false</regex>
<tokenValueMap>src/test/resources/book.conf</tokenValueMap>
</configuration>
其中book.conf文件的内容如下:
{book.name}=Thinkin in Java
{author.name}=Bruce Eckel
比较:相对来说 tokenValueMap 的方式更简洁、灵活;但是我发现用这种方式不能使用系统属性,例如要把值替换成当前工程的版本 ${project.version},只能使用 token/value对的方式。
多个文件输入输出、多个替换
可以使用includes来指定多个输入文件:
<configuration>
<basedir>${basedir}/src/test/resources</basedir>
<includes>
<include>a.txt</include>
<include>b.txt</include>
</includes>
<outputBasedir>${basedir}/src/main/resources</outputBasedir>
<outputDir>.</outputDir>
<regex>false</regex>
<tokenValueMap>src/test/resources/book.conf</tokenValueMap>
</configuration>
- basedir:指定输入文件列表的根目录
- include:指定要替换的文件。(最终文件的路径是 basedir + include)
- outputBasedir:指定输出文件的根目录
- outputDir:指定输出文件目录。(最终文件的路径是 outputBasedir + outputDir + include)
includes里定义多个include,每个include指定一个要替换的文件;outputDir指定输出目录,因为有多个文件,所以不能指定输出文件(要不覆盖了)。
注: 这里basedir 和 outputBasedir 必须被指定,即使在include和outputDir里指定的是一个绝对路径也不行。
输出目录控制
上例中 a.txt 和 b.txt 都是直接放在 src/test/resources 下的,并且转换后生成的a.txt和b.txt也是直接放在输入目录src/main/resources下。修改输入文件的目录结构如下:
src/test/resources
\_ aaa/a.txt
\_ bbb/b.txt
则配置需要修改为:
<configuration>
<basedir>${basedir}/src/test/resources</basedir>
<includes>
<include>aaa/a.txt</include>
<include>bbb/b.txt</include>
</includes>
<outputBasedir>${basedir}/src/main/resources</outputBasedir>
<outputDir>.</outputDir>
<regex>false</regex>
<tokenValueMap>src/test/resources/book.conf</tokenValueMap>
</configuration>
输出目录结构为:
src/main/resources
\_ aaa/a.txt
\_ bbb/b.txt
可以看到输入目录结构被整个复制为输出目录结构。
这里preserveDir参数控制输出行为,默认值为true,即输入目录结构会复制为输出目录结构。如果将它修改为false,则输入文件会直接放到输出目录下而无视目录结构,例如:
<configuration>
<basedir>${basedir}/src/test/resources</basedir>
<includes>
<include>aaa/a.txt</include>
<include>bbb/b.txt</include>
</includes>
<outputBasedir>${basedir}/src/main/resources</outputBasedir>
<outputDir>.</outputDir>
<regex>false</regex>
<preserveDir>false</preserveDir>
<tokenValueMap>src/test/resources/book.conf</tokenValueMap>
</configuration>
则输出目录结构为:
src/main/resources
\_ a.txt
\_ b.txt
模式匹配
上面用includes来指定所有的输入文件;文件量少,则文件名和路径比较固定的时候,这种方式很容易解决问题,但是如果文件量大,并且文件名和目录结构可变的话,这种方式就不灵活。replacer 插件支持模式匹配的方式。例如:
<configuration>
<basedir>${basedir}/src/test/resources</basedir>
<includes>
<include>**/*.txt</include>
</includes>
<outputBasedir>${basedir}/src/main/resources</outputBasedir>
<outputDir>.</outputDir>
<regex>false</regex>
<preserveDir>false</preserveDir>
<tokenValueMap>src/test/resources/book.conf</tokenValueMap>
</configuration>
这里定义include为 **/*.txt,表示在输入文件根目录下的所有目录下的的所有以 .txt 结尾的文件都会被匹配。
排除文件
用上面模式匹配的方式,所有的符合匹配规则的文件都会被处理,然而有的文件可能不想被处理,这里就可以用exclude去定义所有需要过滤的文件。例如想把所有文件名为a.txt的文件过滤:
<configuration>
<basedir>${basedir}/src/test/resources</basedir>
<includes>
<include>**/*.txt</include>
</includes>
<excludes>
<exclude>**/a.txt</exclude>
</excludes>
<outputBasedir>${basedir}/src/main/resources</outputBasedir>
<outputDir>.</outputDir>
<regex>false</regex>
<preserveDir>false</preserveDir>
<tokenValueMap>src/test/resources/book.conf</tokenValueMap>
</configuration>