解决SpringBoot jar包中的文件读取问题实现

所属分类: 软件编程 / java 阅读数: 100
收藏 0 赞 0 分享

前言

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环境,亲测可用,问题完美解决。

更多精彩内容其他人还在看

Spring boot将配置属性注入到bean类中

本篇文章主要介绍了Spring boot将配置属性注入到bean类中,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

Java正则判断日期格式是否正确的方法示例

这篇文章主要介绍了Java正则判断日期格式是否正确的方法,结合实例形式分析了Java针对日期字符串正则判断的相关操作技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

java Future 接口使用方法详解

这篇文章主要介绍了java Future 接口使用方法详解,Future接口是Java线程Future模式的实现,可以来进行异步计算的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Java 读取外部资源的方法详解及实例代码

这篇文章主要介绍了Java 读取外部资源的方法详解及实例代码的相关资料,经常有读取外部资源的要求,如配置文件等等需要读取,需要的朋友可以参考下
收藏 0 赞 0 分享

Java正则表达式之split()方法实例详解

这篇文章主要介绍了Java正则表达式之split()方法,结合实例形式较为详细的分析了split方法的功能、使用方法及相关注意事项,需要的朋友可以参考下
收藏 0 赞 0 分享

Java 存储模型和共享对象详解

这篇文章主要介绍了Java 存储模型和共享对象详解的相关资料,对Java存储模型,可见性和安全发布的问题是起源于Java的存储结构及共享对象安全,需要的朋友可以参考下
收藏 0 赞 0 分享

Java使用正则表达式实现找出数字功能示例

这篇文章主要介绍了Java使用正则表达式实现找出数字功能,结合实例形式分析了Java针对数字的匹配查找及非数字替换操作相关实现技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

Spring核心IoC和AOP的理解

本文主要介绍了Spring核心IoC和AOP的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
收藏 0 赞 0 分享

详解Spring AOP 拦截器的基本实现

本篇文章主要介绍了详解Spring AOP 拦截器的基本实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

Mybatis 中的一对一,一对多,多对多的配置原则示例代码

这篇文章主要介绍了 Mybatis 中的一对一,一对多,多对多的配置原则示例代码,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多