共计 1863 个字符,预计需要花费 5 分钟才能阅读完成。
前言
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:<url>!/{entry} )。所以,此时如果依然依照规范的文件资源定位模式
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 环境,亲测可用,问题完满解决。
本文可转载,但需申明原文出处。程序员小明,一个很少加班的程序员。欢送关注微信公账号,获取更多优质文章。