Java 路徑處理是開發中高頻痛點:相對路徑基準不明、Web 應用部署後路徑變化、JAR 打包導致資源訪問失效。本文系統梳理 Java 路徑體系,提供 Servlet、Spring、獨立應用等多場景獲取真實路徑的標準方案。
File.separator
// 在 Servlet、Filter、Listener、Controller 中
String webRoot = servletContext.getRealPath("/"); // WebRoot 根目錄
String configPath = servletContext.getRealPath("/config/"); // 子目錄
@Autowired ServletContext servletContextServletActionContext.getServletContext()request.getRealPath("/") (依賴 Request 對象,非線程安全場景受限)
// web.xml
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>myapp.root</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>
啟動時自動執行:System.setProperty("myapp.root", servletContext.getRealPath("/"))
任意處獲取:System.getProperty("myapp.root")
// 僅當類在 WEB-INF/classes 目錄下有效,JAR 打包後失效
String classPath = MyClass.class.getClassLoader().getResource("").getPath();
// 處理 URL 編碼空格等特殊字符
String decodedPath = URLDecoder.decode(classPath, "UTF-8");
局限:類打包進 JAR 後,getResource("") 返回 JAR 內部路徑 (jar:file:...),無法直接獲取 WebRoot。
| 代碼 | 返回值 | 適用場景 |
|---|---|---|
MyClass.class.getResource("") | 當前類所在包目錄 URI (不含類文件) | 讀取同包資源文件 |
MyClass.class.getResource("/") | Classpath 根目錄 URI | 讀取 classpath 根下資源 |
Thread.currentThread().getContextClassLoader().getResource("") | Classpath 根目錄 URI (線程上下文類加載器) | 多類加載器環境 (Tomcat、OSGi、測試框架) |
MyClass.class.getClassLoader().getResource("") | Classpath 根目錄 URI (類加載器) | 通用場景 |
ClassLoader.getSystemResource("") | 系統類加載器 Classpath 根 | 啟動類加載器可見資源 |
System.getProperty("user.dir") | JVM 啟動工作目錄 (如 Tomcat bin 目錄) | 相對路徑基準、日誌輸出目錄 |
| 現象 | 原因 | 解決 |
|---|---|---|
| JAR 內 getResource 返回 null | 資源未打入 JAR (Maven 未配置 resources) | pom.xml 配置 <resources> 包含配置文件 |
| getRealPath 返回 null | 應用以 WAR 部署、未爆炸、或容器不支援 | 改用 classpath 資源或外部配置目錄 |
| 路徑含中文/空格報錯 | URL 編碼 (%20、%E4%B8%AD) | URLDecoder.decode(path, "UTF-8") |
| FileInputStream 讀取 WEB-INF 失敗 | 路徑拼接錯誤、權限不足、或未爆炸部署 | 用 getResourceAsStream 讀取 classpath 資源 |
路徑問題本質是**部署形態與代碼假設不匹配**。核心原則:
ClassLoader.getResourceAsStream() 讀取 classpath 資源 (JAR/WAR/目錄部署通用)ServletContext.getRealPath() 獲取,並盡量少用user.dir 定位項目根,主代碼勿依賴遵循「資源隨代碼走 (classpath)、配置外部化」原則,可消除 90% 路徑相關 Bug。