最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot打包后讀取JAR包同級(jí)目錄的外部文件的方法匯總

 更新時(shí)間:2026年04月07日 08:55:43   作者:用戶(hù)030480591263  
在平時(shí)的項(xiàng)目開(kāi)發(fā)中,我們經(jīng)常會(huì)遇到這樣的需求:項(xiàng)目中有一個(gè) template 文件夾,我們希望在代碼中去讀取它,因此,更優(yōu)雅的做法是:將 template 文件夾放在項(xiàng)目根目錄,并在打包后,讓它與 JAR 包處于同級(jí)目錄,本文將手把手教你如何實(shí)現(xiàn)這個(gè)需求,需要的朋友可以參考下

背景與痛點(diǎn)

在平時(shí)的項(xiàng)目開(kāi)發(fā)中,我們經(jīng)常會(huì)遇到這樣的需求:項(xiàng)目中有一個(gè) template 文件夾(比如存放 Word、Excel 模板,或者 Freemarker/HTML 模板),我們希望在代碼中去讀取它。

如果是直接放在 src/main/resources 下,打包后文件會(huì)被打進(jìn) JAR 包內(nèi)部。這就帶來(lái)一個(gè)問(wèn)題:如果生產(chǎn)環(huán)境下需要修改模板內(nèi)容,就必須重新打包發(fā)布,非常不方便。

因此,更優(yōu)雅的做法是:template 文件夾放在項(xiàng)目根目錄,并在打包后,讓它與 JAR 包處于同級(jí)目錄。代碼去讀取這個(gè)外部文件夾。

本文將手把手教你如何實(shí)現(xiàn)這個(gè)需求,并避開(kāi)路徑解析中的常見(jiàn)“坑”。

避坑指南:為什么不建議直接用./template?

很多開(kāi)發(fā)者直覺(jué)上會(huì)寫(xiě)出這樣的代碼:

File templateDir = new File("./template");

結(jié)論:能用,但有非常大的隱患!

在 Java 中,./ 代表的是當(dāng)前工作目錄(Current Working Directory),等同于 System.getProperty("user.dir")。它的致命弱點(diǎn)在于:它依賴(lài)于“你在哪里敲的啟動(dòng)命令”,而不是“JAR 包在哪里”。

  • 場(chǎng)景 1(正常):cd 到了 JAR 包所在的目錄,然后執(zhí)行 java -jar app.jar。此時(shí) ./ 就是 JAR 包所在目錄,讀取成功。
  • 場(chǎng)景 2(報(bào)錯(cuò)): 你的 JAR 包在 /app/my-project/ 下,但你在系統(tǒng)根目錄啟動(dòng)項(xiàng)目:
cd /
java -jar /app/my-project/app.jar

此時(shí),Java 認(rèn)為的 ./ 是根目錄 /!程序會(huì)去尋找 /template,結(jié)果自然是找不到文件。

  • 場(chǎng)景 3(報(bào)錯(cuò)): 將 Spring Boot 配置為 Linux 的 Systemd 服務(wù)啟動(dòng)時(shí),如果沒(méi)有嚴(yán)格配置 WorkingDirectory,默認(rèn)路徑也會(huì)導(dǎo)致找不到文件。

為了代碼的健壯性,我們需要使用絕對(duì)路徑來(lái)定位 JAR 包!

核心方案:精準(zhǔn)定位 JAR 包所在目錄

方法 1:Spring Boot 的極簡(jiǎn)寫(xiě)法(強(qiáng)烈推薦)

如果你使用的是 Spring Boot 項(xiàng)目,Spring 官方提供了一個(gè)非常貼心的類(lèi) ApplicationHome。它可以自動(dòng)判斷當(dāng)前是處于 IDE 環(huán)境還是 JAR 包運(yùn)行環(huán)境,并牢牢鎖定真實(shí)的根目錄。

import org.springframework.boot.system.ApplicationHome;
import java.io.File;
public class TemplateReader {
    public void readTemplates() {
        // 獲取當(dāng)前程序所在的根目錄 (IDE中是項(xiàng)目根目錄,打包后是 jar 包所在目錄)
        ApplicationHome home = new ApplicationHome(getClass());
        File rootDir = home.getDir();
        // 拼接出 template 目錄的絕對(duì)路徑
        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 目錄,請(qǐng)檢查路徑: " + templateDir.getAbsolutePath());
        }
    }
}

方法 2:原生 Java 通用寫(xiě)法(適用于非 Spring 項(xiàng)目)

如果你使用的是普通的 Java Maven 項(xiàng)目,可以通過(guò) ProtectionDomain 獲取當(dāng)前類(lèi)的實(shí)際運(yùn)行物理路徑,然后反推根目錄:

