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里面。