• SpringBoot项目打包成jar后,使用ClassPathResource获取classpath(resource)下文件失败


    我在读取邮件模板的时候,本地测试使用ClassPathResource都可以正常读取,但打包成jar包传到服务器上就无法获取了,报错信息是: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,话不多说,先看正确的获取方法:使用PathMatchingResourcePatternResolver。

    String txt = "";
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    Resource[] resources = resolver.getResources("templates/layout/email.html");
    Resource resource = resources[0];
    //获得文件流,因为在jar文件中,不能直接通过文件资源路径拿到文件,但是可以在jar包中拿到文件流
    InputStream stream = resource.getInputStream();
    StringBuilder buffer = new StringBuilder();
    byte[] bytes = new byte[1024];
    try {
        for (int n; (n = stream.read(bytes)) != -1; ) {
            buffer.append(new String(bytes, 0, n));
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    txt = buffer.toString();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    然后,想知道更多的咱们就继续看看是怎么回事,如果只是为了解决问题,那就可以忽略下面的内容了。

    为了老夫好奇的心,我们继续探索下去,到底是怎么回事?我们先看看之前的代码:

    String txt = "";
    Resource resource = new ClassPathResource("templates/layout/email.html");
    txt = fileUtil.readfile(resource.getFile().getPath());
    
    • 1
    • 2
    • 3

    其实这是一个jar包发布的大坑,相信很多小伙伴遇到了读取文件的问题,其实使用getFile()的时候的坑,为了弄明白到底是咋回事,我进行了跟踪,结果返回的是一个Jar协议地址:jar:file:/xxx/xx.jar!/xxxx。

    然后继续跟踪到org.springframework.util.ResourceUtils#getFile(java.net.URL, java.lang.String)中,有如下的判断:

    public static File getFile(URL resourceUrl, String description) throws FileNotFoundException {
        Assert.notNull(resourceUrl, "Resource URL must not be null");
        if (!"file".equals(resourceUrl.getProtocol())) {
            throw new FileNotFoundException(description + " cannot be resolved to absolute file path because it does not reside in the file system: " + resourceUrl);
        } else {
            try {
                return new File(toURI(resourceUrl).getSchemeSpecificPart());
            } catch (URISyntaxException var3) {
                return new File(resourceUrl.getFile());
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    因为resourceUrl.getProtocol()不是file,而是 jar,这样就抛出了一个FileNotFoundException异常。

    ResouceUtils.getFile()是专门用来加载非压缩和Jar包文件类型的资源,所以它根本不会去尝试加载Jar中的文件,要想加载Jar中的文件,只要用可以读取jar中文件的方式加载即可,比如 xx.class.getClassLoader().getResouceAsStream()这种以流的形式读取文件的方式,所以使用读取文件流就可以拿到了。

    解决方案一:在jar包中使用文件流读取。

    ExcelWriter excelWriter = EasyExcel.write(httpResponse.getOutputStream())
                    .withTemplate(new ClassPathResource("templates/excel/b2cSaleOrder/OrderListExportTemplate.xlsx").getInputStream())
                    .build();
                WriteSheet writeSheetOne = EasyExcel.writerSheet("Sheet1").build();
                excelWriter.fill(listOne, writeSheetOne);
                excelWriter.finish();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    解决方案二:通过指定类所在的目录来指定模板所在根路径

    String fontPath = new ClassPathResource("/fonts/", FontUtil.class.getClassLoader()).getFile().getPath();
    或
    String templatePath = new ClassPathResource("/templates/excel/b2cSaleOrder/OrderListExportTemplate.xlsx", FontUtil.class.getClassLoader()).getFile().getPath();
    
    • 1
    • 2
    • 3

    参考文章1:SpringBoot项目打包成jar后读取文件的大坑,使用ClassPathResource获取classpath下文件失败 - Posts - 任霏的博客

    参考文章2:打包成jar后读取文件的大坑:使用ClassPathResource获取classpath下文件失败_赶路人儿的博客-CSDN博客

    参考文章3:freemaker模板位置ClassTemplateLoader的绝对路径相对路径设置方法_机械手学Java的博客-CSDN博客_freemarker 模板路径

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    408数据结构算法题目
    Swing布局 - SpringLayout
    【2023年11月第四版教材】软考高项极限冲刺篇笔记(2)
    Webshell详解
    低温温度传感器类型
    腾讯云轻量应用服务器性能如何?来自学生的评价
    太阳直散追踪器
    快递查询|阿里云实现调用API接口
    C++-JSON
    MediaCodec原理与流程(重生之我要成为音视频开发大腕)
  • 原文地址:https://blog.csdn.net/m0_67392126/article/details/126115984