SpringBoot实现下载文件以及前台应当如何对接
SpringBoot实现文件下载以及前台对接方案
文件的下载返回:
这里用了一个ResponseEntity实体进行数据返回(当时就是不知道用什么对象返回文件,所以很恶心)。
请求头使用Content-Disposition,fileName标记返回时的文件名称;
ContentType使用octer-stream;
ContentLength...可以选择不填,长度如果填错了会报错
Body,返回文件的InputStream流
fun downloadFile(@RequestBody fileId: Int): ResponseEntity<InputStreamResource> {
val dest = fileService.getDownloadFile(fileId)
return ResponseEntity.ok()
.header("Content-Disposition", "attachment;filename=" + dest.name)
.contentType(MediaType.parseMediaType("application/octet-stream"))
.contentLength(dest.length())
.body(InputStreamResource(dest.inputStream()))
}
当然,我还看到了一种字节流的下载方式,也挺有趣的,但是用了之后好像出了点问题,就没用了(可行,但是数据不对)。
文件接收(百度用的一套代码)
let filename = new Date().getTime().toString() + '.zip'
let blob = new Blob([await downloadFile(res.data.data).data], { type: 'application/force-download' }) // 接收的是blob,若接收的是文件流,需要转化一下
if (typeof window.chrome !== 'undefined') {
// Chrome version
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = filename
link.click()
// console.log(link)
} else if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE version
let blob = new Blob([data], { type: 'application/force-download' })
window.navigator.msSaveBlob(blob, filename)
} else {
// Firefox version
let file = new File([data], filename, { type: 'application/force-download' })
window.open(URL.createObjectURL(file))
}
虽然做出来了,但是很多地方都不完美,我遇到了一堆非常恶心的事情:
因为这个是一个接口请求,只有请求完全结束(文件已经被下载下来之后),下载的文件才会突然显示。
这并不符合我的预期,也是一个非常糟糕的交互。
结局思路:
- 创建文件链接
- 开放文件下载接口,靠token和filepath进行下载
Q&A
为什么要写这篇文章
- 作为一条孤龙来说,所有的解决方案都是自己去一点点翻查的。然后,网上居然一点类似的文章都没有!!
参考文章&视频
- https://www.bilibili.com/video/BV1As411s77T?from=search&seid=7435414762924071490 - SpringBoot返回文件
- https://segmentfault.com/a/1190000015852421 - 前端对接下载文件
适用人群:一些和我一样不喜欢走按部就班的学习路径,选择自学,且只看目录的人们。。。
后来用了接口的形式实现了不跳转界面的下载(瞬间跳转一下,然后自动关上的那种,我有一个可以优化的思路,无需跳转的,等下次完成了断点下载功能的时候一起更新了)