让 Maven2 将资源复制到构建目录,但不将它们捆绑在 JAR 中

Posted

技术标签:

【中文标题】让 Maven2 将资源复制到构建目录,但不将它们捆绑在 JAR 中【英文标题】:Having Maven2 copy resources to the build directory, but NOT bundle them in the JAR 【发布时间】:2011-04-30 10:10:17 【问题描述】:

我在 NetBeans 中启动了一个新的 Maven 项目,接受所有默认值。删除了所有 JAR 依赖项的 POM 被剪切并粘贴在此问题的底部。

应用程序读取各种属性文件(例如日志记录和配置)。它还读取外部资源,例如字体、图像和声音。我不希望将所有这些资源捆绑到 JAR 文件中。相反,我计划将它们部署在部署 JAR 的目录下的子目录中。

项目目录结构的简化视图如下所示:

-src
   |---main
           |---java
                   |---com.mypackage, etc
           |---resources
                        |---conf
                        |---fonts
                        |---images
                        |---sounds
+target

希望在一个干净的构建之后拥有如下所示:

+src
-target
       |---myproject-1.0.0.jar (compiled contents of "src/main/java" ONLY)
       |---conf
       |---fonts
       |---images
       |---sounds

但是,当我通过 NetBeans(或与此相关的命令行)执行“清理并构建”或“执行”时...我实际上得到的外观像这样:

