当前位置: 首页 > 知识库问答 >
问题:

当作为IntelliJ Maven项目构建的JavaFX应用程序打包为JAR时,如何加载资源?

汪翰墨
2023-03-14

问题

当JavaFX应用html" target="_blank">程序被打包为Jar文件时,我应该怎么做才能在JavaFX应用程序中加载资源?

出身背景

该应用程序是IntelliJ IDEA中的一个Maven项目。直接从IntelliJ运行应用程序对于下面描述的所有情况都很好,但是我从项目中构建的jar文件大多无法加载资源(图像和字体)。

项目目录树

application
├── .idea
├── out
├── src
|   ├── main
|   |   ├── java
|   |   |   ├── META-INF
|   |   |   └── Main.java
|   |   └── resources
|   |       ├── images
|   |       |   ├── img1.jpg
|   |       |   └── img2.png
|   |       ├── fonts
|   |       |   └── font.ttf
|   |       └── stylesheet.css
|   └── test
├── target
├── application.iml
└── pom.xml

加载图像的工作原理如下:

Image img1 = new Image(this.getClass().getResource("images/img1.jpg").toString());
Image img2 = new Image(this.getClass().getResource("images/img2.png"));

但是,因为我实际上想加载图像文件夹中的所有图像,而无需硬编码它们的名称,我一直在这样做:

File dir = new File(this.getClass().getResource("images").getFile());
List<File> imageFiles = new ArrayList<>(Arrays.asList(dir.listFiles()));
List<Image> images = new ArrayList<>();
for (int i = 0; i < imageFiles.size(); i++) {
   images.add(new Image("images/" + imageFiles.get(i).getName()));
}

当应用程序被打包到jar文件中并在第2行中产生NullPointerExcure时,这将不起作用。原来dir.listFiles()返回null,而dir.exists()返回false。

加载字体我尝试了两种方法。像样式表中的这样。css

@font-face {
   font-family: 'Font';
   src: url('fonts/font.ttf');
}

或者将此作为Main的开始方法中的第一行:

Font.loadFont(getClass().getResourceAsStream("fonts/font.ttf"), 20);

无论哪种情况,我都是通过样式表应用字体。这两种情况在IntelliJ中运行应用程序时都有效,但在运行jar时两者都不起作用。第一个方法打印错误消息

Jun 14, 2018 4:21:47 AM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
INFO: Could not load @font-face font [jar:file:/D:/path/in/file/system/java/application/out/artifacts/application_jar/application.jar!/fonts/font.ttf]

第二种方法以静默方式失败。

我所做的工作和其他信息

我正在IntelliJ中通过构建罐子-

生成的jar文件确实包含我认为它应该拥有的所有资源。也就是说,它具有以下目录树:

application.jar
├── images
|   ├── img1.jpg
|   └── img2.png
├── fonts
|   └── font.ttf
├── META-INF
├── Main.class
└── stylesheet.css

在发表这篇文章之前,我参考了ApacheMaven Archiver、IntelliJ处理工件、StackOverflow NullPointerException When。。。,StackOverflow JavaFX和maven。。。还有几个类似的问题。其中许多解决了NullPointerException:Location is required问题,这似乎发生在从xml加载JavaFX布局时,我没有这样做,也没有遇到错误。

请注意,我以前几乎没有使用Maven的经验,只是对文件流、类加载器等有一个基本的了解,还有一些使用JavaFX的经验。


共有1个答案

云韬
2023-03-14

这个问题有两个答案。

加载字体只是我的一个输入错误,我在路径名中使用了错误的大写字母。有趣的是,这种输入错误只会使字体在运行jar文件时无法加载,而在IntelliJ上运行应用程序时,这并不重要。因此,您可以从jar中加载字体,如下所示:

Font.loadFont(Memory.class.getResourceAsStream("fonts/Font.ttf"), 20);

如果没有解决方法,从jar中加载文件而不知道其确切名称似乎是不可能的。您必须获得对jar文件本身的引用,并枚举其条目。阿迪在评论中联系到的对这个问题的回答中描述了这一点。

因此,我能够像这样加载我的图像:

List<String> imagePaths = getPaths("images");
List<Image> imagePool = new ArrayList<>();
for (int i = 0; i < imagePaths.size(); i++) {
   imagePool.add(new Image(imagePaths.get(i)));
}

其中getpath

/** Returns the paths to all files in a folder. Useful for loading many files without knowing their names.
 * Importantly, this function will work whether or not the application is run from a jar or not.
 * However it might not work if the jar is not run locally.
 *
 * @param folderPath The relative path to the folder with no ending slash.
 * @return A List of path names to all files in that folder.
 * @throws IOException
 */
public static List<String> getPaths(String folderPath) throws IOException {
    final File jarFile = new File(Memory.class.getProtectionDomain().getCodeSource().getLocation().getPath());
    List<String> filePaths = new ArrayList<>();

    if(jarFile.isFile()) {  // Run with JAR file
        final JarFile jar = new JarFile(jarFile);
        final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
        while(entries.hasMoreElements()) {
            final String name = entries.nextElement().getName();
            if (name.startsWith(folderPath + "/")) { //filter according to the folderPath
                filePaths.add(name);
            }
        }
        jar.close();
    } else { // Run with IDE
        final URL url = Memory.class.getResource("/" + folderPath);
        if (url != null) {
            try {
                final File apps = new File(url.toURI());
                for (File app : apps.listFiles()) {
                    filePaths.add(folderPath + "/" + app.getName());
                }
            } catch (URISyntaxException ex) {
                // never happens
            }
        }
    }
    return filePaths;
}

与Adi所联系的问题的答案相比,这只是稍微有点变化。

 类似资料:
  • 当我想将所有项目构建到一个可运行的jar中时,我的问题就出现了。Jar的构建没有错误,所有的Java类都能工作,只有JAVAFX类不能。我不明白如何将一个带有外部JAVAFX类和依赖项的Java项目构建到一个jar中,以便一切都能正常工作。有什么建议吗?我试了很多都没有结果... 如果您需要一些代码或一些关于项目设置的信息,我会很乐意编写它们。谢谢你的忠告。 我也尝试了Maven:

  • 我有一个由3个模块组成的分级项目: (无依赖项) (依赖于) (取决于两个模块)

  • 问题内容: 我的问题可以通过在Netbeans 8中创建一个新项目来重现: 新项目>> Maven >> JavaFX应用程序 然后添加org.springframework spring-context依赖项。 构建时间从几秒钟增加到超过半分钟,这大部分是由于运行javafxpackager引起的。 我可以使用缓慢发布的版本,但是如何加快开发版本? 这是我的pom.xml: 谢谢!丹尼尔 问题答

  • 我在spring boot应用程序中有一个类,它扩展了SpringBootServletInitializer,在这个类中,我在运行时加载spring datasource详细信息,当我将应用程序打包为WAR时,这很好,但当我将其更改为jar时,SpringBootServletInitializer将被忽略。并从文档中发现,SpringBootServletInitializer仅在以WAR形式

  • 我有一个在macOS上使用< code > flutter _ libserialport 库的项目。我正在修改它,以在网络上工作,但这个库不能在网络上工作。 我正在使用javascript中的< code>navigator.serial构建一个web实现,效果很好。 然而,当我试图为web构建项目时,我得到了以下错误 这是有道理的,因为FFI在网络上不可用。 但我甚至不需要网络上的。 我怎样才