解决SpringBootjar包中的⽂件读取问题
前⾔
SpringBoot微服务已成为业界主流,从开发到部署都⾮常省时省⼒,但是最近⼩明开发时遇到⼀个问题:在代码中读取资源⽂件(⽐如word⽂档、导出模版等),本地开发时可以
正常读取,但是,当我们打成jar包发布到服务器后,再次执⾏程序时就会抛出不到⽂件的异常。
背景
这个问题是在⼀次使⽤freemarker模版引擎导出word报告时发现的。⼤概说⼀下docx导出java实现思路:导出word的⽂档格式为docx,事先准备好⼀个排好版的docx⽂档作为模
版,读取解析该模版,将其中的静态资源替换再导出。
docx⽂档本⾝其实是⼀个压缩的zip⽂件,将其解压过后就会发现它有⾃⼰的⽬录结构。
问题
spring怎么读取properties这个docx⽂档所在⽬录如下图所⽰:
在本地调试时,我使⽤如下⽅式读取:
import org.springframework.util.ResourceUtils;
public static void main(String[] args) throws IOException {
File docxTemplate = File("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/docxTe
显⽽易见,这个异常告诉我们:没有到⽂件,但是将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 = ClassLoader().getResourceAsStream("templates/docxTemplate.docx");
}
拿到流之后,就可以将其转换为任意⼀个我们需要的对象,⽐如File、String等等,此处我要获取docxTemplate.docx下的⽬录结构,因此我需要⼀个File对象,代码举例如下:
import org.apachemons.io.FileUtils;
public static void main(String[] args) throws IOException {
InputStream inputStream = ClassLoader().getResourceAsStream("templates/docxTemplate.docx");
File docxFile = new File("docxTemplate.docx");
// 使⽤common-io的⼯具类即可转换
ZipFile zipFile = new ZipFile(docxFile);
Enumeration<? extends ZipEntry> zipEntrys = ies();
// todo 记得关闭流
}
结果
打包、发布⾄beta环境,亲测可⽤,问题完美解决。
本⽂可转载,但需声明原⽂出处。程序员⼩明,⼀个很少加班的程序员。欢迎关注,获取更多优质⽂章。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论