+src
-target
       |---classes
                  |---("src/main/java" and "src/main/resources" slammed together)
       |---myproject-1.0.0.jar (the "classes" subdirectory JAR'ed up)

有人能指出我获得第一个结果而不是第二个结果的正确方向吗?如果这是一个愚蠢的问题(我是 Maven 菜鸟),或者我忽略了之前提出的重复问题,我深表歉意。但是,从我在 Stack Overflow 上进行的搜索...看起来所有重复的问题都试图以 other 的方式进行! (即将资源放入 JAR,而不是将它们取出

pom.xml:

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>steveperkins</groupId>
    <artifactId>myproject</artifactId>
    <packaging>jar</packaging>
    <version>1.0.0</version>
    <name>My Project</name>
    <url>http://maven.apache.org</url>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.4</source>
                    <target>1.4</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
    ...

【问题讨论】:

【参考方案1】:

虽然建议的解决方案可以工作,但它们基本上可以解决 maven 约定。更好的选择是过滤掉资源,这样它们就不会包含在 jar 中,但在 IDE 中工作时仍可作为资源使用。在 pom 中它应该是这样的:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <configuration>
                        <excludes>
                            <exclude>/conf/**</exclude>
                            <exclude>/fonts/**</exclude>
                            <exclude>/images/**</exclude>
                            <exclude>/sounds/**</exclude>
                        </excludes>
                    </configuration>
                </execution>
            </executions>
        </plugin>
   </plugins>
</build>

这将有效地将它们从 jar 中排除,而无需任何解决方法。

Here 是 jar 插件的文档页面。

虽然以上内容将回答您的问题,但我可能会建议一些其他可能对您的工作有所帮助的可能性。第二步,要使这些资源仍然可用,您可以使用 assembly 插件打包您的项目。这将允许您创建一个 zip 文件并将所有文件、资源和 jar 放在适当的位置,以便在解压缩 zip 时一切都到位。

如果这个项目是一个更大的工作的一部分,您仍然可以为每个遇到这种情况的地方使用组装插件,并且在主项目中,您可以将它们提取并重新组装在一个更大的 zip 中,包括所有必要的工件。

最后我建议您将目录结构保留在目标下。如果您自定义它,最好通过 Maven 变量来完成,以便更改渗透到其他插件。如果您在 Maven 完成后手动删除和重命名内容,您以后可能会遇到问题。通常,如果您按照您想要的方式配置它,Maven jar 插件应该能够正确处理它,因此您无需担心目标下的内容。我个人使用 Eclipse,而 pusign 非常擅长同步 IDE 和 Maven 配置。对于 NetBeans,我怀疑情况也是如此。如果不是最好的方法是在 NetBeans 中配置您的项目,以使用 target/classes 作为构建工件的目标文件夹,并使用 target/test-classes 作为从 src/test/java 构建的东西。

【讨论】:

这不会给出 OP 的要求(即目标目录根目录中的 conf、字体等),至少在没有更多努力的情况下不会。 这是我的意思,他根本不需要更改他的根文件夹。绕过假定的 Maven 约定是通往黑暗的道路。只要你玩得好,Maven 就很棒。如果你尝试改变它周围的世界,它会在许多意想不到的地方打破 这就是为什么我建议使用 another 位置而不是 src/main/resources 来实现 OP 所要求的而不破坏 anything 我最喜欢这种方法,因为它与 NetBeans 用于从 IDE 中运行应用程序的“exec”目标配合得很好。我真的不在乎除了厨房水槽之外的所有东西是否在构建过程中都被复制到“目标/类”中......只要我最终将 JAR 文件之外的非 Java 资源作为最终交付物。正确构建 JAR 后,我可以使用汇编程序将所有内容打包。 但是,我必须注意,上面的这个 pom 示例并不适合我所写的。我最终将该 元素提升了两个级别,成为 元素的直接子元素......然后完全消除了 元素。那时工作得很好。【参考方案2】:

就个人而言,我不会使用资源的默认位置,而是使用“额外”位置,并配置资源插件以将它们从那里复制到您想要的位置:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.4.3</version>
        <executions>
          <execution>
            <id>copy-resources</id>
            <!-- here the phase you need -->
            <phase>validate</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <outputDirectory>$basedir/target</outputDirectory>
              <resources>          
                <resource>
                  <directory>src/non-packaged-resources</directory>
                  <filtering>true</filtering>
                </resource>
              </resources>              
            </configuration>            
          </execution>
        </executions>
      </plugin>
    </plugins>
    ...
  </build>
  ...
</project>

如果您坚持使用默认位置 (src/main/resources),我认为您必须配置一些排除项(见下文)以避免默认复制资源,然后使用与上述相同的方法。

另一种选择是使用 AntRun maven 插件和 Ant 来移动文件,但这不是真正的 maven 方式,所以我不会详细说明。

资源

Copy Resources Including and excluding files and directories

【讨论】:

【参考方案3】:

Eugene 走在了正确的轨道上,但有更好的方法来完成这项工作。

它应该看起来像这样:

<build>
  <outputDirectory>target/$artifactId-$version</outputDirectory>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <version>2.3.1</version>
      <configuration>
        <classesDirectory>$project.build.outputDirectory</classesDirectory>
        <outputDirector>target</outputDirectory>
      </configuration>
    </plugin>
  </plugins>
  <resources>
    <resource>
      <directory>src/main/resources/conf</directory>
      <targetPath>../conf</targetPath>
    </resource>
    <resource>
      <directory>src/main/resources/ANOTHER_PATH</directory>
      <targetPath>../ANOTHER_PATH</targetPath>
    </resource>
  </resources>
</build>

您将无法摆脱“类”目录,但您可以给它一个不应该干扰 NetBeans 的不同名称。

您可以找到有关&lt;outputDirectory&gt; 元素here 的更多信息。

你可以找到更多关于jar插件here。

您可以找到有关&lt;resource&gt; 元素here 的更多信息。

附带说明,您可能需要考虑在 1.6 JDK 下运行 Maven 并派生 maven-compiler-plugin 以使用 1.4 JDK 进行编译。你可以找到更多关于这个here。这应该会增加您的编译时间。您还可以在运行测试用例时告诉 surefire 以使用 1.4 JDK 执行。

【讨论】:

【参考方案4】:

你可以设想一个特殊的resources:copy-resources目标执行。

【讨论】:

以上是关于让 Maven2 将资源复制到构建目录,但不将它们捆绑在 JAR 中的主要内容,如果未能解决你的问题,请参考以下文章

PHP:在文件中记录错误但不将它们显示给 POST/GET 请求

为啥 SBT 不将生成的资源复制到 classes 文件夹?

《APUE.3E》习题4.6编写自己的cp(l)程序,它复制包含空洞的文件,但不将字节0包含到输出文件中去

Spring Batch 处理记录,但不将它们插入数据库

Laravel Artisan Migrate 命令创建表但不将每个迁移文件填充到迁移表

R:函数如何使用省略号 (...) 接受变量参数而不将它们复制到内存中?