背景
把 java 項(xiàng)目打包成 jar 包時(shí),資源文件夾 resources 下的文件會(huì)被打包進(jìn) jar 包里面。當(dāng)使用 jar 運(yùn)行整個(gè)項(xiàng)目時(shí), 通過 getResource() 方法獲得的資源文件路徑會(huì)變成 xxx.jar!/xxx 的格式,這種格式的路徑,不能通過 new File 的方式找到文件。這里我提供兩個(gè)思路解決這個(gè)問題。
使用 getResourceAsStream
在這種情況下,如果想讓 jar 讀取到自己的資源文件,可以通過類加載器的 getResourceAsStream() 方法來解決。
InputStream is = this.getClass().getResourceAsStream("geolite/GeoLite2-City.mmdb")
想辦法讓資源文件出現(xiàn)在 jar 包同級(jí)目錄下
既然無法讀取 jar 包內(nèi)部的文件,那可以轉(zhuǎn)變思路,使資源文件出現(xiàn)在 jar 包的同級(jí)目錄下,然后可以獲取 jar 包的路徑,從而獲得資源文件的路徑。
由于我的項(xiàng)目是多模塊,所以我把資源文件放在項(xiàng)目根目錄下,同主模塊處在同級(jí)。這樣打包以后,資源文件不會(huì)被打包進(jìn) jar 包內(nèi),而是和主模塊同級(jí)。然后通過 Docker 把資源文件移動(dòng)到 jar 包所在的目錄下,這樣就可以輕松訪問到資源文件了。
Docker 指令如下:
RUN mkdir /data_cleaner && mkdir /data_cleaner/lib && mkdir /data_cleaner/resources
COPY resources/ /data_cleaner/resources/
COPY runner/target/lib/* /data_cleaner/lib/
COPY runner/target/*.jar /data_cleaner
CMD java -jar /data_cleaner/data-cleaning-runner.jar
需要注意的是,上述方法只適用于 Docker 環(huán)境下,所以我們需要區(qū)分項(xiàng)目是在 IDE 環(huán)境運(yùn)行,還是 Docker 環(huán)境下使用 jar 包運(yùn)行。可以通過以下代碼來判斷,同時(shí)獲取 jar 包的所在目錄
String filePath = "/resources/geolite/GeoLite2-City.mmdb";
String path;
// 判斷 ide 運(yùn)行還是 jar 運(yùn)行
File file = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
if (file.isFile()) { // jar 運(yùn)行
// 獲取 jar 包所在目錄
path = System.getProperty("java.class.path");
int firstIndex = path.lastIndexOf(System.getProperty("path.separator")) + 1;
int lastIndex = path.lastIndexOf(File.separator);
path = path.substring(firstIndex, lastIndex);
} else { // IDE 運(yùn)行
path = System.getProperty("user.dir");
}
path += filePath;
System.out.println(path);
File myFile = new File(path);
參考資料
文章標(biāo)題:使用 jar 包運(yùn)行項(xiàng)目時(shí)的資源文件定位問題
文章作者:Ciel Ni
文章鏈接:http://www.cielni.com/2018/12/15/docker-jar-file/
有問題或建議歡迎與我聯(lián)系討論,轉(zhuǎn)載或引用希望標(biāo)明出處,感激不盡!