在 Web 容器中獲取部署根路徑(webapp/ 目錄)是常見需求:讀取配置文件、存儲上傳文件、生成報表等。Spring 提供開箱即用的監聽器方案。
<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>
webAppRootKey:自定義系統屬性鍵,默認 webapp.root。WebAppRootListener:ServletContextListener 實現,容器啟動時將 ServletContext.getRealPath("/") 寫入 System.setProperty(key, path)。public class PathUtil {
private static final String WEB_ROOT = System.getProperty("webapp.root");
public static String getWebRoot() { return WEB_ROOT; }
public static String getAbsolutePath(String relativePath) {
return WEB_ROOT + File.separator + relativePath;
}
}
// WebAppRootListener 源碼精簡
public class WebAppRootListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
String key = event.getServletContext().getInitParameter("webAppRootKey");
String root = event.getServletContext().getRealPath("/");
System.setProperty(key, root);
}
public void contextDestroyed(ServletContextEvent event) {
String key = event.getServletContext().getInitParameter("webAppRootKey");
System.clearProperty(key); // 防止內存洩漏
}
}
| 場景 | 建議方案 |
|---|---|
| Spring Boot 內嵌容器 | @Value("${spring.servlet.multipart.location}") 或 ResourceLoader.getResource("") |
| 非 Spring 環境 | servletContext.getRealPath("/") 在 Servlet/Listner/Filter 中調用 |
| 單元測試 | Mock ServletContext 或使用 ClassLoader.getResource("") 定位 classpath |
| 戰鬥部署 (WAR 包) | getRealPath 可能返回 null,改用 servletContext.getResource("/") 獲取 URL 再轉換 |
PathUtil,業務代碼僅依賴相對路徑。WebAppRootListener 已在 contextDestroyed 中 clearProperty,防止系統屬性污染後續部署。一行配置,一行代碼,優雅解決「路徑焦慮」。