SpringBoot打包后讀取JAR包同級目錄的外部文件的方法匯總
背景與痛點
在平時的項目開發(fā)中,我們經常會遇到這樣的需求:項目中有一個 template 文件夾(比如存放 Word、Excel 模板,或者 Freemarker/HTML 模板),我們希望在代碼中去讀取它。
如果是直接放在 src/main/resources 下,打包后文件會被打進 JAR 包內部。這就帶來一個問題:如果生產環(huán)境下需要修改模板內容,就必須重新打包發(fā)布,非常不方便。
因此,更優(yōu)雅的做法是:將 template 文件夾放在項目根目錄,并在打包后,讓它與 JAR 包處于同級目錄。代碼去讀取這個外部文件夾。
本文將手把手教你如何實現這個需求,并避開路徑解析中的常見“坑”。
避坑指南:為什么不建議直接用./template?
很多開發(fā)者直覺上會寫出這樣的代碼:
File templateDir = new File("./template");
結論:能用,但有非常大的隱患!
在 Java 中,./ 代表的是當前工作目錄(Current Working Directory),等同于 System.getProperty("user.dir")。它的致命弱點在于:它依賴于“你在哪里敲的啟動命令”,而不是“JAR 包在哪里”。
- 場景 1(正常): 你
cd到了 JAR 包所在的目錄,然后執(zhí)行java -jar app.jar。此時./就是 JAR 包所在目錄,讀取成功。 - 場景 2(報錯): 你的 JAR 包在
/app/my-project/下,但你在系統(tǒng)根目錄啟動項目:
cd / java -jar /app/my-project/app.jar
此時,Java 認為的 ./ 是根目錄 /!程序會去尋找 /template,結果自然是找不到文件。
- 場景 3(報錯): 將 Spring Boot 配置為 Linux 的 Systemd 服務啟動時,如果沒有嚴格配置
WorkingDirectory,默認路徑也會導致找不到文件。
為了代碼的健壯性,我們需要使用絕對路徑來定位 JAR 包!
核心方案:精準定位 JAR 包所在目錄
方法 1:Spring Boot 的極簡寫法(強烈推薦)
如果你使用的是 Spring Boot 項目,Spring 官方提供了一個非常貼心的類 ApplicationHome。它可以自動判斷當前是處于 IDE 環(huán)境還是 JAR 包運行環(huán)境,并牢牢鎖定真實的根目錄。
import org.springframework.boot.system.ApplicationHome;
import java.io.File;
public class TemplateReader {
public void readTemplates() {
// 獲取當前程序所在的根目錄 (IDE中是項目根目錄,打包后是 jar 包所在目錄)
ApplicationHome home = new ApplicationHome(getClass());
File rootDir = home.getDir();
// 拼接出 template 目錄的絕對路徑
File templateDir = new File(rootDir, "template");
if (templateDir.exists() && templateDir.isDirectory()) {
System.out.println("成功找到 template 目錄: " + templateDir.getAbsolutePath());
File[] files = templateDir.listFiles();
if (files != null) {
for (File file : files) {
System.out.println("讀取到文件: " + file.getName());
// 在這里處理你的文件邏輯...
}
}
} else {
System.out.println("未找到 template 目錄,請檢查路徑: " + templateDir.getAbsolutePath());
}
}
}方法 2:原生 Java 通用寫法(適用于非 Spring 項目)
如果你使用的是普通的 Java Maven 項目,可以通過 ProtectionDomain 獲取當前類的實際運行物理路徑,然后反推根目錄:
import java.io.File;
import java.net.URLDecoder;
public class NativeTemplateReader {
private static File getTemplateDir() {
try {
// 獲取當前類的代碼源路徑
String path = NativeTemplateReader.class.getProtectionDomain().getCodeSource().getLocation().getPath();
path = URLDecoder.decode(path, "UTF-8"); // 防止路徑中的中文或空格被 URLEncode
File file = new File(path);
File rootDir;
if (file.isFile() && path.endsWith(".jar")) {
// 環(huán)境:打包后的 jar 運行,根目錄就是 jar 包所在的父目錄
rootDir = file.getParentFile();
} else {
// 環(huán)境:IDE (如 IDEA) 中運行,退回項目根目錄
rootDir = new File(System.getProperty("user.dir"));
}
return new File(rootDir, "template");
} catch (Exception e) {
// 兜底方案
return new File(System.getProperty("user.dir"), "template");
}
}
}
工程化進階:讓 Maven 打包時自動復制文件夾
代碼寫好了,但每次執(zhí)行 mvn clean package 打包后,我們還需要手動把根目錄的 template 文件夾復制到 target 目錄下,和 jar 包放在一起,太繁瑣了!
我們可以通過配置 maven-resources-plugin 插件,讓 Maven 在打包時自動完成復制。
1. 規(guī)范的項目結構
首先確保你的項目目錄長這樣:
my-project/ ├── src/ │ └── main/java/... ├── template/ <-- 放在項目根目錄下,與 src 同級 │ ├── test1.txt │ └── test2.html └── pom.xml
2. 修改 pom.xml
在 <build><plugins> 節(jié)點下添加以下配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy-template-folder</id>
<!-- 在打包(package)階段執(zhí)行 -->
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<!-- 復制的目標位置:打包后的 target 目錄下的 template 文件夾 -->
<outputDirectory>${project.build.directory}/template</outputDirectory>
<resources>
<resource>
<!-- 復制的源位置:項目根目錄下的 template 文件夾 -->
<directory>${project.basedir}/template</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>最終效果驗證
- 開發(fā)階段:直接在 IDEA 中運行,代碼會精準讀取項目根目錄下的
template文件夾。 - 打包階段:執(zhí)行
mvn clean package。你會發(fā)現target目錄下不僅有xxx.jar,旁邊還自動多出了一個template文件夾。 - 部署階段:把
target目錄下的 jar 包和template文件夾一起丟到服務器上。無論你用什么姿勢(跨目錄、寫腳本、systemd)啟動項目,代碼都能穩(wěn)穩(wěn)地讀取到外部的模板文件。 - 后期運維:需要改模板?直接替換服務器上
template里的文件即可,無需重啟!無需重新打包!
總結
- 讀取外部同級文件,不要直接用
./,容易因為啟動目錄不同而產生 BUG。 - Spring Boot 項目無腦使用
ApplicationHome。 - 結合 Maven
maven-resources-plugin插件,可以實現絲滑的自動化打包體驗。
以上就是SpringBoot打包后讀取JAR包同級目錄的外部文件的方法匯總的詳細內容,更多關于SpringBoot打包后讀取JAR包外部文件的資料請關注腳本之家其它相關文章!
相關文章
SpringBoot多模塊依賴沖突排查與架構優(yōu)化實戰(zhàn)
本文詳細記錄了在SpringBoot多模塊項目開發(fā)中遇到的依賴版本沖突、模塊依賴設計不合理等問題的排查和解決方案的過程,主要重點關注了父模塊依賴管理、模塊化拆分、按需依賴等等,需要的朋友可以參考下2026-04-04
Hadoop?MapReduce實現單詞計數(Word?Count)
這篇文章主要為大家詳細介紹了如何利用Hadoop實現單詞計數(Word?Count)的MapReduce,文中的示例代碼講解詳細,感興趣的可以跟隨小編一起學習一下2023-05-05

