本文叙述
注: 本文中使用到的PdfUtil工具类暂不提供自行剔除
本文用于多个文件批量下载,提供两种下载方式 (二者利弊自行考量)
1. 将文件文件全部下载到本地文件夹,之后将文件夹打包成zip最后输出到浏览器再删除文件夹跟zip文件利用本地磁盘作为过渡
2. 直接在代码中拿到全部文件的byte[]数组之后,将文件的byte[]数组全部装入zip文件流,最后将zip文件流输出到浏览器,全过程不产生实体文件到磁盘中。
前端调用方式: 前端调用接口方式本文是直接通过 window.location.href 方式调用接口地址 或通过以下js方式调用本文不做叙述自行了解其他方式以下提供案例代码
js文件
import axios from 'axios'
import { getToken } from '@/utils/auth'
const mimeMap = {
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
zip: 'application/zip'
}
const baseUrl = process.env.VUE_APP_BASE_API //接口前缀换成自己的
export function downLoadZip(str, filename) {
var url = baseUrl + str
axios({
method: 'get',
url: url,
responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() }
}).then(res => {
resolveBlob(res, mimeMap.zip)
})
}
/**
* 解析blob响应内容并下载
* @param {*} res blob响应内容
* @param {String} mimeType MIME类型
*/
export function resolveBlob(res, mimeType) {
const aLink = document.createElement('a')
var blob = new Blob([res.data], { type: mimeType })
// //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
var contentDisposition = decodeURI(res.headers['content-disposition'])
var result = patt.exec(contentDisposition)
var fileName = result[1]
fileName = fileName.replace(/\"/g, '')
aLink.href = URL.createObjectURL(blob)
aLink.setAttribute('download', fileName) // 设置下载文件名称
document.body.appendChild(aLink)
aLink.click()
document.body.appendChild(aLink)
}
在具体页面模块引入该文件的downLoadZip 方法
import { downLoadZip } from "@/utils/zipdownload";
在具体事件上调用下载方法
handleGenTable(row) {
downLoadZip("传入接口路径从controller层开始填写" , "zip文件名称");// 例如downLoadZip("/test/downLoadZip", "test");
}
以下附上后端代码
下载工具类
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.OSSObject;
import com.nuoer.common.utils.aliyun.CloudConstant;
import com.nuoer.common.utils.pdf.PdfUtil;
import com.nuoer.project.cv.domain.SkillCert;
import com.nuoer.project.personalCenter.domain.MineDto;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
/**
* 文件下载类
* 本类提供两种多线程批量下载方式
* 方式一 : 实体文件储存到本地磁盘后输出到浏览器
* 方式二: 直接处理远程拉取到的文件流byte[] 数组后输出到浏览器
*/
public class DownloadUtil {
private static Logger logger = LoggerFactory.getLogger(DownloadUtil.class);
/**
* 下载线程数
*/
private static final int DOWNLOAD_THREAD_NUM = 14;
/**
* 下载线程池
*/
private static ExecutorService downloadExecutorService = ThreadUtil
.buildDownloadBatchThreadPool(DOWNLOAD_THREAD_NUM);
/**
* 创建文件夹,如果文件夹已经存在或者创建成功返回true
*
* @param path
* 路径
* @return boolean
*/
private static boolean createFolderIfNotExists(String path) {
String folderName = getFolder(path);
if (folderName.equals(path)) {
return true;
}
File folder = new File(getFolder(path));
if (!folder.exists()) {
synchronized (DownloadUtil.class) {
if (!folder.exists()) {
return folder.mkdirs();
}
}
}
return true;
}
/**
* 获取文件夹
*
* @param path
* 文件路径
* @return String
*/
private static String getFolder(String path) {
int index = path.lastIndexOf("/");
return -1 != index ? path.substring(0, index) : path;
}
/**
* 获取最后一个元素
*
* @param size
* 列表长度
* @param index
* 下标
* @return int
*/
private static int getLastNum(int size, int index) {
return index > size ? size : index;
}
/**
* 获取划分页面数量
*
* @param size
* 列表长度
* @return int
*/
private static int getPageNum(int size) {
int tmp = size / DOWNLOAD_THREAD_NUM;
return size % DOWNLOAD_THREAD_NUM == 0 ? tmp : tmp + 1;
}
/**
* 通过http请求获取远程文件信息 文件下载
*
* @param fileUrl
* 文件url,如:<code>https://i