Java实现批量下载(打包成zip)的实现
作者:LuckyWangxs 发布时间:2022-04-02 01:53:05
引言
批量下载思路,首先前端发送下载请求,携带必要参数,也可无参默认批量下载页面全部数据;后台接收后进行数据处理拿到要下载文件的下载地址,循环下载地址,用压缩流,将文件直接写入压缩包,最后利用文件下载将压缩包输出给前端。
一、前端JS发送下载请求
1、ajax无法发送下载请求
关于下载的常见需求无非就是点击按钮下载或者选中点击批量下载,点击下载或批量下载后,携带参数向后台发送下载请求,但是JS中的ajax无法触发浏览器的下载机制,这也是处于安全考虑,所以下载请求不可以通过发送ajax请求实现。
2、js发送下载请求:超链接方式
我们可以通过< a >标签实现,在a标签的href中拼接get请求并携带所需参数,如下
<a href="http://localhost:8080/download/?ids=123,234&fileName=down">下载</a>
批量下载,前端可以传每条数据的id,用逗号拼接成字符串,后台接收后进行数据处理,然后进行批量下载,但是此方式有局限性,如果我选中了很多条数据,每条数据的id都是32位UUID,那get请求无法携带大量参数,所以这种方式并不适合批量下载,只适合单条数据下载。
3、js发送下载请求:拼接Form表单,并提交
form表单也有局限性,例如form表单不能传输json格式的数据,也就是说用此方式提交,后台不能用@RequestBody注解
$('.download-btn').click(function () {
// 如果要传选中行的id,则从页面获取到所有id,可以拿逗号拼接,放到输入框传给后台
// 如果需要把选中行整行数据传到后台,form表单不支持传json格式数据,所以可以把
// 选中行数据放入数组,转为json放入输入框,后台用String接收,然后再转回Obj
var $dataForm = $(
"<form type='hidden' method='post'>" +
"<input type='hidden' id='ids' name='ids' value='" + ids + "' type='text'/>" +
"</form>"
);
$dataForm.attr("action", 'localhost:8080/download');
$(document.body).append($dataForm);
//提交表单,实现下载
$dataForm.submit();
});
如上边代码所示,传参为ids,那如果你想传obj,可以用JSON.stringify()将前端对象或数组类型转为json字符串,然后赋值给表单的输入框,一并提交给后台,后台用String接收,然后再转回Object,我在测试过程中 js提交数据到后台(json)," 被转译 成了& quot;,如果你也遇到,请看这篇文章:文章链接
二、后台处理
此处省略接收参数,获取需要下载的文件的url,直接写死模拟:
@RequestMapping(value = "/download", method = RequestMethod.POST)
public void plistDownLoad(HttpServletResponse response) throws Exception {
// 此处模拟处理ids,拿到文件下载url
List<String> paths = new ArrayList<>();
paths.add("C:\\Users\\E480\\Desktop\\Study\\casul笔记.txt");
paths.add("C:\\Users\\E480\\Desktop\\Study\\config配置中心笔记.txt");
paths.add("C:\\Users\\E480\\Desktop\\Study\\GateWay.txt");
if (paths.size() != 0) {
// 创建临时路径,存放压缩文件
String zipFilePath = "D:\\workspace-IDEA\\zip\\我的zip.zip";
// 压缩输出流,包装流,将临时文件输出流包装成压缩流,将所有文件输出到这里,打成zip包
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFilePath));
// 循环调用压缩文件方法,将一个一个需要下载的文件打入压缩文件包
for (String path : paths) {
// 该方法在下面定义
fileToZip(path, zipOut);
}
// 压缩完成后,关闭压缩流
zipOut.close();
//拼接下载默认名称并转为ISO-8859-1格式
String fileName = new String(("我的压缩文件.zip").getBytes(),"ISO-8859-1");
response.setHeader("Content-Disposition", "attchment;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();
}
}
将文件打包的方法,需要传一个压缩路径,和一个文件,一次只将一个文件写入压缩包
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();
// 压缩流不必关闭,使用完后再关
}
三、结束
我也是第一次接触批量下载,它本身并不难,都只是一些IO的常规操作,没有弯弯绕绕,只是在实现完整功能的过程中踩到了一些坑,在此记录一下,以便加深印象和帮助他人吧~~
来源:https://blog.csdn.net/qq_41563912/article/details/109592864


猜你喜欢
- springboot和vue结合的方案网络上的主要有以下两种:1. 【不推荐】在html中直接使用script标签引入vue和一些常用的组件
- 本文实例为大家分享了java * 实现在线人数统计的具体代码,供大家参考,具体内容如下1.在工程中创建监听类SessionListener
- 公司的老项目要改造多租户,于是进入了大坑,本文写点遇到的坑以及解决方案,每次遇到问题在网上搜了好久,记录下来,防止以后忘掉。(一).方案网上
- 随着现在分布式架构越来越盛行,在很多场景下需要使用到分布式锁。很多小伙伴对于分布式锁还不是特别了解,所以特地总结了一篇文章,让大家一文读懂分
- 最近做了一个功能,里面涉及到了渐变圆形的需求。就是一个颜色可以渐变的圆环,最后实现的效果如下图:左图是带渐变效果,右图是不带渐变效果。原理还
- 本文研究的主要是Java中finally和return的关系,具体介绍和实例如下所示。finally 和 return 关系的总结1.try
- 介绍今天我们将研究java中的Builder模式。Builder 设计模式是一种创造性的设计模式,如工厂模式和抽象工厂模式。当Object包
- 1 概念方面List是接口,ArrayList是List接口的一个实现类2 初始化方面2.1 List2.1.1 错误写 * ist list
- 欢迎大家来学习本节内容,前几节我们已经学习了其他几种自定义控件,分别是Andriod 自定义控件之音频条及 Andriod 自定义控件之创建
- 一个Resty项目包含的部分(resty-route):1. RestFilter像其他web框架一样,Resty也需要一个入口,在web.
- 本文实例汇总了Java各种排序算法。分享给大家供大家参考,具体如下:1. 冒泡排序:public class SortTest { pub
- Pull解析方法给应用程序完全的控制文档该怎么样被解析。Android中对Pull方法提供了支持的API,主要是org.xmlpull.v1
- 如下所示:public class 字符串常用操作 { public static void main(String[] arg
- CountDownLatch 是一个非常实用的多线程控制工具类。” Count Down ” 在英文中意为倒计数, Latch 为门问的意思
- Spark的算子的分类从大方向来说,Spark 算子大致可以分为以下两类:1)Transformation 变换/转换算子:这种变换并不触发
- 1、原理事务的概念想必大家都很清楚,其ACID特性在开发过程中占有重要的地位。同时在并发过程中会出现一些一致性问题,为了解决一致性问题,也出
- 本文实例讲述了C#使用windows服务开启应用程序的方法。分享给大家供大家参考。具体如下:使用windows服务开启应用程序,会遇到如下问
- 遇到的问题!注:自定义CommentGenerator的都知道通过实现CommentGenerator接口的一些不足,毕竟只是实现了Comm
- 本文实例讲述了C#转换日期类型的方法。分享给大家供大家参考。具体分析如下:如:将日期1999-5-31 11:20转换成 /Date(928
- 这篇文章主要介绍了SpringBoot使用Log4j过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需