打包下载成.zip文件

项目背景

公司使用vue + SpringBoot实现批量下载功能

今天在调试批量下载这个功能。打包成.zip文件时,在返回给前端浏览器出现报错信息:

后端报错:

ERROR c.c.p.c.e.BusinessExceptionHandler - java.io.IOException: 你的主机中的软件中止了一个已建立的连接。

org.apache.catalina.connector.ClientAbortException: java.io.IOException: 你的主机中的软件中止了一个已建立的连接。

找了好久的错,发现浏览器的控制台有报错信息

Access to XMLHttpRequest at 'http://...:8097/pcsms-admin/batchExport/pdf?vids=1e7ed541bdd6b9f5614cca14623f8681,8dfda9f7151745ad5aa5f0abc2c55d5c' from origin 'http://..:8001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

于是在后端中设置响应体,如 HttpServletResponse response :

response.setHeader("Access-Control-Allow-Origin","*");

紧接着又出现如下的报错信息:

Access to XMLHttpRequest at 'http://...:8097/batchExport/pdf?vids=1e7ed541bdd6b9f5614cca14623f8681,8dfda9f7151745ad5aa5f0abc2c55d5c' from origin 'http://...:8001' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

在面向百度编程中,找到一个帖子有详细的解释--axios设置withCredentials导致“跨域”的解决方案。检查前端配置果然有:

axios.defaults.withCredentials = true;

(一) 当前端配置withCredentials=true时, 后端配置Access-Control-Allow-Origin不能为*, 必须是相应地址

(二) 当配置withCredentials=true时, 后端需配置Access-Control-Allow-Credentials

(三) 当前端配置请求头时, 后端需要配置Access-Control-Allow-Headers为对应的请求头集合

于是我们可以采取方法一:axios.defaults.withCredentials = false;

在找其他解决方法时,找到一个可以不更改前端配置的方法二--Jquery Ajax设置withCredentials解决跨域请求,在response里加上以下两个header

response.addHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
// response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.addHeader("Access-Control-Allow-Credentials","true");

最后,终于问题成功解决。

后端代码:

  1. TestController
@RequestMapping(value = "/batchExport/pdf", method = RequestMethod.POST)
public void batchExportPdf(HttpServletRequest request, HttpServletResponse response, @RequestParam("vids") String vids) throws Exception {
//获取uavFileId,不进行xss过滤
// HttpServletRequest orgRequest = XssHttpServletRequestWrapper.getOrgRequest(request);
// String ids = orgRequest.getParameter("vids");
String[] vid = vids.split(",");
byte[] data = sopService.batchExportPdf(vid); String fileName = URLEncoder.encode("批量下载PDF" + DateUtils.format(new Date(), "yyyyMMddHHmmss") + ".zip", "UTF-8"); response.reset();
// 当前端配置withCredentials=true时, 后端配置Access-Control-Allow-Origin不能为*, 必须是相应地址
response.addHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
// 这个若不起作用,使用下面的"FileName"的
// response.addHeader("Access-Control-Expose-Headers","*");
response.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
// 设置在下载框默认显示的文件名
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ";" + "filename*=utf-8''" + fileName);
response.setHeader("FileName", fileName);
// 让axios放行指定的响应头 https://blog.csdn.net/u012586326/article/details/125790079
response.addHeader("Access-Control-Expose-Headers","FileName");
// 写明文件大小
response.addHeader("Content-Length", "" + data.length);
// 指明response的返回对象是文件流
response.setContentType("application/octet-stream; charset=UTF-8");
response.setCharacterEncoding("UTF-8");
// 当前端配置withCredentials=true时, 后端需配置Access-Control-Allow-Credentials
response.addHeader("Access-Control-Allow-Credentials","true"); IOUtils.write(data, response.getOutputStream()); }
  1. TestService
    /**
* 批量下载pdf
* @param vids
* @return
*/
byte[] batchExportPdf(String[] vids) throws Exception;
  1. TestServiceImpl
    @Override
public byte[] batchExportPdf(String[] vids) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// 用于将数据压缩成Zip文件格式
ZipOutputStream zipOut = new ZipOutputStream(outputStream);
FileInputStream inputStream = null;
List<String> deletePdf = new ArrayList<>();
List<FileInputStream> in = new ArrayList<>();
try {
for (String vid : vids) {
// 下载到本地
// PdfDTO包含:pdfPath(本地PDF路径)、fileName(下载后的文件名(不含文件后缀.pdf))
PdfDTO dto = exportPdfByVid(vid);
if (!ObjectUtils.isEmpty(dto)) {
zipOut.putNextEntry(new ZipEntry((Objects.requireNonNull(dto.getFileName())) + ".pdf"));
inputStream = new FileInputStream(new File(dto.getPdfPath()));
int len;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1) {
zipOut.write(bytes, 0, len);
}
//关闭该zip文件中打开的项
zipOut.closeEntry();
deletePdf.add(dto.getPdfPath());
in.add(inputStream);
}
}
} catch (Exception e) {
log.error("批量下载时出现错误:" + e.toString());
throw new BusinessException("批量下载时出现错误:" + e.getMessage());
} finally {
try {
for (FileInputStream stream : in) {
stream.close();
}
// 关流
IOUtils.closeQuietly(zipOut);
} catch (IOException e) {
log.error("批量下载时流关闭异常:" + e.toString());
}
// 删除源文件(我这里是因为从数据服务器下载了文件到本地,所以删掉本地的)
File file = null;
for (String s : deletePdf) {
file = new File(s);
file.delete();
}
}
return outputStream.toByteArray();
}

参考:

https://blog.csdn.net/cckevincyh/article/details/81140443

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Allow-Origin

https://blog.csdn.net/baidu_28068985/article/details/105558280

