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

8
我在NetBeans中开始了一个新的Maven项目,并接受了所有默认设置。该POM已剥离了所有JAR依赖项,将其剪切并粘贴到本问题的底部。
该应用程序读取各种属性文件(例如日志和配置文件)。它还读取外部资源,如字体、图像和声音。我不希望所有这些资源被捆绑到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上的搜索来看...所有的重复问题都试图去另一个方向!(即将资源放入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>
    ...
4个回答

11

虽然提出的解决方案可行,但它们基本上是绕过了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中排除它们,而无需任何绕过方法。 这里是jar插件的文档页面。
尽管以上内容将回答您的问题,但我建议您考虑一些其他可能性,以帮助您在努力中取得成功。作为第二步,为了仍然使这些资源可用,您可以使用assembly插件来打包您的项目。这将允许您创建一个zip文件,并将所有文件、资源和jar放置在适当的位置,以便当zip文件被解压缩时,一切都自动就位。
如果该项目是较大工作的一部分,您仍然可以为每个工作使用assembly插件,在主项目中提取和重新组合它们以包括所有必要的构件的更大的zip文件中。
最后,建议您保留目标下的目录结构不变。如果您想自定义它,最好通过Maven变量进行配置,以便更改能够渗透到其他插件中。如果您在Maven完成后手动删除和重命名内容,则可能会在以后遇到问题。通常,如果您按照所需的方式对其进行配置,则Maven jar插件应该能够正确地完成工作,因此您不需要担心目标下的内容。个人而言,我使用Eclipse,并且推送非常擅长使IDE和Maven配置保持同步。对于NetBeans,我认为情况也是如此。如果不是这样,最好的方法是在NetBeans中配置您的项目,以使用target/classes作为构建工件的目标文件夹,使用target/test-classes作为从src/test/java构建的内容的目标文件夹。

这不会给出OP所要求的内容(即在目标目录的根目录中包含conf、font等),至少需要更多的努力。 - Pascal Thivent
这就是为什么我建议使用与“src/main/resources”不同的位置来实现OP要求的内容,而不会破坏任何东西。 - Pascal Thivent
然而,我必须指出,上面的POM示例按原样并没有起作用。最终我将<configuration>元素提升了两个级别,使其成为<plugin>元素的直接子元素...然后完全消除了<executions>元素。这样就可以正常工作了。 - Steve Perkins
@Steve:感谢您的评论,我已经对答案进行了更正以反映您的经验。 - Newtopian
同意,但不强制执行协议 :-). 我的观点是,在引用你在这里引用的内容时,将资源放置在不被Maven捡起的不同位置,因此,当从IDE执行应用程序时,这些资源不会被放置在目标文件夹中,从而防止应用程序找到这些资源。我倾向于让IDE环境和最终部署环境尽可能接近。在这里,我从问题中理解的是,期望在此位置找到这些资源,只是它们位于jar文件内是不可取的... - Newtopian
显示剩余5条评论

6

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

<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方式,所以我不会详细介绍它。
资源

0

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>

你无法摆脱 'classes' 目录,但你可以给它一个不会干扰 NetBeans 的不同名称。

你可以在这里找到更多关于 <outputDirectory> 元素的信息 here

你可以在这里找到更多关于 jar 插件的信息 here

你可以在这里找到更多关于 <resource> 元素的信息 here

另外,您可能希望考虑在1.6 JDK下运行Maven,并分叉maven-compiler-plugin以使用您的1.4 JDK进行编译。 您可以在这里了解更多信息。 这应该可以提高您的编译时间。 您还可以在运行测试用例时告诉surefire也使用1.4 JDK进行执行。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接