目录
流的方式
后端代码
前端代码
其他几种方式
网上寻觅半晌,发现解决方案很多,但是能够满足要求的寥寥无几。
我需要做的是能够下载文件并且能够在后端指定文件名,In fact, It's very easy! e ha。
方式较多,可以直接取controller方法中的response对象
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); if (attributes instanceof ServletRequestAttributes) { HttpServletResponse response = ((ServletRequestAttributes) attributes).getResponse();
//将文件中文编码为字母数字,在前端获取后进行解码
String fileName = URLEncoder.encode(fileName, "UTF-8");
//让前端获取自定义的响应头(Attachment-Name)
response.setHeader("Access-Control-Expose-Headers","Attachment-Name");
response.setHeader("Attachment-Name", fileName + ".xlsx");
@PostMapping("/goods/saleInfo/export")
public void exportExcel(@RequestBody SaleInfoDto saleInfoDto) {
//TODO:根据参数请求数据
//TODO:设置响应头
//TODO:设置响应体
//TODO:刷新并关闭响应数据流
}
@Data
class SaleInfoDto{
private String area;
}
var params = {
area:'河南'
}
var url = "/goods/saleInfo/export";
this.$http.post(url, params, {
responseType: "arraybuffer"
}).then(function (response) {
console.log(response);
if ((response.ok = true)) {
//获取自定义文件名
var fileName = response.headers.map["attachment-name"][0];
//生成Blob对象,通过创建的a标签点击下载
var objectUrl = URL.createObjectURL(new Blob([response.data]));
var link = document.createElement("a");
console.log(link);
link.download = decodeURIComponent(fileName);
link.href = objectUrl;
link.click();
} else {
this.$message({
type: "info",
message: "下载响应异常"
});
}
}).catch(function (error) {
console.log(error);
this.$message({
type: "info",
message: "下载出现异常"
});
});
(responseType: "arraybuffer")如果不加的话依然可以下载下来文件,但是发现会比实际的文件大几kb,并且 文件打不开!
(decodeURIComponent(fileName);)将后端编码后的文件名解码为真实的文件名,可以有效防止中文乱码。
var url = "/goods/saleInfo/export";
this.$http.get(url,{
params: params,
responseType: "arraybuffer"
}).then(function (response) {
...................................
@GetMapping("/goods/saleInfo/export")
public void exportExcel(SaleInfoDto saleInfoDto) {
//TODO:根据参数请求数据
//TODO:设置响应头
//TODO:设置响应体
//TODO:刷新并关闭响应数据流
}
let url = "/goods/saleInfo/export?area=河南"
let iframe = document.createElement('iframe')
iframe.src = url
iframe.style.display = 'none'
document.body.appendChild(iframe)
let url = "/goods/saleInfo/export?area=河南"
let link = document.createElement('a')
link.href = url
link.style.display = 'none'
document.body.appendChild(link)
link.click()
let url = "/goods/saleInfo/export?area=河南"
window.open(url, '_blank');
无论上面的哪种方式,其原理是类似的,相当于由浏览器来直接解析响应头和响应数据流。此时response响应头信息配置如下:
String tmpFileName = fileName == null ? "export" : new String(fileName.getBytes("gbk"), "iso8859-1");
response.setHeader("Content-Disposition", "attachment; filename=" + tmpFileName + ".xlsx");
response.setContentType("multipart/form-data");