import java.io.File;
import java.net.URLDecoder;

public class NativeTemplateReader {

    private static File getTemplateDir() {
        try {
            // 獲取當(dāng)前類(lèi)的代碼源路徑
            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 運(yùn)行,根目錄就是 jar 包所在的父目錄
                rootDir = file.getParentFile();
            } else {
                // 環(huán)境:IDE (如 IDEA) 中運(yùn)行,退回項(xiàng)目根目錄
                rootDir = new File(System.getProperty("user.dir")); 
            }

            return new File(rootDir, "template");

        } catch (Exception e) {
            // 兜底方案
            return new File(System.getProperty("user.dir"), "template");
        }
    }
}

工程化進(jìn)階:讓 Maven 打包時(shí)自動(dòng)復(fù)制文件夾

代碼寫(xiě)好了,但每次執(zhí)行 mvn clean package 打包后,我們還需要手動(dòng)把根目錄的 template 文件夾復(fù)制到 target 目錄下,和 jar 包放在一起,太繁瑣了!

我們可以通過(guò)配置 maven-resources-plugin 插件,讓 Maven 在打包時(shí)自動(dòng)完成復(fù)制

1. 規(guī)范的項(xiàng)目結(jié)構(gòu)

首先確保你的項(xiàng)目目錄長(zhǎng)這樣:

my-project/
 ├── src/
 │    └── main/java/...
 ├── template/          <-- 放在項(xiàng)目根目錄下,與 src 同級(jí)
 │    ├── test1.txt
 │    └── test2.html
 └── pom.xml

2. 修改 pom.xml

<build><plugins> 節(jié)點(diǎn)下添加以下配置:

<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>
                <!-- 復(fù)制的目標(biāo)位置:打包后的 target 目錄下的 template 文件夾 -->
                <outputDirectory>${project.build.directory}/template</outputDirectory>
                <resources>
                    <resource>
                        <!-- 復(fù)制的源位置:項(xiàng)目根目錄下的 template 文件夾 -->
                        <directory>${project.basedir}/template</directory>
                        <filtering>false</filtering>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

最終效果驗(yàn)證

  1. 開(kāi)發(fā)階段:直接在 IDEA 中運(yùn)行,代碼會(huì)精準(zhǔn)讀取項(xiàng)目根目錄下的 template 文件夾。
  2. 打包階段:執(zhí)行 mvn clean package。你會(huì)發(fā)現(xiàn) target 目錄下不僅有 xxx.jar,旁邊還自動(dòng)多出了一個(gè) template 文件夾。
  3. 部署階段:把 target 目錄下的 jar 包和 template 文件夾一起丟到服務(wù)器上。無(wú)論你用什么姿勢(shì)(跨目錄、寫(xiě)腳本、systemd)啟動(dòng)項(xiàng)目,代碼都能穩(wěn)穩(wěn)地讀取到外部的模板文件。
  4. 后期運(yùn)維:需要改模板?直接替換服務(wù)器上 template 里的文件即可,無(wú)需重啟!無(wú)需重新打包!

總結(jié)

  • 讀取外部同級(jí)文件,不要直接用 ./,容易因?yàn)閱?dòng)目錄不同而產(chǎn)生 BUG。
  • Spring Boot 項(xiàng)目無(wú)腦使用 ApplicationHome
  • 結(jié)合 Maven maven-resources-plugin 插件,可以實(shí)現(xiàn)絲滑的自動(dòng)化打包體驗(yàn)。

