解决SpringBoot jar包中的文件读取问题
前言
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:!/{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环境,亲测可用,问题完美解决。
最后
七夕啦~给大家科普一下辣的程度
- 1级:微辣
- 2级:中辣
- 3级:重辣
- 4级:变态辣
- 10级:你又一个人过七夕辣! 祝天下有情人终成眷属!祝大家早日脱单!❤️ < END >
- Java文件上传与下载【面试+工作】
- QBC查询
- 一条delete语句的调优(r4笔记第86天)
- Java支付宝接口开发【面试+工作】
- 03.SVN检出/解决冲突/提交
- Spring思维导图,让Spring不再难懂(mvc篇)
- SQL优化一(SQL使用技巧)
- Spring思维导图,让Spring不再难懂(aop篇)
- MongoDB初探第二篇 (r4笔记第82天)
- Spring思维导图,让Spring不再难懂(cache篇)
- 曲折的10g,11g中EM的安装配置过程(r4笔记第98天)
- Linux 学习记录 一(安装、基本文件操作).
- 实用的位运算应用(r4笔记第97天)
- 关于date格式的两个案例(r4笔记第96天)
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释