SpringBoot打jar包或war包獲取不到資源文件解決辦法

問題描述

在開發(fā)過程中我們經(jīng)常會碰到要在代碼中獲取資源文件的情況,而我在最近將原有的Tomcat的原生項(xiàng)目遷移到SpringBoot項(xiàng)目中時(shí)碰到一個(gè)問題,就是在本地運(yùn)行時(shí),獲取本地的xml資源文件是能夠獲取到的,但是項(xiàng)目打成war包然后將其部署到Tomcat中運(yùn)行時(shí),就會發(fā)生問題,報(bào)找不到資源文件的錯(cuò)誤。然后經(jīng)過尋找排查確定了是下面代碼通過ClassLoader獲取路徑的時(shí)候出錯(cuò)了。

ExcelXmlModelFactory.class.getClassLoader().getResource("template/").getPath()

我的資源文件存放路徑如下

image

在本地中打印的日志路徑為

/Users/hupengfei/git/lap/lap-service/out/production/resources/template

但是在將SpringBoot打包成war包部署到Tomcat中時(shí)打印的目錄為

/home/app/lap/app/lap-service-1.0.0-SNAPSHOT.war!/WEB-INF/classes!/template/

可以看到在Linux中無法直接訪問未經(jīng)解壓的文件,所以就會找不到文件。

解決辦法

通過ClassLoadergetResourceAsStream()方法獲取其流,就能夠獲取到

讀取jar里面的文件,我們只能用流去讀取,不能用File

獲取資源的兩種方式

通常在開發(fā)過程中會碰到讀取配置文件的問題,一般有兩種方式進(jìn)行讀取。一種是Class.getResource(String path),一種是ClassLoader.getResource(String path),這兩種雖然都能讀取文件,但是在path的填寫上有一點(diǎn)點(diǎn)的不同。

Class.getResource

  • path以/開頭:則是從ClassPath根下獲取
  • path不以/開頭:默認(rèn)是從此類所在的包下取資源

下面有個(gè)例子

public class Test {
    public static void main(String[] args) {
         System.out.println(Test.class.getResource("/"));
        System.out.println(Test.class.getResource(""));
    }
}

輸出如下

file:/Users/hupengfei/git/Test/out/production/classes/
file:/Users/hupengfei/git/Test/out/production/classes/Practice/Day13/

那么如果在resource下有三個(gè)資源文件

image

那么該怎么獲取這三個(gè)文件呢,因?yàn)樵赾lass文件夾中的目錄結(jié)構(gòu)如下

-- classes
    -- Convience
    -- Practice
    -- Test

所以如果想要獲取Test下的資源文件,就如下的獲取方法

System.out.println(Test.class.getResource("../../Test/1.xml"));
System.out.println(Test.class.getResource("/Test/1.xml"));

ClassLoader.getResource

ClassLoader.getResource的path中不能以/開頭,path是默認(rèn)是從根目錄下進(jìn)行讀取的

例子如下

System.out.println(Test.class.getClassLoader().getResource(""));
System.out.println(Test.class.getClassLoader().getResource("/"));

打印如下

file:/Users/hupengfei/git/Test/out/production/classes/
null

從上面例子我們可以看到

Test.class.getClassLoader().getResource("")=Test.class.getResource("/")

兩個(gè)獲取資源文件的差別

其實(shí)查看Class.getResource中可以看到

    public java.net.URL getResource(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResource(name);
        }
        return cl.getResource(name);
    }

他最后調(diào)用的還是ClassLoader.getResource這個(gè)方法,那么為什么會有path的差別呢,因?yàn)槠?code>resolveName方法中對傳的/進(jìn)行了解析,解析為了空字符串。

    private String resolveName(String name) {
        if (name == null) {
            return name;
        }
        if (!name.startsWith("/")) {
            Class<?> c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                name = baseName.substring(0, index).replace('.', '/')
                    +"/"+name;
            }
        } else {
            name = name.substring(1);
        }
        return name;
    }

可以看到在這穿進(jìn)去的為/

image

傳出的是

image

參考文章

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,715評論 19 139
  • ClassLoader翻譯過來就是類加載器,普通的java開發(fā)者其實(shí)用到的不多,但對于某些框架開發(fā)者來說卻非常常見...
    時(shí)待吾閱讀 1,169評論 0 1
  • 傍晚接你放學(xué)的時(shí)候,有個(gè)培訓(xùn)學(xué)校在做活動(dòng),只要掃二維碼并加群,就可以領(lǐng)一個(gè)小黃人彩筆。你一出校門就看到了醒目...
    婷Amy閱讀 177評論 0 0
  • Sublime Text 3(以下簡稱 ST3)作為輕量級文本編輯器是很不錯(cuò)的,打開速度要比 VS Code 快不...
    沐青之楓閱讀 4,316評論 5 6
  • 《不離不散》 主演:涓 子 作詞:盧木鳥 作曲:姜 山 編曲:姜 山 愛上你的笑發(fā)現(xiàn)你的美 相見恨晚是命中注定的緣...
    華狐發(fā)布閱讀 307評論 0 0

友情鏈接更多精彩內(nèi)容