Java 應用部署形態多樣 (WAR 包、Spring Boot JAR、Docker 映像)、運行環境複雜 (Tomcat, Jetty, WebLogic, Resin, WildFly)、類載入機制層級分明 (Bootstrap, Extension, Application, 自定義 ClassLoader)。同一行 new File("xxx") 在不同情境下指向完全不同的物理路徑。掌握路徑解析邏輯,是避免 FileNotFoundException、配置檔讀取失敗、資源洩漏的關鍵。
| 場景 | 關鍵 API | 返回含義 | 典型用途 |
|---|---|---|---|
| Web 環境 (Servlet/JSP) | ServletContext.getRealPath("/") | Web 應用根目錄物理絕對路徑 (如 E:/workspace/project/) | 讀取配置檔、上傳檔案存儲根路徑 |
request.getContextPath() | Web 應用上下文路徑 (如 /myapp),無尾部斜槓 | 生成頁面跳轉 URL、AJAX 請求路徑 | |
request.getServletPath() / request.getRequestURI() | Servlet 映射路徑 / 完整請求 URI (含 ContextPath) | 權限攔截、日誌記錄、靜態資源映射 | |
| JSP 隱含對象 | application.getRealPath("/") | 同 ServletContext.getRealPath("/") | JSP 頁面直接取得物理路徑 |
application.getRealPath(request.getRequestURI()) | 當前請求 JSP 檔案物理路徑 | 包含當前檔案的相對引用資源 | |
| 獨立 Java 類 (非 Web 環境) | Class.getResource("") / Class.getResource("/") | 類所在包目錄 / Classpath 根目錄 URL | 讀取同包/Classpath 下配置檔、資源檔 |
ClassLoader.getResource("") / ClassLoader.getResource("/") | Classpath 根目錄 URL (無包前綴) | 統一資源加載入口,推薦使用 | |
new File("").getAbsolutePath() / System.getProperty("user.dir") | JVM 啟動工作目錄 (通常為啟動腳本執行目錄) | 相對路徑基準點,**極不穩定,生產環境禁用** | |
| Spring Resource 抽象 | ResourceLoader.getResource("classpath:xxx") / file:xxx / url:xxx | 統一資源訪問介面,支援前綴協議 | **企業級開發首選**,解耦環境差異 |
user.dir = $CATALINA_HOME/bin。new File("config.properties") 會讀 bin/config.properties,**非專案目錄**。user.dir 為 Domain 根目錄。相對路徑基於 Domain 根,絕對路徑建議配置在啟動腳本 JAVA_OPTIONS。user.dir = $JBOSS_HOME/bin。模組資源需用 Module.getResource()。user.dir 為 `java -jar` 執行目錄。classpath:/ 指向 JAR 內 BOOT-INF/classes/,**不可寫入**。外部配置請用 file:./config/ 或環境變數。src/main/resources (Classpath 根) → 使用 ClassLoader.getResourceAsStream("config.yml") 或 Spring @Value("classpath:config.yml") / ResourceLoader 讀取。**只讀,打包進 JAR/WAR 安全。**app.storage.root=/data/app/storage) 注入絕對路徑,或使用 System.getProperty("user.home") / 環境變數構建。容器化環境掛載 Volume 到該路徑。@RequestParam("file") MultipartFile → 儲存至配置的絕對路徑 → 資料庫存相對業務路徑 → 下載時流式輸出。| 錯誤代碼 | 問題 | 修正方案 |
|---|---|---|
new File("config.xml") 在 Servlet 中 | 相對路徑指向容器 bin/ 目錄,找不到檔案 | getServletContext().getRealPath("/WEB-INF/classes/config.xml") 或 Spring classpath: |
File f = new File(request.getRealPath("/upload")) | WAR 解壓部署時路徑有效,打包部署 (未解壓) 返回 null | 配置外部絕對路徑 app.upload.root,不依賴 getRealPath |
ClassLoader.getResource("").getPath() 含中文/空格 | URL 編碼導致 File 構造失敗 | 用 ResourceUtils.getFile() (Spring) 或 URLDecoder.decode(path, "UTF-8") |
路徑問題本質是環境假設與現實不符。拋棄「相對路徑」幻想,擁抱「配置化絕對路徑 + Classpath 只讀資源 + Spring Resource 抽象」,你的 Java 應用將在任何環境下穩健運行。