JavaFX中getResourceAsStream加载FXML图片失败问题咨询
JavaFX FXML加载时图片路径解析异常问题
问题场景
在IntelliJ中维护Maven结构的JavaFX项目时,遇到以下问题:
- 使用
getClass().getClassLoader().getResourceAsStream("AuthorizationPage.fxml")加载FXML文件时,FXML本身能正常加载,但其中通过@images/sign-up-logo.png引用的图片加载失败,抛出IllegalArgumentException: Invalid URL or resource not found异常 - 使用
getClass().getResource("/AuthorizationPage.fxml")加载时,FXML及其中的图片均能正常显示 - 已确认
getResourceAsStream返回的流不为null,单独验证图片流也能正常加载
问题代码
@Override public void start(Stage stage) throws IOException { Parent root; FXMLLoader fxmlLoader = new FXMLLoader(); // 以下代码加载FXML文件时,其中的图片无法正常加载 root = fxmlLoader.load(getClass().getClassLoader().getResourceAsStream("AuthorizationPage.fxml")); // 以下代码仅用于验证,getResourceAsStream能获取到图片流,单独验证时图片可正常加载 // System.out.println(Objects.isNull(getClass().getClassLoader().getResourceAsStream("sign-up-logo.png"))); // 以下代码可正常加载FXML文件及其中的图片 root = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/AuthorizationPage.fxml"))); Scene scene = new Scene(root); stage.setScene(scene); SceneManager sceneManager = SceneManager.getInstance(stage); sceneManager.addScene("/AuthorizationPage.fxml", "User Authorization"); if (!SessionManager.hasUserSessionFromLocalFileExpired()) { sceneManager = SceneManager.getInstance(stage); sceneManager.addScene("/convertor.fxml", "Convert Pdf Documents"); sceneManager.activateScene("Convert Pdf Documents", "Convert Pdf Documents", true, true); } else { sceneManager.activateScene("User Authorization", "User Authorization", false, false); } }
异常堆栈
null/images/sign-up-logo.png Exception in Application start method java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:465) at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1082) Caused by: java.lang.RuntimeException: Exception in Application start method at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901) at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196) at java.base/java.lang.Thread.run(Thread.java:833) Caused by: javafx.fxml.LoadException: unknown path:33 at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2714) at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2692) at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2539) at com.javafxapp.javafxapplication/com.app.convertor.authorization.Main.start(Main.java:39) at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847) at javafx.graphics@19.0.2/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484) at javafx.graphics@19.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457) at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) at javafx.graphics@19.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456) at javafx.graphics@19.0.2/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96) at javafx.graphics@19.0.2/com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at javafx.graphics@19.0.2/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184) ... 1 more Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found at javafx.graphics@19.0.2/javafx.scene.image.Image.validateUrl(Image.java:1138) at javafx.graphics@19.0.2/javafx.scene.image.Image.<init>(Image.java:695) at javafx.fxml@19.0.2/com.sun.javafx.fxml.builder.JavaFXImageBuilder.build(JavaFXImageBuilder.java:47) at javafx.fxml@19.0.2/com.sun.javafx.fxml.builder.JavaFXImageBuilder.build(JavaFXImageBuilder.java:37) at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:774) at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2961) at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2646) ... 11 more Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found at javafx.graphics@19.0.2/javafx.scene.image.Image.validateUrl(Image.java:1123) ... 17 more Exception running application com.app.convertor.authorization.Main Process finished with exit code 1
FXML片段
<HBox prefHeight="100.0" prefWidth="200.0"> <children> <AnchorPane prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS"> <children> <ImageView fitHeight="108.0" fitWidth="101.0" layoutX="270.0" pickOnBounds="true" preserveRatio="true"> <image> <Image url="@images/sign-up-logo.png" /> </image> </ImageView> </children> </AnchorPane> </children> </HBox>
Maven pom.xml片段
<resources> <resource> <directory>src/main/resources</directory> </resource> <resource> <directory>src/main/resources/com/app/convertor/config</directory> </resource> <resource> <directory>src/main/resources/com/app/convertor/fxml/images</directory> </resource> <resource> <directory>src/main/resources/com/app/convertor/fxml</directory> </resource> </resources>
问题原因
核心原因是FXMLLoader加载InputStream时,缺少资源解析的基础URL上下文:
- 当使用
FXMLLoader.load(URL)方法时,FXMLLoader会自动将该URL作为基础路径,解析FXML中以@开头的相对路径资源(比如图片) - 当使用
load(InputStream)方法时,FXMLLoader无法获取到FXML文件的原始URL,导致相对路径失去了基准,只能以null作为基础拼接路径(异常信息中的null/images/sign-up-logo.png就是直接证据),最终找不到资源
正确解决方案
有两种可靠的解决方式:
方式1:给FXMLLoader设置location属性(保留InputStream加载方式)
如果一定要用InputStream加载,需要先获取FXML的URL并设置给FXMLLoader的location属性,提供相对路径的解析基准:
@Override public void start(Stage stage) throws IOException { Parent root; FXMLLoader fxmlLoader = new FXMLLoader(); // 先获取FXML的URL,作为解析相对路径的基础 URL fxmlUrl = getClass().getClassLoader().getResource("AuthorizationPage.fxml"); // 设置FXMLLoader的location fxmlLoader.setLocation(fxmlUrl); // 再加载流 root = fxmlLoader.load(fxmlUrl.openStream()); // 后续代码不变... }
方式2:直接使用URL加载(推荐)
这是JavaFX官方更推荐的方式,直接用FXMLLoader.load(URL),无需手动处理流,自动维护资源解析上下文:
@Override public void start(Stage stage) throws IOException { Parent root; // 直接通过URL加载,自动处理相对路径资源 root = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/AuthorizationPage.fxml"))); // 后续代码不变... }
额外优化:Maven资源配置简化
你的pom.xml中配置了多个重复的resource目录,实际上只需要配置根目录src/main/resources即可,Maven会自动递归处理子目录下的所有资源:
<resources> <resource> <directory>src/main/resources</directory> </resource> </resources>
内容的提问来源于stack exchange,提问作者Vidhan
相关产品推荐
相关产品推荐

