问题
当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的经验。
这个问题有两个答案。
加载字体只是我的一个输入错误,我在路径名中使用了错误的大写字母。有趣的是,这种输入错误只会使字体在运行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:
问题内容: 我的问题可以通过在Netbeans 8中创建一个新项目来重现: 新项目>> Maven >> JavaFX应用程序 然后添加org.springframework spring-context依赖项。 构建时间从几秒钟增加到超过半分钟,这大部分是由于运行javafxpackager引起的。 我可以使用缓慢发布的版本,但是如何加快开发版本? 这是我的pom.xml: 谢谢!丹尼尔 问题答
我有一个由3个模块组成的分级项目: (无依赖项) (依赖于) (取决于两个模块)
我在spring boot应用程序中有一个类,它扩展了SpringBootServletInitializer,在这个类中,我在运行时加载spring datasource详细信息,当我将应用程序打包为WAR时,这很好,但当我将其更改为jar时,SpringBootServletInitializer将被忽略。并从文档中发现,SpringBootServletInitializer仅在以WAR形式
和调用方法的位置:
我有一个在macOS上使用< code > flutter _ libserialport 库的项目。我正在修改它,以在网络上工作,但这个库不能在网络上工作。 我正在使用javascript中的< code>navigator.serial构建一个web实现,效果很好。 然而,当我试图为web构建项目时,我得到了以下错误 这是有道理的,因为FFI在网络上不可用。 但我甚至不需要网络上的。 我怎样才