以上就是SpringBoot打包后讀取JAR包同級(jí)目錄的外部文件的方法匯總的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot打包后讀取JAR包外部文件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring-webflux?響應(yīng)式編程的實(shí)例詳解

    Spring-webflux?響應(yīng)式編程的實(shí)例詳解

    Spring 提供了兩個(gè)并行堆棧,一種是基于帶有 Spring MVC 和 Spring Data 結(jié)構(gòu)的 Servlet API,另一個(gè)是完全反應(yīng)式堆棧,它利用了 Spring WebFlux 和 Spring Data 的反應(yīng)式存儲(chǔ)庫(kù),這篇文章主要介紹了Spring-webflux?響應(yīng)式編程,需要的朋友可以參考下
    2022-09-09
  • java開(kāi)發(fā)RocketMQ生產(chǎn)者高可用示例詳解

    java開(kāi)發(fā)RocketMQ生產(chǎn)者高可用示例詳解

    這篇文章主要為大家介紹了java開(kāi)發(fā)RocketMQ生產(chǎn)者高可用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • SpringBoot多模塊依賴(lài)沖突排查與架構(gòu)優(yōu)化實(shí)戰(zhàn)

    SpringBoot多模塊依賴(lài)沖突排查與架構(gòu)優(yōu)化實(shí)戰(zhàn)

    本文詳細(xì)記錄了在SpringBoot多模塊項(xiàng)目開(kāi)發(fā)中遇到的依賴(lài)版本沖突、模塊依賴(lài)設(shè)計(jì)不合理等問(wèn)題的排查和解決方案的過(guò)程,主要重點(diǎn)關(guān)注了父模塊依賴(lài)管理、模塊化拆分、按需依賴(lài)等等,需要的朋友可以參考下
    2026-04-04
  • springMVC實(shí)現(xiàn)前臺(tái)帶進(jìn)度條文件上傳的示例代碼

    springMVC實(shí)現(xiàn)前臺(tái)帶進(jìn)度條文件上傳的示例代碼

    本篇文章主要介紹了springMVC實(shí)現(xiàn)前臺(tái)帶進(jìn)度條文件上傳的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2017-01-01
  • Java五子棋簡(jiǎn)單實(shí)現(xiàn)代碼舉例

    Java五子棋簡(jiǎn)單實(shí)現(xiàn)代碼舉例

    Java五子棋游戲是一種經(jīng)典的兩人對(duì)戰(zhàn)棋類(lèi)游戲,它基于簡(jiǎn)單的規(guī)則,即任何一方的棋子在棋盤(pán)上形成連續(xù)的五個(gè),無(wú)論是橫、豎還是斜線(xiàn),都將獲勝,這篇文章主要介紹了Java五子棋實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2024-10-10
  • Java中定時(shí)任務(wù)的全方位場(chǎng)景實(shí)現(xiàn)思路分析

    Java中定時(shí)任務(wù)的全方位場(chǎng)景實(shí)現(xiàn)思路分析

    在開(kāi)發(fā)過(guò)程中,根據(jù)需求和業(yè)務(wù)的不同經(jīng)常會(huì)有很多場(chǎng)景需要用到不同特性的定時(shí)任務(wù),本文將針對(duì)這些場(chǎng)景,提供不同的一個(gè)實(shí)現(xiàn)思路,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧
    2023-12-12
  • mybatis-plus多表關(guān)聯(lián)查詢(xún)功能的實(shí)現(xiàn)

    mybatis-plus多表關(guān)聯(lián)查詢(xún)功能的實(shí)現(xiàn)

    本文給大家介紹mybatis-plus多表關(guān)聯(lián)查詢(xún)功能的實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-11-11
  • Java數(shù)據(jù)結(jié)構(gòu)之循環(huán)隊(duì)列簡(jiǎn)單定義與用法示例

    Java數(shù)據(jù)結(jié)構(gòu)之循環(huán)隊(duì)列簡(jiǎn)單定義與用法示例

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之循環(huán)隊(duì)列簡(jiǎn)單定義與用法,簡(jiǎn)要描述了循環(huán)隊(duì)列的概念、原理,并結(jié)合實(shí)例形式分析了java循環(huán)隊(duì)列的定義與使用方法,需要的朋友可以參考下
    2017-10-10
  • java使用udp實(shí)現(xiàn)簡(jiǎn)單多人聊天功能

    java使用udp實(shí)現(xiàn)簡(jiǎn)單多人聊天功能

    這篇文章主要為大家詳細(xì)介紹了java使用udp實(shí)現(xiàn)簡(jiǎn)單多人聊天功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Hadoop?MapReduce實(shí)現(xiàn)單詞計(jì)數(shù)(Word?Count)

    Hadoop?MapReduce實(shí)現(xiàn)單詞計(jì)數(shù)(Word?Count)

    這篇文章主要為大家詳細(xì)介紹了如何利用Hadoop實(shí)現(xiàn)單詞計(jì)數(shù)(Word?Count)的MapReduce,文中的示例代碼講解詳細(xì),感興趣的可以跟隨小編一起學(xué)習(xí)一下
    2023-05-05

最新評(píng)論

益阳市| 财经| 镇平县| 珠海市| 长兴县| 漳浦县| 高唐县| 象山县| 临澧县| 望谟县| 华宁县| 米林县| 睢宁县| 莫力| 衡东县| 遵义县| 突泉县| 通化县| 抚顺市| 林州市| 左贡县| 正定县| 广德县| 永城市| 依兰县| 东至县| 定州市| 云南省| 星座| 德江县| 新安县| 沂源县| 光泽县| 巢湖市| 尉犁县| 仁怀市| 滁州市| 娄烦县| 门头沟区| 绿春县| 拜泉县|