可以使用weindo.open(URL)直接打开,但考虑到体验用了blob,这里前端和后端有几个坑,先上代码
//批量下载
batchDownload() {
let _this = this;
console.log(this.$refs.selectedData.selection);
let sheetData = this.$refs.selectedData.selection;
if (sheetData.length > 0) {
let url = _this.BASEURL + "/DbCaseMgr/batchDownload";
let idList = [];
for (let i = 0; i < sheetData.length; i++) {
idList.push(sheetData[i]["C_ID"]);
}
let postData = { idList: idList };
_this.$axios
.post(url, postData, { responseType: "blob" })
.then(function(res) {
console.log(res);
let contentDisposition = res.headers["content-disposition"];
let fileName = decodeURIComponent(
contentDisposition.substring(contentDisposition.indexOf("=") + 1)
);
console.log("fileName=" + fileName);
_this.download1(res, fileName);
//window.open(url + "?filePath=" + filePath);
})
.catch(function(err) {
console.log(err);
});
} else {
_this.$message({
showClose: true,
message: "请选择至少一条数据",
type: "error"
});
}
download1(res, fileName) {
let blob = new Blob([res.data], { type: res.headers["content-type"] });
//let blob = new Blob([res.data]);
let a = document.createElement("a");
a.style.display = "none";
document.body.appendChild(a);
const url = window.URL || window.webkitURL || window.moxURL;
let link = url.createObjectURL(blob);
a.href = link;
a.download = fileName;
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(link);
},
后端
/**
* 批量下载
*
* @param response
*/
@PostMapping(value = "/batchDownload")
public void batchDownload(@RequestBody(required = true) HashMap<String, Object> paraMap, HttpServletResponse response) {
List<String> idList = (List<String>) (paraMap.containsKey("idList")? paraMap.get("idList") : new ArrayList<String>());
List<Map<String, Object>> caseList = dataClassifyTagService.queryCaseByIdList(idList);
// 存放--服务器上zip文件的目录
String directory = "F:/picture";
List<String> paths = new ArrayList<>();
List<String> names = new ArrayList<>();
for (Map<String, Object> map : caseList) {
paths.add((String) map.get("C_PHYSICAL_PATH"));
names.add((String) map.get("C_CASE_NAME"));
}
File directoryFile = new File(directory);
if (!directoryFile.isDirectory() && !directoryFile.exists()) {
directoryFile.mkdirs();
}
// 设置最终输出zip文件的目录+文件名
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
String zipFileName = formatter.format(new Date()) + ".zip";
String strZipPath = directory + "\\" + zipFileName;
ZipOutputStream zipStream = null;
FileInputStream zipSource = null;
BufferedInputStream bufferStream = null;
File zipFile = new File(strZipPath);
try {
// 构造最终压缩包的输出流
zipStream = new ZipOutputStream(new FileOutputStream(zipFile));
for (int i = 0; i < paths.size(); i++) {
// 解码获取真实路径与文件名
String realFileName = java.net.URLDecoder.decode(names.get(i), "UTF-8");
String realFilePath = java.net.URLDecoder.decode(paths.get(i), "UTF-8");
File file = new File(realFilePath);
// TODO:未对文件不存在时进行操作,后期优化。
if (file.exists()) {
zipSource = new FileInputStream(file);// 将需要压缩的文件格式化为输入流
/**
* 压缩条目不是具体独立的文件,而是压缩包文件列表中的列表项,称为条目,就像索引一样这里的name就是文件名,
* 文件名和之前的重复就会导致文件被覆盖
*/
ZipEntry zipEntry = new ZipEntry(realFileName);// 在压缩目录中文件的名字
zipStream.putNextEntry(zipEntry);// 定位该压缩条目位置,开始写入文件到压缩包中
bufferStream = new BufferedInputStream(zipSource, 1024 * 10);
int read = 0;
byte[] buf = new byte[1024 * 10];
while ((read = bufferStream.read(buf, 0, 1024 * 10)) != -1) {
zipStream.write(buf, 0, read);
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭流
try {
if (null != bufferStream)
bufferStream.close();
if (null != zipStream) {
zipStream.flush();
zipStream.close();
}
if (null != zipSource)
zipSource.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 判断系统压缩文件是否存在:true-把该压缩文件通过流输出给客户端后删除该压缩文件 false-未处理
if (zipFile.exists()) {
try {
download(response, zipFileName, strZipPath);
} catch (IOException e) {
e.printStackTrace();
}
zipFile.delete();
}
}
public void download(HttpServletResponse response, String filename, String path) throws IOException {
response.setCharacterEncoding("UTF-8");
if (filename != null) {
FileInputStream is = null;
BufferedInputStream bs = null;
OutputStream os = null;
try {
File file = new File(path);
if (file.exists()) {
// 设置Headers
response.setHeader("Content-Type", "application/octet-stream;charset=UTF-8");
// 设置下载的文件的名称-该方式已解决中文乱码问题
response.setHeader("Content-Disposition",
"attachment;filename=" + java.net.URLEncoder.encode(filename, "UTF-8"));
is = new FileInputStream(file);
bs = new BufferedInputStream(is);
os = response.getOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = bs.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
} else {
String error = "下载的文件资源不存在";
response.sendRedirect("error=" + error);
}
} finally {
if (is != null) {
is.close();
}
if (bs != null) {
bs.close();
}
if (os != null) {
os.flush();
os.close();
}
}
}
}
下面记录一下自己遇到的一些坑
1: // 设置Headers
response.setHeader(“Content-Type”, “application/octet-stream;charset=UTF-8”);
// 设置下载的文件的名称-该方式已解决中文乱码问题
response.setHeader(“Content-Disposition”,
“attachment;filename=” + java.net.URLEncoder.encode(filename, “UTF-8”));
这两点很重要
因为涉及到跨域的问题,前端可能获取不到content-disposition,需要在跨域设置的地方标记,跨域设置有两种方式,自行百度
2:前端使用了blob进行下载,正常情况下设置了blob的,axios会自动帮我们将文件流转化成blob,但前端的数据不一定都是blob
这种是错误类型
这是因为前端设置的responseType没有生效,困扰了很久,后来发现是因为前端的框架使用了mock.js,mock,js将请求拦截其内部将responseType置空,所以要先消除mock,不同的项目引用mock,js的方式和位置有所不同,需要自己找到配置文件注释.add(’@/mock’) 或者有的是require(’@/mock’),然后重启
这种是正确类型