解决Springboot项目打成jar包后获取resources目录下的文件失败的问题
前几天在项目读取resources目录下的文件时碰到一个小坑,明明在本地是可以正常运行的,但是一发到测试环境就报错了,说找不到文件,报错信息是:class path resource [xxxx] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:xxxx.jar!/BOOT-INF/classes!xxxx。
看了半天代码感觉没有问题,于是怀疑是打成项目jar包后和原项目存在差异导致的。于是我把的项目打成jar包,在本地直接调试jar,果然发现问题所在。下面我将以一个自己的测试项目api-test替代原来的公司项目来讲述一下排查过程。
一、项目代码
GetResourceTest:
public class GetResourceTest {
public InputStream getResource1() throws IOException {
File file = new DefaultResourceLoader().getResource("/template/qiankuan.ftl").getFile();
return Files.newInputStream(file.toPath());
}
public InputStream getResource2() throws IOException {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("/template/qiankuan.ftl");
Resource resource = resources[0];
return resource.getInputStream();
}
}
TestController:
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping(value = "/getResource")
@ResponseBody
public void getResource() throws IOException {
GetResourceTest getResourceTest = new GetResourceTest();
getResourceTest.getResource1();
}
}
二、排查过程
1、首先使用Maven的install命令将项目打成jar包

命令执行成功后再target目录下就生成了jar包

2、在Termininal里cd到target目录下,然后执行下面的代码,9992可以替换成其他端口
java -jar -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9992 api-test-1.0.0-SNAPSHOT.jar
执行成功如下

3、添加远程调试
依次点击菜单Run,点击Edit Configurations,点击+,点击Remote JVM Debug,端口后改成刚刚设置的9992。
4、请求接口
请求测试接口,9991是项目原来的端口
127.0.0.1:9991/test/getResource
5、请求结果
请求果然报错了,报错和之前测试环境的报错一摸一样。其实我们通过这个报错已经可以大致上看出问题了。。。

6、断点调试
在请求的入口打上断点开始断点调试

通过断点调试也可以看到这个文件地址在原来的地址/template/qiankuan.ftl 前拼接了jar:file:/D:/Project/test/fhey-test/api-test/target/api-test-1.0.0-SNAPSHOT.jar!/BOOT-INF/classes!成为了jar:file:/D:/Project/test/fhey-test/api-test/target/api-test-1.0.0-SNAPSHOT.jar!/BOOT-INF/classes!/template/qiankuan.ftl。

然后在后面一段代码中,resourceUrl.getProtocol()的返回结果是"jar"而不是"file", 被判定为不是文件然后抛出了一个FileNotFoundException异常。


