如何在maven构建期间覆盖WAR文件中的文件?

时间:2012-10-04 14:28:06

标签: eclipse maven myeclipse maven-war-plugin maven-profiles

我有一个Java webapp项目,我在Eclipse中开发(更准确地说是MyEclipse 10)并使用Maven 3构建。

我有以下布局(仅包括与我的问题相关的文件:

project root
|-- src
|   |-- main
|   |   |-- java
|   |   |-- resources
|   |   |   |-- log4j.xml
|   |   |   +-- struts.properties
|   |   |-- webapp
|   |   |   |-- META-INF
|   |   |   |   +--context.xml
|   |   |-- config
|   |   |   |-- test
|   |   |   |   |--log4j.xml
|   |   |   |   |--struts.properties
|   |   |   |   +--context.xml
|   |   |   +-- prod
|   |   |   |   |--log4j.xml
|   |   |   |   |--struts.properties
|   |   |   |   +--context.xml
|   +--test
+--pom.xml

如您所见,我包含了许多配置文件。在项目结构中处于适当位置的人,即src/main/resourcessrc/main/webapp内部,是我在MyEclipse工作时经常使用的那个。我可以使用MyEclipse连接器自动将部署更新到例如我的开发机器上的Tomcat实例。我只需点击“运行服务器”即可调试。实际上,在这种情况下根本不需要使用Maven。

然后,当我想为测试或生产等其他环境构建版本时,我运行mvn -P test clean install并构建一个很好的WAR。

我的目标是用src/config/{environment}/中的那些替换最终WAR中的配置文件。

我在pom.xml

中设置了个人资料
<profiles>
    <profile>
        <id>test</id>
        <properties>
            <environment>test</environment>
        </properties>
    </profile>

    <profile>
        <id>prod</id>
        <properties>
            <environment>prod</environment>
        </properties>
    </profile>
</profiles>

然后,我尝试将这些资源从指定的配置文件(使用environment变量)复制到WAR内部的正确位置(或将压缩到WAR中的临时文件夹):

<webResources>
    <resource>
        <directory>/src/main/config/${environment}</directory>
        <targetPath>META-INF/</targetPath>
        <includes>
            <include>context.xml</include>
        </includes>
    </resource>
    <resource>
        <directory>src/main/config/${environment}</directory>
        <targetPath>WEB-INF/classes/</targetPath>
        <includes>
            <include>
                struts.properties
            </include>
            <include>
                log4j.xml
            </include>
        </includes>
    </resource>
</webResources>

现在这似乎有效,除了“标准”资源被复制到此后的目录,因此它们会覆盖这些文件。所以我总是最终得到来自log4j.xml的{​​{1}}而不是来自src/main/resources

src/main/configuration/prod/

从Maven输出中提取:

[INFO] Processing war project
[INFO] Copying webapp webResources [D:\workspace\MyProject/src/main/config/prod] to [D:\workspaces\SITEL\Webfauna\target\Webfauna]
[INFO] Copying webapp webResources [D:\workspace\MyProject\src/main/config/prod] to [D:\workspaces\SITEL\Webfauna\target\Webfauna]
[INFO] Copying webapp resources [D:\workspace\MyProject\src\main\webapp]

正如您在最后一行所看到的那样,来自src/main/webapp的内容会在以后复制,从而覆盖我的自定义文件:(

我的问题:如何强制Maven使用“来自激活的配置文件”的文件并以某种方式覆盖“自然”文件?

6 个答案:

答案 0 :(得分:12)

正如第二个{​​{3}}所指出的,最简单的解决方案是过滤掉原始文件,以便它们可以被配置文件文件夹中的文件替换。

所以我添加了对标准资源的过滤:

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <excludes>
                <!-- Exclude those since they are copied from the profile folder for the build -->
                <exclude>log4j.xml</exclude>
                <exclude>struts.properties</exclude>
            </excludes>
            <filtering>false</filtering>
        </resource>
    </resources>

以及网络资源:

<warSourceExcludes>**/context.xml</warSourceExcludes>

所以现在3个文件没有复制到WAR文件夹中。在下一步(webResources)中,它们将从活动配置文件的文件夹中复制。

我还添加了一个默认文件夹,其中包含具有常用值的3个文件。此默认文件夹中的文件也会被复制,但只能在配置文件的文件夹之后复制。由于资源未被覆盖,因此只有在资源尚不存在时才会复制它们。如果您在未激活配置文件的情况下构建,或者您可以定义合理的默认值,则此选项非常有用,如果文件相同,则每个配置文件都不需要复制该文件。

配置文件夹的结构:

-- config
   |-- test
   |   |--log4j.xml
   |   |   |--struts.properties
   |   |   +--context.xml
   |   +-- prod
   |   |   |--log4j.xml
   |   |   +--context.xml
   |   +-- default
   |       |--log4j.xml
   |       |--struts.properties
   |       +--context.xml
...

我的pom.xml的webResources部分:

<webResources>
    <!-- Resources from the activated profile folder -->
    <resource>
        <directory>/src/main/config/${environment}</directory>
        <targetPath>META-INF/</targetPath>
        <includes>
            <include>context.xml</include>
        </includes>
    </resource>
    <resource>
        <directory>src/main/config/${environment}</directory>
        <targetPath>WEB-INF/classes/</targetPath>
        <includes>
            <include>
                struts.properties
            </include>
            <include>
                log4j.xml
            </include>
        </includes>
    </resource>
    <!-- Default resources in case some file was not defined in the profile folder -->
    <!-- Files are not overwritten so default files will be copied only if it does not exist already -->
    <resource>
        <directory>/src/main/config/default</directory>
        <targetPath>META-INF/</targetPath>
        <includes>
            <include>context.xml</include>
        </includes>
    </resource>
    <resource>
        <directory>src/main/config/default</directory>
        <targetPath>WEB-INF/classes/</targetPath>
        <includes>
            <include>
                struts.properties
            </include>
            <include>
                log4j.xml
            </include>
        </includes>
    </resource> 
</webResources>

答案 1 :(得分:1)

我认为您需要覆盖战争文件。在war类型的每个配置文件中创建一个依赖项而不是jar,它将覆盖当前war文件中的文件。

另一种可能性可能是maven-war-plugin的overlay configuration

因此配置文件将激活您想要通过当前文件复制的文件。插件网站上还有quite some documentation以及一些示例

希望有效!

答案 2 :(得分:1)

答案 3 :(得分:1)

另一次尝试:)

我玩过覆盖参数。我认为只替换webapp文件夹中的另一个war文件中的webapp文件夹中的文件。所以这对你的设置来说不是完美的。

然而,上面提到的webResource参数可以做到这一点:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.mimacom.maven.examples</groupId>
<artifactId>mimacom-war-overlays</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>${project.artifactId}</name>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.build.compiler.version>1.6</project.build.compiler.version>
    <junit.version>4.9</junit.version>
</properties>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>${project.build.compiler.version}</source>
                    <target>${project.build.compiler.version}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.3</version>
        </plugin>
    </plugins>
</build>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
    </dependency>
</dependencies>

<profiles>
    <profile>
        <id>prod</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.3</version>
                    <configuration>
                        <webResources>
                            <resource>
                                <directory>src/main/config/prod</directory>
                            </resource>
                        </webResources>
                        <!--<includes>-->
                            <!--<include>${basedir}/environments/overlay-1/css/styles.css</include>-->
                        <!--</includes>-->
                        <!--<overlays>-->
                            <!--<overlay>-->
                                <!--<includes>-->
                                    <!--../environments/overlay-1/css/**-->
                                <!--</includes>-->
                            <!--</overlay>-->
                        <!--</overlays>-->
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
    <profile>
        <id>test</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.3</version>
                    <configuration>
                        <webResources>
                            <resource>
                                <directory>src/main/config/test</directory>
                            </resource>
                        </webResources>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>

</profiles>

激活的配置文件会将其他文件夹添加到war文件中。所以应该这样做!

答案 4 :(得分:1)

我看到你会使用相同的资源,但在每个配置文件中使用不同的配置(测试和产品)。

所以,我建议你使用这样的配置:

<profiles>
<profile>
    <id>test</id>
    <activation>
        <activeByDefault>true</activeByDefault>
        <property>
            <name>env</name>
            <name>test</name>
        </property>
    </activation>
    <build>
        <filters>
            <filter>test.properties</filter>
        </filters>
    </build>
</profile>

<profile>
    <id>prod</id>
    <activation>
        <property>
            <name>env</name>
            <value>prod</value>
        </property>
    </activation>
    <build>
        <filters>
            <filter>prod.properties</filter>
        </filters>
    </build>
</profile>
</profiles>

在这种情况下,我有两个配置文件,每个配置文件都使用“env”参数激活。 每个配置文件都有一个文件来过滤您的资源,将您的log4j.xml,struts.properties,context.xml文件放在src / main / resources中,并使用变量在每个配置文件中使用正确的配置。

希望有所帮助。

答案 5 :(得分:0)

以上是上述解决方案的简单版本,仅依赖于插入pom.xml的简单代码段。

使用以下命令构建默认(本地工作站)webapp:

mvn war:exploded

添加环境命令行参数,将文件从特定于环境的目录(如resources-prod)复制到目标WEB-INF / classes目录:

mvn war:exploded -Denvironment=prod

在pom.xml的项目元素中添加:

<!-- this profile will allow files in environment-specific folders like resources-prod or resources-test
     to be added to the resulting war's classpath under WEB-INF/classes
     to activate the profile, simply add '-Denvironment=prod' to your maven build command 
     this also works fine with war:inplace and war:exploded 
-->
<profile>
    <id>environment-specific</id>
    <activation>
        <property>
            <name>environment</name>
        </property>
    </activation>
    <build>
    <plugins>   
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.4</version>
        <configuration>
            <webResources>
                <!-- note the order of the following resource elements are important. 
                     if there are duplicate files, the first file copied will win
                -->
                <resource>
                    <!-- this is relative to the pom.xml directory -->                        
                    <directory>resources-${environment}</directory>
                    <!-- override default destination at root of war -->
                    <targetPath>WEB-INF/classes</targetPath>
                </resource>
                <resource>
                    <directory>src/main/resources</directory>
                    <targetPath>WEB-INF/classes</targetPath>
                </resource>
            </webResources>
        </configuration>
      </plugin>             
    </plugins>
    </build>
</profile>

更多信息和link to working example