乌市泽哥 发表于 2023-7-3 19:29:44

解决Springboot项目打成jar包后获取resources目录下的文件失败的问题

前几天在项目读取resources目录下的文件时碰到一个小坑,明明在本地是可以正常运行的,但是一发到测试环境就报错了,说找不到文件,报错信息是:class path resource 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;
      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包

https://img2023.cnblogs.com/blog/685402/202307/685402-20230703200421755-1207921988.png
命令执行成功后再target目录下就生成了jar包
https://img2023.cnblogs.com/blog/685402/202307/685402-20230703200421807-494167064.png
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执行成功如下
https://img2023.cnblogs.com/blog/685402/202307/685402-20230703200422174-1748243348.png
3、添加远程调试

依次点击菜单Run,点击Edit Configurations,点击+,点击Remote JVM Debug,端口后改成刚刚设置的9992。
https://img2023.cnblogs.com/blog/685402/202307/685402-20230703201156670-1122550842.png
4、请求接口

请求测试接口,9991是项目原来的端口
127.0.0.1:9991/test/getResource
5、请求结果

请求果然报错了,报错和之前测试环境的报错一摸一样。其实我们通过这个报错已经可以大致上看出问题了。。。
https://img2023.cnblogs.com/blog/685402/202307/685402-20230703200421825-1102769233.png
6、断点调试

在请求的入口打上断点开始断点调试
https://img2023.cnblogs.com/blog/685402/202307/685402-20230703200421904-345094120.png
通过断点调试也可以看到这个文件地址在原来的地址/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。
https://img2023.cnblogs.com/blog/685402/202307/685402-20230703200422308-529659963.png
然后在后面一段代码中,resourceUrl.getProtocol()的返回结果是"jar"而不是"file",被判定为不是文件然后抛出了一个FileNotFoundException异常。
https://img2023.cnblogs.com/blog/685402/202307/685402-20230703200422242-713301572.png
https://img2023.cnblogs.com/blog/685402/202307/685402-20230703200422058-403556369.png
三、解决方法

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;
InputStream inputStream = resource.getInputStream();
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 解决Springboot项目打成jar包后获取resources目录下的文件失败的问题