三、解决方法
ResouceUtils.getFile()是专门用来加载非压缩和Jar包文件类型的资源,所以它根本不会去尝试加载Jar中的文件,要想加载Jar中的文件,只要用可以读取jar中文件的方式加载即可,比如 可以采用ClassPathResource这种以流的形式读取文件的方式或者PathMatchingResourcePatternResolver来读取文件。
ClassPathResource classPathResource = new ClassPathResource("/template/qiankuan.ftl" );
InputStream inputStream = classPathResource.getInputStream();
或者
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("/template/qiankuan.ftl");
Resource resource = resources[0];
InputStream inputStream = resource.getInputStream();
解决Springboot项目打成jar包后获取resources目录下的文件失败的问题的更多相关文章
- SpringBoot项目打成jar包后上传文件到服务器 目录与jar包同级问题
看标题好像很简单的样子,但是针对使用jar包发布SpringBoot项目就不一样了.当你使用tomcat发布项目的时候,上传文件存放会变得非常简单,因为你可以随意操作项目路径下的资源.但是当你使用Sp ...
- 解决springboot项目打成jar包部署到linux服务器后上传图片无法访问的问题
前言:目前大三,自己也在学习和摸索的阶段.在和学校的同学一起做前后端分离项目的时候,我们发现将后端打包成jar,然后部署到服务器中通过java -jar xxx.jar运行项目以后,项目中存在文件上传 ...
- springboot项目打成jar包,启动指定外部的yml文件
java -jar xxx.jar --spring.config.local=application.yml
- 【转载】JAVA SpringBoot 项目打成jar包供第三方引用自动配置(Spring发现)解决方案
JAVA SpringBoot 项目打成jar包供第三方引用自动配置(Spring发现)解决方案 本文为转载,原文地址为:https://www.cnblogs.com/adversary/p/103 ...
- SpringBoot项目打成Jar包时运行
使用java -jar ***.jar执行jar包的时候,会找jar包中的main()方法. 对于SpringBoot项目的Jar包,在META-INF目录下的MANIFEST.MF文件中,Main- ...
- spring boot 打jar包,获取resource路径下的文件
前言:最近在spring boot项目静态类中获取resource路径下文件,在idea中启动都可以获取,但是打包后变成了jar包 就无法获取到. 我想到了两种方法,一种是根据http访问静态资源比如 ...
- JAVA SpringBoot 项目打成jar包供第三方引用自动配置(Spring发现)解决方案
本项目测试环境 JDK: 1.8 SpringBoot: 2.1 需求描述 当我们想要利用SpringBoot封装一套组件并发布给第三方使用时,我们就不得不考虑我们的组件能否被使用者正确引入使用,此处 ...
- springboot项目打成jar包后台运行在linux上
背景:springboot2为为主体搭建的项目,直接打成jar包,上传到linux上面 启动项目:java -jar xx.jar 这样很方便,但是不能关闭窗口,否则项目就停了 后台启动: nohup ...
- eclipse中,将springboot项目打成jar包
1.右击项目,选择Run As - Maven clean 2.右击项目,选择Run As - Maven install 3.成功后 会在项目的target文件夹下生成jar包 4.将打包好的jar ...
- idea将springboot项目打成jar包
1.首先,找到pom.xml,把下面的build块中的内容改成如下所示 <build> <plugins> <plugin> <groupId>org. ...
随机推荐
- 随机模块random os模块 序列化模块
random: 验证码的实现: choice是选择列表中任意一个 ##记得把randint取出来的数字转化成str类型,要不就会相加 ##cha()是把asc编码表里的数字转化成字符 更进一步做成函数 ...
- Linux:进程模型和进程管理
1 进程与程序 在Linux系统中,执行一个程序或命令就可以触发一个进程,系统会给予这个进程一个ID,称为PID,同时根据触发这个进程的用户与相关属性关系,基于这个PID一组有效的权限设置.如下图所示 ...
- YII2.0的文件上传, 并把文件名称重新编译
/** *@Action 文件上传示例 *@这里我们演示的是一个YII2.0的文件上传, 并把文件名称重新编译 *@我们上传的是一个叫 photo 的jpg和png格式的文件 */ Controlle ...
- VUE3企业级项目基础框架搭建流程(3)
VUE-Router npm install vue-router@4 安装完成后,在项目目录里新建一个router文件,我这里的用的是typeScript,所以建立的是router.ts, 该文件是 ...
- 教练!我不想遍历了!——用bool运算有效减少dataframe的时间复杂度
方法参考:python - 降低python for循环的时间复杂度 - 堆栈内存溢出 (stackoom.com) 朋友们,朋友们,事情是这样的. 这几天博主在处理数据的时候遇到了这样的标注数据: ...
- Mysql查询执行报错Packet for query is too large (6,831,159 > 4,194,304)
根据意思可以看出 mysql执行的报文过大.需要我们设置允许的最大报文max_allowed_packet: org.springframework.dao.TransientDataAccessRe ...
- windows下MinGW编译ffmpeg
windows下MinGW编译ffmpeg 1.官网下载MinGW并安装 1)下载 ,下载网址: https://sourceforge.net/projects/mingw/files/ ...
- 关于 import 和 import static
import 嘛,就是导包.比如说java的一些自带的包,例如 import java.lang.Matn: 又或者我们自己做的包,例如 import com.link.testImport; 一些实 ...
- linux安装tomcat,mysql
环境:centos7.6 ssh连接工具:tabby 安装tomcat 创建目录 mkdir /opt/tomcat 获取tomcat: 1.自己百度下载 2.我这里提供百度网盘 链接:https:/ ...
- PaddlePaddle 飞桨复现 ResNet34
import paddle.nn as nn class ResidualBlock(nn.Layer): def __init__(self, in_channels, out_channels, ...