Java 底層資源尋找機制僅支援相對路徑。所謂「絕對路徑」只是 API 幫我們轉換為相對路徑的便利方法。理解這點對避免路徑問題至關重要。
Servlet、Filter、Listener、Controller、Interceptor 等可直接取得 ServletContext:
String realPath = servletContext.getRealPath("/");
方法 1:類加載機制(適用於類在 WEB-INF/classes 下)
URL url = MyClass.class.getClassLoader().getResource("");
String classPath = url.getPath(); // 取得 classpath 根目錄
// 再推導至 WebRoot
若類被打包進 JAR,此法失效。
方法 2:Spring 框架監聽器註冊系統屬性(推薦)
<!-- web.xml -->
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>webapp.root</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>
啟動時會將 ServletContext.getRealPath("/") 寫入系統屬性 webapp.root,之後任何地方可用:
String webRoot = System.getProperty("webapp.root");
| 程式碼 | 說明 | 範例輸出 |
|---|---|---|
MyClass.class.getResource("") | 當前類 .class 所在目錄 URI(不含類檔) | file:/D:/project/WebRoot/WEB-INF/classes/com/pkg/ |
MyClass.class.getResource("/") | Classpath 根目錄 URI | file:/D:/project/WebRoot/WEB-INF/classes/ |
Thread.currentThread().getContextClassLoader().getResource("") | 當前執行緒 ClassLoader 的 classpath 根目錄 | file:/D:/project/WebRoot/WEB-INF/classes/ |
MyClass.class.getClassLoader().getResource("") | 同上,靜態呼叫 | file:/D:/project/WebRoot/WEB-INF/classes/ |
ClassLoader.getSystemResource("") | 系統 ClassLoader 的 classpath 根目錄 | file:/D:/project/WebRoot/WEB-INF/classes/ |
System.getProperty("user.dir") | JVM 啟動工作目錄(通常為伺服器 bin 目錄) | E:\apache-tomcat\bin |
推薦: 使用 Thread.currentThread().getContextClassLoader().getResource("") 獲取 classpath 根路徑,兼容性最好。
// JSP/Servlet 中
String root = request.getServletContext().getRealPath("/");
src 為 classpath 根目錄,直接用相對路徑:
File f = new File("com/test.java"); // 相對 classpath
String path = servletContext.getRealPath("/"); // .../WebRoot/
String docPath = path.substring(0, path.lastIndexOf("\\WebRoot") + 1) + "doc/db.properties";
Properties p = new Properties();
p.load(new FileInputStream(new File(docPath)));
File、InputStream。user.dir:它指向啟動目錄,非專案目錄。getResourceAsStream() 從 ClassLoader 讀取,而非 File IO。