使用Maven复制文件的最佳做法


193

我有一些配置文件和各种文档,我想使用Maven2从开发环境复制到开发服务器目录。奇怪的是,Maven在这项任务上似乎并不强。

一些选项:

  • 在Maven中轻松使用复制任务
<copy file="src/main/resources/config.properties" tofile="${project.server.config}/config.properties"/>
  • 使用Ant插件从Ant 执行复制

    • 与通常为jar类型的POM的“主要”构件一起构造zip类型的构件,然后将该构件从存储库中解压缩到目标目录中。

    • maven-resources插件,如下所述。

    • Maven Assembly插件-但是,当我想简单且“常规地”执行操作时,这似乎需要大量手动定义。

    • 该页面甚至显示了如何构建插件进行复制!

    • maven-upload插件,如下所述。

    • 带有copy的maven-dependency-plugin,如下所述。


所有这些似乎都是多余的:Maven应该擅长执行这些标准任务,而不必大惊小怪。

有什么建议吗?


2
Maven建立在具有阶段性生命周期的概念的基础上,将随机文件复制到远程服务器任务并不完全适合。始终将您的项目视为一个整体。
安德烈(André)

3
“所有这些似乎都是临时性的:Maven应该擅长执行这些标准任务,而不必大惊小怪。”本质上,您正在做的不是标准任务。如果您的工件是战争/耳朵,那么这就像使用cargo插件(cargo.codehaus.org/Maven2+plugin#Maven2plugin-get…)一样简单。您所描述的内容听起来非常特定于您的部署方式,而不是标准的Java应用程序容器部署。Maven并非真正适合于处理实时服务器的部署时间活动-它更适合于构建/开发活动。
whaley

66
@André:我一遍又一遍地听到这个争论,但是很抱歉,那是BS。从整体上考虑项目没有错,但是任何体面的构建系统的一部分都应该具有使我能够以直接的方式完成任务X的功能,例如复制文件,而Maven无法做到这一点。有一个原因为什么最近弹出如此多的项目来包含构建脚本代码范式(例如Gradle,SBT或Buildr)。
Matthias

我建议使用pom.xml来构建构件,并使用另一个pom.xml 来部署给定的构件。
托尔比约恩Ravn的安德森

上面的所有建议似乎仍然不允许我将特定文件从其他项目/工件复制到Maven项目中。我在src / main / folder下的某个文件中有一些文件,该文件变成了jar,我尝试使用dependency-copy maven插件,但是我还没有找到一种方法来说明要复制哪些文件,因此我得到了整个jar文件始终在汇编文件中。这里的所有其他建议,例如资源,似乎都不允许我指定项目而不是项目内部的资源
Alexandre Thenorio 2012年

Answers:


119

不要回避Antrun插件。仅仅因为有些人倾向于认为Ant和Maven是对立的,所以他们不是。如果需要执行一些不可避免的一次性定制,请使用复制任务:

<project>
  [...]
  <build>
    <plugins>
      [...]
      <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <phase>deploy</phase>
            <configuration>
              <tasks>

                <!--
                  Place any Ant task here. You can add anything
                  you can add between <target> and </target> in a
                  build.xml.
                -->

              </tasks>
            </configuration>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

在回答这个问题时,我将重点放在您所问问题的细节上。如何复制文件?这个问题和变量名使我遇到一个更大的问题,例如:“是否有更好的方法来处理服务器配置?” 使用Maven作为生成系统来生成可部署的工件,然后在单独的模块或完全在其他地方执行这些自定义。如果您共享了更多的构建环境,可能会有更好的方法-有一些插件可以配置许多服务器。您可以附加在服务器根目录中解压缩的程序集吗?您正在使用什么服务器?

同样,我确信还有更好的方法。


现在不推荐使用任务描述符吗?
马特

3
@Matt是,task现在已弃用该参数(Antrun插件)。您应该target改用(从1.5开始)。不幸的是,有一些例子混淆了这一点。例如,target参数version<1.5。
cuh 2011年

这怎么可能是公认的答案?肯定应该有一个变更请求,使Maven使复制变得简单。
Wolfgang Fahl,2017年

137
<build>
    <plugins>
        ...
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.3</version>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include> **/*.properties</include>
            </includes>
        </resource>
    </resources>
    ...
</build>

谢谢@Peter,这很有用。现在,我使用资源插件复制资源目标而不是antrun。后者的定义实际上更简单直观,但是我无法通过它(版本1.3)将所有Maven自定义属性(在<properties>部分中定义)传递给antrun,因此我切换到资源插件。
Cornel Masson'3

2
我以前以为这是正确的答案……直到我意识到资源插件没有跳过配置。Antrun是必经之路。
Mike Post

创建跳过配置文件应该不难。还没有使用过antrun,所以我不能说哪个更容易/更好
Vivek Chavda '18

40

为了复制文件,请使用:

        <plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
                <execution>
                    <id>copy-resource-one</id>
                    <phase>install</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>

                    <configuration>
                        <outputDirectory>${basedir}/destination-folder</outputDirectory>
                        <resources>
                            <resource>
                                <directory>/source-folder</directory>
                                <includes>
                                    <include>file.jar</include>
                                </includes>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
           </executions>
        </plugin>

为了使用子文件夹复制文件夹,请使用以下配置:

           <configuration>
              <outputDirectory>${basedir}/target-folder</outputDirectory>
              <resources>          
                <resource>
                  <directory>/source-folder</directory>
                  <filtering>true</filtering>
                </resource>
              </resources>              
            </configuration>  

Maven中的过滤是指字符串插值,因此我想<filtering>避免对使用${...}变量的脚本文件进行不必要的更改。
GeroldBroser恢复Monica

20

Maven依赖插件节省了我很多时间来处理蚂蚁任务:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>install-jar</id>
            <phase>install</phase>
            <goals>
                <goal>copy</goal>
            </goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>...</groupId>
                        <artifactId>...</artifactId>
                        <version>...</version>
                    </artifactItem>
                </artifactItems>
                <outputDirectory>...</outputDirectory>
                <stripVersion>true</stripVersion>
            </configuration>
        </execution>
    </executions>
</plugin>

依赖性:副本是documentend,并具备解压更有用的目标。


3
我已经好几年没有使用Ant了,也不想因为这么简单的事情而开始使用它。因此,感谢您的回答。
古斯塔夫

17

对于简单的复制任务,我建议使用copy-rename-maven-plugin。简单明了,易于使用:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>com.coderplus.maven.plugins</groupId>
        <artifactId>copy-rename-maven-plugin</artifactId>
        <version>1.0</version>
        <executions>
          <execution>
            <id>copy-file</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>copy</goal>
            </goals>
            <configuration>
              <sourceFile>src/someDirectory/test.environment.properties</sourceFile>
              <destinationFile>target/someDir/environment.properties</destinationFile>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

如果您要复制多个文件,请<sourceFile>...</destinationFile>

<fileSets>
  <fileSet>
    <sourceFile>src/someDirectory/test.environment.properties</sourceFile>
    <destinationFile>target/someDir/environment.properties</destinationFile>
  </fileSet>
  <fileSet>
    <sourceFile>src/someDirectory/test.logback.xml</sourceFile>
    <destinationFile>target/someDir/logback.xml</destinationFile>
  </fileSet>                
</fileSets>

此外,如果需要,您可以在多个阶段中指定多个执行,第二个目标是“重命名”,它只是按照说的做,而其余配置保持不变。有关更多用法示例,请参阅“ 用法”页面

注意:此插件只能复制文件,不能复制目录。(感谢@ james.garriss找到了此限制。)


1
虽然我喜欢这个插件,但令人惊讶的是它不能复制目录。
james.garriss

2
@ james.garriss我不知道此限制,但是很遗憾,您是对的。我将其编辑为答案,以节省一些人自己寻找的时间。
morten.c

7

上面的ant解决方案最容易配置,但是我使用Atlassian的maven-upload-plugin很幸运。我找不到好的文档,这是我的用法:

<build>
  <plugin>
    <groupId>com.atlassian.maven.plugins</groupId>
    <artifactId>maven-upload-plugin</artifactId>
    <version>1.1</version>
    <configuration>
       <resourceSrc>
             ${project.build.directory}/${project.build.finalName}.${project.packaging}
       </resourceSrc>
       <resourceDest>${jboss.deployDir}</resourceDest>
       <serverId>${jboss.host}</serverId>
       <url>${jboss.deployUrl}</url>
     </configuration>
  </plugin>
</build>

上面引用的变量“ $ {jboss.host}”在我的〜/ .m2 / settings.xml中定义,并使用maven配置文件激活。这个解决方案并不局限于JBoss,这就是我命名的变量。我有一个关于开发,测试和实时发布的资料。因此,要将我的耳朵上传到测试环境中的jboss实例中,我将执行:

mvn upload:upload -P test

这是来自settings.xml的摘录:

<server>
  <id>localhost</id>
  <username>username</username>
  <password>{Pz+6YRsDJ8dUJD7XE8=} an encrypted password. Supported since maven 2.1</password>
</server>
...
<profiles>
  <profile>
    <id>dev</id>
    <properties>
      <jboss.host>localhost</jboss.host> 
      <jboss.deployDir>/opt/jboss/server/default/deploy/</jboss.deployDir>
      <jboss.deployUrl>scp://root@localhost</jboss.deployUrl>
    </properties>
  </profile>
  <profile>
    <id>test</id>
    <properties>
       <jboss.host>testserver</jboss.host>
       ...

注意:带有此插件的Atlassian Maven存储库位于:https : //maven.atlassian.com/public/

我建议下载源代码并查看其中的文档以查看插件提供的所有功能。

`


5

好吧,Maven不能很好地完成精细的任务,它不是像bash或ant这样的脚本语言,它是声明性的-您说-我需要打仗,也需要耳朵,您就明白了。但是,如果您需要自定义战争或耳朵在内部的外观,则会遇到问题。它只是不像蚂蚁那样的程序性的,而是声明性的。一开始它有一些优点,到最后可能有很多缺点。

我想最初的概念是拥有不错的插件,“可以正常工作”,但是如果您做非标准的事情,现实就不一样了。

但是,如果您在pom上投入了足够的精力,并且很少使用自定义插件,那么您将获得一个比ant更好的构建环境(当然,这取决于您的项目,但是对于更大的项目,它会变得越来越真实)。



4

复制任意文件的通用方法是利用Maven Wagon传输抽象。它可以处理不同的目的地通过协议,如fileHTTPFTPSCPWebDAV

有一些插件可提供通过使用来复制文件的功能Wagon。最值得注意的是:

  • 开箱即用的Maven Deploy插件

    deploy-file目标。它非常不灵活,但是可以完成工作:

    mvn deploy:deploy-file -Dfile=/path/to/your/file.ext -DgroupId=foo 
    -DartifactId=bar -Dversion=1.0 -Durl=<url> -DgeneratePom=false

    使用的主要缺点Maven Deploy Plugin是它被指定为与Maven存储库一起使用。它假定特定的结构和元数据。您可以看到该文件位于下面,foo/bar/1.0/file-1.0.ext并创建了校验和文件。这没有办法。

  • Wagon Maven插件

    使用upload-single目标

    mvn org.codehaus.mojo:wagon-maven-plugin:upload-single
    -Dwagon.fromFile=/path/to/your/file.ext -Dwagon.url=<url>

    Wagon Maven Plugin用于复制的用法很简单,而且似乎用途最广。


在以上示例中,<url>可以是任何受支持的协议。请参阅现有的Wagon提供商列表。例如

  • 在本地复制文件: file:///copy/to
  • 将文件复制到正在运行的远程主机SSHscp://host:22/copy/to


上面的示例在命令行中传递插件参数。另外,也可以直接在中配置插件POM。然后调用将像mvn deploy:deploy-file@configured-execution-id。也可以将其绑定到特定的构建阶段。


请注意,为使协议SCP能够正常工作,您需要在中定义扩展名POM

<build>
  [...]
  <extensions>
    <extension>
      <groupId>org.apache.maven.wagon</groupId>
      <artifactId>wagon-ssh</artifactId>
      <version>2.12</version>
    </extension>
  </extensions>


如果要复制到的目标位置需要身份验证,则可以通过Server设置提供凭据。repositoryId/ serverId传递给插件必须与设置中定义的服务器匹配。


3

我只能假设您的$ {project.server.config}属性是自定义定义的,并且不在标准目录布局之内。

如果是这样,那么我将使用复制任务。


假设我小心地将文件放入标准目录布局中。Maven可以按原样而不是zip / jar将其复制到目标吗?
约书亚·福克斯

2

另一种方法是使用Assembly插件将这些东西捆绑到工件中。然后,您可以使用依赖插件在所需的位置解压缩这些文件。依赖插件中也有复制目标以复制工件。


1

我为这个答案整理了许多不同的资料:

...
<repository>
    <id>atlassian</id>
    <name>Atlassian Repo</name>
    <url>https://maven.atlassian.com/content/repositories/atlassian-public</url>
</repository>
...
<dependency>
    <groupId>com.atlassian.maven.plugins</groupId>
    <artifactId>maven-upload-plugin</artifactId>
    <version>1.1</version>
</dependency>
...
<plugin>
    <groupId>com.atlassian.maven.plugins</groupId>
    <artifactId>maven-upload-plugin</artifactId>
    <version>1.1</version>
    <configuration>
        <serverId>jira-repo</serverId>
        <resourceSrc>
            ${project.build.directory}/${project.build.finalName}.${project.packaging}
        </resourceSrc>
        <resourceDest>opt/jira/webapps</resourceDest> <!-- note: no leading slash -->
        <url>scp://root@jira</url>
    </configuration>
</plugin>
...

来自~/.m2/settings.xml

...
<servers>
  <server>
    <id>jira-repo</id>
    <username>myusername</username>
    <password>mypassword</password>
  </server>
</servers>
...

然后运行命令:(-X用于调试)

mvn -X upload:upload


-1

总结一下上面的一些很好的答案:Maven旨在构建模块并将结果复制到Maven存储库。将模块复制到Deployment / installer-input目录的任何操作都必须在Maven核心功能的上下文之外进行,例如使用Ant / Maven copy命令。


Ant属于Maven的核心功能,Wagon也是如此(尽管它周围的插件不是Maven的官方核心插件)。
GeroldBroser
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.