Как перезаписать файлы в файле WAR во время сборки maven?

У меня есть проект 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/resources и src/main/webapp, я обычно использую, когда работаю в MyEclipse. Я могу использовать коннекторы MyEclipse для автоматического обновления развертывания, например, экземпляр Tomcat на моей машине разработчика. Я просто нажимаю «запустить сервер» и могу отлаживать. На самом деле нет необходимости использовать Maven в этом контексте.

Затем, когда я хочу создать выпуск для другой среды, такой как тестирование или производство, я запускаю mvn -P test clean install, и он создает красивую WAR.

Моя цель - заменить файлы конфигурации внутри финальной WAR на файлы из src/config/{environment}/.

Я установил профили в моем 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 от 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 использовать файлы «из активированного профиля» и как-то ПЕРЕЗАПИСАТЬ «натуральные» файлы?


person Pierre Henry    schedule 04.10.2012    source источник


Ответы (6)


Как указано во втором вопросе / ответе пользователя944849, самым простым решением было отфильтровать исходные файлы, чтобы они могли заменить на файлы из папки профиля.

Поэтому я добавил фильтрацию к стандартным ресурсам:

    <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:

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

И раздел webResources моего pom.xml:

<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>
person Pierre Henry    schedule 05.10.2012
comment
Замечательная информация. Искал точное решение и получил его. Большое спасибо. - person Lalit Narayan Mishra; 30.06.2015

Взгляните на любой из этих вопросов / ответов. Кто-то может работать на вас.

Запустить задачу ant на этапе сборки maven перед упаковкой войны?

Файлы были перезаписаны в проекте maven при создании войны

person user944849    schedule 04.10.2012
comment
Q2: На что-то здесь. Я пытался использовать packagingExcludes, но это не сработало. Похоже, warSourceExcludes может помочь. - person Pierre Henry; 04.10.2012

еще одна попытка :)

Я поигрался с параметром наложения. Я думаю, что это заменяет только файлы в папке webapp, которые у вас есть, в другом военном файле внутри папки 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>

The activated profiles will add additional folders to the war file. So that should do the trick!

person wemu    schedule 05.10.2012

Я вижу, что вы будете использовать одни и те же ресурсы, но с разной конфигурацией в каждом профиле (тестовом и производственном).

Итак, я предлагаю вам использовать такую ​​конфигурацию:

<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 и использования переменных для использования правильной конфигурации в каждом профиле.

Надеюсь, это поможет.

person chavocarlos    schedule 14.02.2013

Думаю нужно наложить файлы войны. Либо создайте зависимость в каждом профиле типа war вместо jar, которая будет перекрывать файлы в вашем текущем файле войны.

Другой возможностью может быть конфигурация оверлея для maven-war-plugin.

чтобы профиль активировал файлы, которые вы хотите скопировать, поверх текущих. На сайте плагина есть довольно много документации, а также некоторые Примеры

Надеюсь, что это сработает!

person wemu    schedule 04.10.2012
comment
Но мои пользовательские файлы конфигурации не являются частью внешней WAR, поэтому я не уверен, как я могу применить их в качестве наложения ... не уверен! - person Pierre Henry; 04.10.2012
comment
Я думаю, вам не нужно использовать внешний файл war, если вы используете maven-war-plugin и оверлеи. Параметры id / artifactId / groupId кажутся необязательными, поэтому вам не нужно помещать конфигурацию среды в отдельный модуль. - person wemu; 04.10.2012
comment
похоже, что военный плагин работает на этапе пакета: maven.apache.org/guides/introduction/, в то время как плагин ресурсов запускается раньше в процессах-ресурсах. Я не думаю, что этот способ поможет обмануть плагин войны. - person wemu; 04.10.2012

Вот более простая версия вышеперечисленных решений, основанная только на простом фрагменте, вставленном в pom.xml.

Создайте веб-приложение по умолчанию (локальная рабочая станция) с помощью:

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>

Дополнительная информация и ссылка на рабочий пример.

person mkvalsvik    schedule 14.02.2014