前言
SpringBoot微服務已成為業界主流,從開發到部署都非常省時省力,但是最近小明開發時遇到一個問題:在代碼中讀取資源檔案(比如word檔案、匯出模版等),本地開發時可以正常讀取 ,但是,當我們打成jar包發布到服務器后,再次執行程式時就會拋出找不到檔案的例外,
背景
這個問題是在一次使用freemarker模版引擎匯出word報告時發現的,大概說一下docx匯出java實作思路:匯出word的檔案格式為docx,事先準備好一個排好版的docx檔案作為模版,讀取決議該模版,將其中的靜態資源替換再匯出,
docx檔案本身其實是一個壓縮的zip檔案,將其解壓過后就會發現它有自己的目錄結構,
問題
這個docx檔案所在目錄如下圖所示:

在本地除錯時,我使用如下方式讀取:
import org.springframework.util.ResourceUtils;
public static void main(String[] args) throws IOException {
File docxTemplate = ResourceUtils.getFile("classpath:templates/docxTemplate.docx");
}
可以正常決議使用,但是打包發布到beta環境卻不可用,拋出例外如下:
java.io.FileNotFoundException: class path resource [templates/docxTemplate.docx] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/usr/local/subject-server.jar!/BOOT-INF/classes!/templates/docxTemplate.docx
顯而易見,這個例外告訴我們:沒有找到檔案,但是將jar包解壓過后,發現這個檔案是真真實實存在的,
那這到底是怎么回事呢?這壓根難不倒我,我們要善于透過堆疊資訊看本質,通過仔細觀察堆疊資訊,我發現此時的檔案路徑并不是一個合法的URL(檔案資源定位符),原來jar包中資源有其專門的URL形式: jar:
File f=new File("jar:file:……");
定位檔案,就會拋出java.io.FileNotFoundException,
解決
雖然我們不能用常規操作檔案的方法來讀取jar包中的資源檔案docxTemplate.docx,但可以通過Class類的getResourceAsStream()方法,即通過流的方式來獲取 :
public static void main(String[] args) throws IOException {
InputStream inputStream = WordUtil.class.getClassLoader().getResourceAsStream("templates/docxTemplate.docx");
}
拿到流之后,就可以將其轉換為任意一個我們需要的物件,比如File、String等等,此處我要獲取docxTemplate.docx下的目錄結構,因此我需要一個File物件,代碼舉例如下:
import org.apache.commons.io.FileUtils;
public static void main(String[] args) throws IOException {
InputStream inputStream = WordUtil.class.getClassLoader().getResourceAsStream("templates/docxTemplate.docx");
File docxFile = new File("docxTemplate.docx");
// 使用common-io的工具類即可轉換
FileUtils.copyToFile(inputStream,docxFile);
ZipFile zipFile = new ZipFile(docxFile);
Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
// todo 記得關閉流
}
結果
打包、發布至beta環境,親測可用,問題完美解決,
本文可轉載,但需宣告原文出處, 程式員小明,一個很少加班的程式員,歡迎關注微信公眾號,獲取更多優質文章,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/47219.html
標籤:Java
