SpringBoot 打jar包如何解决静态文件下载问题


1.问题

SpringBoot项目需要下载一个静态模板文件 demo.xlsx,这个文件放在 resources/static/excel/demo.xlsx 目录下面。但是项目是以 jar 包的形式线上运行。而jar包作为压缩包是无法直接获取的。只能获取其中的流InputStream,而无法获取 File类型,而文件下载时又需要 response.addHeader("Content-Length",String.valueOf(file.length()));否则文件下载会报错,尝试修复。如下图所示

所以二者相悖,然后搜索到虽然 stream.available() 也是可以获取预估的文件大小,但是对于网络下载的文件并不十分准确,受到网络影响很大。而且其返回的是 int类型(-2,147,483,648,2,147,483,647),所以最大也就是 214M的大小,而file.length()返回的是long类型。

综上所述,搜了一上午,基本上帖子都没什么用,直到我搜到下面这个解决办法,它总结了诸多问题,然后给出一个非常好的解决办法,见下面。

2.解决办法

主要就是参考 spring boot中Excel文件下载踩坑大全 感谢大佬。解决思路就是使用 spring提供的工具类FileCopyUtils.copyToByteArray 一劳永逸的解决问题,适用于小文件下载。所以我最后的下载工具类代码是如下:

public static HttpServletResponse downloadFile(HttpServletResponse response, String fileName) {
    InputStream inputStream = null;
    OutputStream outputStream = null;
    try {
        // 直接获取流
        inputStream = FileUtil.class.getClassLoader().getResourceAsStream("static/excel/" + fileName);
        response.setContentType("application/octet-stream");
        String name = java.net.URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + java.net.URLDecoder.decode(name, "ISO-8859-1") );
        outputStream = response.getOutputStream();
        if( inputStream != null) {
            // 调用工具类
            byte[] results = FileCopyUtils.copyToByteArray(inputStream);
            outputStream.write(results);
            outputStream.flush();
        }
    } catch (IOException e) {
        log.error("文件下载失败, e");
    }
    finally {
        IOUtils.closeQuietly(outputStream);
        IOUtils.closeQuietly(inputStream);
    }
}

需要明确的是:对于下载,不需要返回值。因为,本身就已经把数据输入到response里面。