首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Applet 存取 JAR 內資源檔案的正確姿勢

     編輯:Java 相關知識

問題情境

將圖片、聲音等資源打包進 JAR,HTML 以 ARCHIVE="test.jar" 載入 Applet。直覺寫法 new ImageIcon("/img/logo.gif") 拋出 AccessControlException: FilePermission denied。

根本原因

  • Applet 沙箱禁止本地檔案系統存取(FilePermission)
  • new ImageIcon(String path) 嘗試以檔案路徑載入,觸發安全檢查
  • JAR 內資源非檔案系統路徑,需透過 ClassLoader 以串流方式讀取

正確解法:Class.getResource()

API 契約

public URL getResource(String name)
// 規則:
// 1. 以 '/' 開頭:從 classpath 根目錄查找(不含套件前綴)
// 2. 不以 '/' 開頭:相對於當前類別套件路徑(將 '.' 換成 '/')
// 3. 找不到回傳 null

修正程式碼

// 錯誤寫法
// private ImageIcon icon = new ImageIcon("/img/logo.gif");

// 正確寫法
private ImageIcon icon = new ImageIcon(getClass().getResource("/img/logo.gif"));

// 更完整的防禦寫法
URL imgUrl = getClass().getResource("/img/logo.gif");
if (imgUrl == null) {
    throw new IllegalStateException("資源不存在: /img/logo.gif");
}
ImageIcon icon = new ImageIcon(imgUrl);

完整 Applet 範例

import javax.swing.*;
import java.awt.*;

public class ImageButtonApplet extends JApplet {
    public void init() {
        try {
            // 關鍵:使用 getClass().getResource() 取得 JAR 內資源 URL
            URL imgUrl = getClass().getResource("/img/logo.gif");
            if (imgUrl == null) throw new Exception("找不到資源");
            
            ImageIcon icon = new ImageIcon(imgUrl);
            JButton btn = new JButton(icon);
            
            getContentPane().add(btn);
        } catch (Exception e) {
            e.printStackTrace();
            getContentPane().add(new JLabel("載入失敗: " + e.getMessage()));
        }
    }
}

打包與部署步驟

  1. 目錄結構:
    src/ImageButtonApplet.java
    src/img/logo.gif
  2. 編譯:javac -d bin src/ImageButtonApplet.java
  3. 打包:jar cvf test.jar -C bin .(包含 img/logo.gif)
  4. HTML:
    <applet code="ImageButtonApplet.class" archive="test.jar" width="200" height="200"></applet>

進階資源存取模式

1. 取得 InputStream(適用非圖片資源)

try (InputStream is = getClass().getResourceAsStream("/config.properties")) {
    Properties props = new Properties();
    props.load(is);
}

2. 批次列出目錄下資源

JAR 無目錄概念,需掃描 ClassPath 或使用 ClassLoader.getResources()。常見做法:預先定義資源清單檔(MANIFEST.MF 或自訂 resources.lst)。

3. 非 Applet 環境通用性

getClass().getResource() 在以下環境同樣適用:

  • 一般 Java 應用(java -jar app.jar)
  • Web 應用(WEB-INF/classes、WEB-INF/lib/*.jar)
  • Spring ClassPathResource 底層實作
  • 單元測試(src/test/resources)

常見錯誤與除錯

錯誤現象原因解決
getResource 回傳 null路徑錯誤、大小寫不符、未打入 JAR檢查 JAR 內結構:jar tf test.jar | grep logo
ImageIcon 圖片不顯示URL 正確但圖片格式不支援、損壞用 ImageIO.read(url) 驗證
開發環境正常、部署失效IDE 自動複製 resources 到輸出目錄,但打包腳本遺漏檢查 Maven/Gradle resources 設定

現代化替代方案

Applet 已淘汰,現代 Web 應用資源載入:

  • 前端:<img src="/assets/logo.gif">、Webpack import logo from './logo.gif'、Vite new URL('./logo.gif', import.meta.url)
  • Java 後端:Spring ResourceLoader、ClassPathResource、ServletContext.getResource()
  • 桌面應用:JavaFX getClass().getResource()、Swing 同樣適用

總結

鐵律:JAR 內資源永遠使用 Class.getResource() 或 ClassLoader.getResource() 取得 URL/Stream,絕不使用檔案路徑字串。 此原理貫穿 Java 所有類載入場景,掌握它能解決 90% 的資源載入問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved