You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:21:01