先说全局,整体思想就是将mongodb中的文件循环取出并生成独立文件,将路径存入队列,处理完mongdb中的文件路径后,在方法末尾激活批量处理压缩文件的方法,将队列传给该方法,让其循环调用压缩方法将每个文件压缩进zip文件中,并将zip文件生成实体文件,待其以二进制流的形式传给浏览器后,删除本地zip压缩文件及mongodb中下载的各个文件。
Controller层写法
/**
* mongodb批量下载文件,并打成zip压缩包
*
* @param params id数组
* @param request 请求
* @param response 返回
*/
@PostMapping("/downloadZip")
@ApiLogAnnotation(
interfaceTypeCode = "downloadZip",
interfaceDescription = "mongodb批量下载文件,并打成zip压缩包")
public void downloadZipByMongodb(
@RequestBody Map<String, Object> params,
HttpServletRequest request,
HttpServletResponse response) {
try {
downloadMongodbService.downloadZipByMongodb(params, request, response);
} catch (Exception e) {
e.printStackTrace();
log.info("mongodb批量下载文件,并打成zip压缩包失败!");
}
}
service层写法
/**
* 批量下载并压缩
*
* @param params id数组
* @param request 请求
* @param response 返回
* @throws IOException io流异常
*/
void downloadZipByMongodb(
Map<String, Object> params, HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
Impl层写法
@Override
public void downloadZipByMongodb(
Map<String, Object> params, HttpServletRequest request, HttpServletResponse response)
throws Exception {
String ids = Optional.ofNullable(params).map(p -> p.get("ids")).orElse("").toString();
if (StringUtil.isBlank(ids)) {
response.setHeader("Content-Disposition", "");
} else {
List<String> paths = new ArrayList<>();
String filePath = request.getSession().getServletContext().getRealPath("");
String[] idList = ids.split(",");
/* 循环从mongodb下载文件*/
for (String id : idList) {
Query query = Query.query(Criteria.where("_id").is(id));
// 查询单个文件
GridFSFile gfsFile = gridFsTemplate.findOne(query);
if (gfsFile != null) {
GridFsResource gridFsResource =
new GridFsResource(
gfsFile,
GridFSBuckets.create(mongoDbFactory.getMongoDatabase())
.openDownloadStream(gfsFile.getObjectId()));
String fileName = gfsFile.getFilename().replace(",", "");
// 处理中文文件名乱码
if (request.getHeader("User-Agent").toUpperCase().contains("MSIE")
|| request.getHeader("User-Agent").toUpperCase().contains("TRIDENT")
|| request.getHeader("User-Agent").toUpperCase().contains("EDGE")) {
fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
} else {
// 非IE浏览器的处理:
fileName = new String(fileName.getBytes(), StandardCharsets.UTF_8);
}
String newfilePath = filePath + File.separator + fileName;
paths.add(newfilePath);
File file = new File(newfilePath);
copyInputStreamToFile(gridFsResource.getInputStream(), file);
}
}
plistDownLoad(paths, request, response);
}
}
/** 将GridFsResource转成File */
private static void copyInputStreamToFile(InputStream inputStream, File file) throws IOException {
try (FileOutputStream outputStream = new FileOutputStream(file)) {
int read;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
}
}
/** 批量压缩并下载 */
public void plistDownLoad(
List<String> paths, HttpServletRequest request, HttpServletResponse response)
throws Exception {
String filePath = request.getSession().getServletContext().getRealPath("");
if (paths.size() != 0) {
// 创建临时路径,存放压缩文件
String zipFilePath = filePath + File.separator + "我的zip.zip";
// 压缩输出流,包装流,将临时文件输出流包装成压缩流,将所有文件输出到这里,打成zip包
ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(Paths.get(zipFilePath)));
// 循环调用压缩文件方法,将一个一个需要下载的文件打入压缩文件包
for (String path : paths) {
// 该方法在下面定义
fileToZip(path, zipOut);
}
// 压缩完成后,关闭压缩流
zipOut.close();
// 拼接下载默认名称并转为ISO-8859-1格式
String fileName = new String(("我的压缩文件.zip").getBytes(), StandardCharsets.UTF_8);
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
// 该流不可以手动关闭,手动关闭下载会出问题,下载完成后会自动关闭
ServletOutputStream outputStream = response.getOutputStream();
FileInputStream inputStream = new FileInputStream(zipFilePath);
// 如果是SpringBoot框架,在这个路径
// org.apache.tomcat.util.http.fileupload.IOUtils产品
// 否则需要自主引入apache的 commons-io依赖
// copy方法为文件复制,在这里直接实现了下载效果
IOUtils.copy(inputStream, outputStream);
// 关闭输入流
inputStream.close();
// 下载完成之后,删掉这个zip包
File fileTempZip = new File(zipFilePath);
fileTempZip.delete();
/*循环删除mongodb的文件*/
for (String path : paths) {
File file = new File(path);
file.delete();
}
}
}
/** 单个文件压缩进zip文件 */
public static void fileToZip(String filePath, ZipOutputStream zipOut) throws IOException {
// 需要压缩的文件
File file = new File(filePath);
// 获取文件名称,如果有特殊命名需求,可以将参数列表拓展,传fileName
String fileName = file.getName();
FileInputStream fileInput = new FileInputStream(filePath);
// 缓冲
byte[] bufferArea = new byte[1024 * 10];
BufferedInputStream bufferStream = new BufferedInputStream(fileInput, 1024 * 10);
// 将当前文件作为一个zip实体写入压缩流,fileName代表压缩文件中的文件名称
zipOut.putNextEntry(new ZipEntry(fileName));
int length = 0;
// 最常规IO操作,不必紧张
while ((length = bufferStream.read(bufferArea, 0, 1024 * 10)) != -1) {
zipOut.write(bufferArea, 0, length);
}
// 关闭流
fileInput.close();
// 需要注意的是缓冲流必须关闭掉,否则输出无效
bufferStream.close();
// 压缩流不必关闭,使用完后再关
}