[业务场景]
前端上传附件到后端指定文件夹 /static/images 中,前端请求下载附件。
由于上传附件的名称和真实存放文件名称不一致,前端直接通过文件名请求下载的名字是随机生成的UUID名,对用户非常不友好。
因此,应当使用后端以文件流的形式返回下载。
[后端] Spring Boot 以文件流的形式返回
/*
* 根据文件名进行文件下载
* */
@GetMapping("/download")
public void fileDownload(String fileName, String fileNameUid, HttpServletResponse response) throws IOException {
System.out.println("=======/column/download=======");
System.out.println(fileName);
System.out.println(fileNameUid);
// 去数据库找真实文件名
String realFileName = "20210328165114_79d30e1033fb4a6d9c8c572039e7c142.jpg";
String downloadUrl = ResourceUtils.getURL("classpath:").getPath() + "\\static\\images";
// 获取文件输入流
FileInputStream fileInputStream = new FileInputStream(new File(downloadUrl, realFileName));
// 附件下载
response.setContentType("application/x-download;charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); // 下载返回的是文件原始名称
// 获取响应输出流
ServletOutputStream outputStream = response.getOutputStream();
// 文件拷贝
IOUtils.copy(fileInputStream, outputStream);
IOUtils.closeQuietly(fileInputStream);
IOUtils.closeQuietly(outputStream);
}
[前端] Vue请求文件下载
#1-> 直接用<a>标签请求下载
<a href="http://localhost:8080/column/download?fileName=下载.jpg" methods="get">下载附件</a>
原生的<a>样式太丑,可以用下面的方式进行封装,底层机制是一样的。
<el-link icon="el-icon-download" @click="downloadFile(file.acc_name, file.acc_name_uid)">{{ file.acc_name }}</el-link>
async downloadFile (fileName, fileNameUid) {
const a = document.createElement('a')
a.href = 'http://localhost:8080/column/download?fileName=' + fileName + '&fileNameUid=' + fileNameUid
a.click()
}
#2-> axios-GET请求
// 下载文件
async downloadFile (fileName, fileNameUid) {
console.log(fileName + ' ' + fileNameUid)
const { data: res } = await this.$http.get('/column/download', {
params: {
fileName: fileName,
fileNameUid: fileNameUid
},
responseType: 'blob' // 必须注明blob方式返回
})
console.log('======= /column/download =======')
console.log(res)
const url = window.URL.createObjectURL(new Blob([res]))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', '下载.jpg') // 下载文件的名称及文件类型后缀
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
参考