https://blog.csdn.net/HermitSun/article/details/100797223


Java-如何打包下载成.zip文件的更多相关文章

  1. vue-webpack项目自动打包压缩成zip文件批处理

    为什么需要这个? 使用vue框架开发项目,npm run build这个命令会一直用到,如果需要给后端发包,那你还要打包成zip格式的压缩包,特别是项目提测的时候,一天可能要执行重复好几次,所以才有了 ...

  2. Vue -- webpack 项目自动打包压缩成zip文件

    这段时间用 Vue2.0 开发项目,每次打包都会用到 npm run build 命令,但是每次部署时给后端发包都要手动zip压缩,这样一两次还行,但遇到项目板块测试和临时加急功能测试的时候,一天可能 ...

  3. 使用 SharpZipLib 打包数据到 ZIP 文件

    SharpZipLib 是一个优秀的开源的第三方压缩库,可以通过这个库将一些导出的文件打包到一个 ZIP 文件当中供用户下载. GitHub 地址:https://github.com/icsharp ...

  4. Java使用基本JDK操作ZIP文件以及zip文件的加密、解密等功能

    Java使用基本JDK操作ZIP文件 http://blog.csdn.net/zhyh1986/article/details/7723649 Java解压和压缩带密码的zip文件 http://b ...

  5. Java实现打包下载BLOB字段中的文件

    概述 web项目的文件打包下载实现:servlet接收请求,spring工具类访问数据库及简化大字段内容获取,org.apache.tools.zip打包. 必要提醒:当前总结是继Java实现下载BL ...

  6. 十一、springboot 配置log4j2以及打包成zip文件

    前言 其实我们前面已经配置了日志,但是最近总感觉日志日志格式看的不舒服,并且每次打包都是一个jar 文件,lib都包含在jar 中,每次做很小的修改都需要重新替换jar文件,jar文件会比较大,传输起 ...

  7. c# 把网络图片http://....png 打包成zip文件

    思路: 1.把网络图片下载到服务器本地. 2.读取服务器图片的文件流 3.使用zip帮助类,把图片文件流写进zip文件流. 4.如果是文件服务器,把zip文件流 推送文件服务器,生成zip的下载url ...

  8. php将文件夹打包成zip文件

    function addFileToZip($path,$zip){    $handler=opendir($path); //打开当前文件夹由$path指定.    while(($filenam ...

  9. php打包文件夹成zip文件

    function addFileToZip($path,$zip){    $handler=opendir($path); //打开当前文件夹由$path指定.    while(($filenam ...

  10. java 实现Excel压缩成Zip导出

    1 概述 在web项目中常见的一种场景就是将文件导出为Excel,但是当需要导出多个Excel时,使用者将频繁操作,这样就严重降低了项目的友好交互性以及易用性,那么怎么才能优雅的解决这个问题呢?笔者今 ...

随机推荐

  1. day08-SpringMVC底层机制简单实现-04

    SpringMVC底层机制简单实现-04 https://github.com/liyuelian/springmvc-demo.git 8.任务7-完成简单视图解析 功能说明:通过目标方法返回的 S ...

  2. 学习Java Day24

    今天明白了 一.面向对象(面向过程) 1. 面向对象 找对象(封装了过程)来干. 例如:洗衣服(洗衣机就是对象). 2. 面向对象思想特点 是一种更符合我们思想习惯的思想. 可以将复杂的事情简单化.  ...

  3. 基于Vue3+TS的Monorepo前端项目架构设计与实现

    写在前面 你好,我是前端程序员鼓励师岩家兴!去年在另一个项目https://juejin.cn/post/7121736546000044046中,我向读者朋友们介绍了结合npm包管理工具yarn作v ...

  4. 郁金香 fs寄存器

    为什么我们在追eax要挂主线程呢,这是因为它的数据来源在fs中 004D1000 为什么是这个呢 $ ==> 0392FFDC 指向SEH链表指针 $+4 03930000 线程堆栈顶部(地址最 ...

  5. (原创)【B4A】一步一步入门04:编译模式、打包为APK、私钥签名

    一.前言 上篇 (原创)[B4A]一步一步入门03:APP名称.图标等信息修改 中我们将APP做成了标准的样子. 本篇文章会讲解如何将程序打包成APK文件以分发,同时讲解如何制作私钥并签名APP,以用 ...

  6. [学习笔记]SQL server完全备份指南

    方式一,使用SQL Server Management Studio 准备工作 连接目标数据库服务器 在目标数据库上右键->属性,将数据库的恢复模式设置为"简单",兼容级别设 ...

  7. JZOJ 4250.路径

    \(\text{Solution}\) \(30\) 分暴搜合法路径 另 \(30\) 分状压 设 \(f_{i,j,k}\) 表示当前到第 \(i\) 个点,走过的点状态为 \(j\),走过的路径长 ...

  8. Vue 关键概念介绍

    Vue现在已经迭代到 3+ 版本,阅读官方文档的过程中发现作者的一些理念和思路很合我口味,很多概念与方案都是基于解决实际问题提出并实现的,且在权衡利弊后勇于打破常规,比如如何看待关注点分离?.可见,V ...

  9. STM32L4 Keil ST-Link 连接失败

    ST-LINK 连接失败的因素,以我个人的经历而言有两种:一个是驱动问题,一个是插线问题.连接正常的情况如下图所示,SWDIO 能显示你的设备信息: 注意使用 SW 端口,JTAG 端口导致无法识别设 ...

  10. 轻量级CI/CD发布部署环境搭建及使用_04_docker安装nexus3

    轻量级CI/CD发布部署环境搭建及使用_04_配置宿主机的环境:jdk.maven.node.pythod2 尽自己的绵薄之力,为开源技术分享添砖加瓦   1,搜索nexus3 docker sear ...