java接口下载zip,不生成中间文件,返回前端文件流

java接口下载zip,不生产中间文件,返回前端文件流

    • 程序设计:
    • 代码实现:

程序设计:

前端向后端请求zip文件,zip文件中有多个文件压缩而成,后端操作文件流,而不生成中间文件。最后把zip返回给前端。

代码实现:

    @ApiOperation(value = "下载Zip", notes = "")@PostMapping("/getDownLoadZip")public void getDownLoadZip(@RequestBody GClientManagementVo vo, HttpServletRequest request,HttpServletResponse response) throws Exception {SysUserEntityVo uc = (SysUserEntityVo) request.getAttribute("UC");GClientManagementService.getDownLoadZip(vo, uc,response);}

中间有业务代码,可酌情删减。代码中注意关闭流,避免影响内存。

 @Overridepublic void getDownLoadZip(GClientManagementVo vo, SysUserEntityVo uc, HttpServletResponse response) throws Exception {String filename = vo.getProjectName();String encodeFileName = URLEncoder.encode(filename);ServletOutputStream out = response.getOutputStream();// 创建一个ByteArrayOutputStream来存放最终的ZIP流ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();ZipOutputStream zipOut = new ZipOutputStream(zipOutputStream);try {//写入文件createFilePs(vo, zipOut);//结束写入zipOut.finish();// 最终ZIP流的内容byte[] zipBytes = zipOutputStream.toByteArray();//设置允许跨域的keyresponse.setHeader("Access-Control-Expose-Headers", "Content-Disposition");//文件名有“,”等特殊字符发送到前端会报错,用""括起来解决response.addHeader("Content-Disposition", "attachment;filename=\"" + encodeFileName + "\"");//设置文件大小response.addHeader("Content-Length", "" + zipBytes.length);//设置文件名,避免问题,这个也用""括起来response.setHeader("filename,", "filename=\"" + encodeFileName + "\"");//设置文件类型response.setContentType("application/octet-stream");out.write(zipBytes);out.flush();} catch (Exception e) {throw e;} finally {try {out.close();} catch (Exception e) {throw e;}try {zipOutputStream.close();} catch (Exception e) {throw e;}try {zipOut.close();} catch (Exception e) {throw e;}try {out.close();} catch (Exception e) {throw e;}}}private void createFilePs(GClientManagementVo vo, ZipOutputStream zipOut) throws Exception {// 创建第一个文件install 或者uninstallByteArrayOutputStream file1 = new ByteArrayOutputStream();//install  or uninstallString str1 = "";String fileName1 = "";QueryWrapper<GClientAdmin> queryWrapper = new QueryWrapper();if (vo.getFunction().equalsIgnoreCase(ParamsEnum.Install.getValue())) {queryWrapper.eq("sign", ParamsEnum.Install.getValue());} else {queryWrapper.eq("sign", ParamsEnum.Uninstall.getValue());}queryWrapper.last("limit 1");GClientAdmin gClientAdmin = gClientAdminDao.selectOne(queryWrapper);fileName1 = gClientAdmin.getScriptName();str1 = replaceScriptcode(gClientAdmin.getScriptCode(), vo);try {// 创建ByteArrayOutputStream来模拟文件流writeToFile(file1, str1);// 将每个文件流添加到ZIP流中addToZipFile(fileName1, file1.toByteArray(), zipOut);} catch (IOException ex) {ex.printStackTrace();throw ex;}//多个已经上传文件List<GClientManagementScriptVo> scriptList = vo.getScriptList();if (CollectionUtils.isNotEmpty(scriptList)) {scriptList.forEach(e -> {List<ParamsObject> paramslist = e.getParamslist();if (CollectionUtils.isNotEmpty(paramslist)) {paramslist.forEach(m -> {if (ParamsEnum.File.getValue().equalsIgnoreCase(m.getDataType())) {String str = m.getFileContent();String fileName = m.getFileName();//创建ByteArrayOutputStream来模拟文件流ByteArrayOutputStream file = new ByteArrayOutputStream();try {// 创建ByteArrayOutputStream来模拟文件流writeToFile(file, str);// 将每个文件流添加到ZIP流中addToZipFile(fileName, file.toByteArray(), zipOut);} catch (IOException ex) {ex.printStackTrace();}}});}});}}private String replaceScriptcode(String scriptcode, GClientManagementVo vo) throws Exception {//查找主参数的字符串String startParams = ParamsEnum.Params_Replace_Start.getValue();String endParams = ParamsEnum.Params_Replace_End.getValue();String resultParams = findSubstringBetween(scriptcode, startParams, endParams);if (resultParams != null) {//开始替换主参数String result = resultParams//projectName.replace(ParamsEnum.ProjectName.getValue(), "\"" + vo.getProjectName() + "\"")//applicationName.replace(ParamsEnum.MSIApplicationName.getValue(), "\"" + vo.getApplicationName() + "\"")//cmdRcopt.replace(ParamsEnum.CmdRCOpt.getValue(), vo.getCmdRcopt())//maxRunTime.replace(ParamsEnum.MaxRunTime.getValue(), vo.getMaxRunTime().toString())//startStopService.replace(ParamsEnum.StartStopService.getValue(), "\"" + vo.getStartStopService() + "\"")//debugEnable.replace(ParamsEnum.DebuggingEnabled.getValue(), "$" + vo.getDebugEnable())//defaultMsicLine.replace(ParamsEnum.DefaultMSICmdLine.getValue(), "\"" + vo.getDefaultMsicLine() + "\"")//uDriveMap.replace(ParamsEnum.UDriveMap.getValue(), "$" + vo.getuDriveMap())//function.replace(ParamsEnum.sFunction.getValue(), "\"" + vo.getFunction().toUpperCase(Locale.ROOT) + "\"")//ifsScript.replace(ParamsEnum.bIsIFSScript.getValue(), "$" + vo.getIfsScript());//替换主脚本字符串// 使用 replaceAll 方法和正则表达式来替换所有匹配的子字符串// 注意:这里使用了正则表达式,所以需要对特殊字符进行转义int startIndex = scriptcode.indexOf(startParams);if (startIndex != -1) {int endIndex = scriptcode.indexOf(endParams, startIndex);if (endIndex != -1) {scriptcode = scriptcode.substring(0, startIndex) + result + scriptcode.substring(endIndex + endParams.length());} else {throw new Exception("End tag not found.");}} else {throw new Exception("Start tag not found.");}//查找子参数的字符串String startCommand = ParamsEnum.Command_Replace_Start.getValue();String endCommand = ParamsEnum.Command_Replace_End.getValue();AtomicReference<String> codeStr = new AtomicReference<>("");if (CollectionUtils.isNotEmpty(vo.getScriptList())) {vo.getScriptList().forEach(e -> {AtomicReference<String> finalCode = new AtomicReference<>(e.getScriptCode());if (CollectionUtils.isNotEmpty(e.getParamslist())) {e.getParamslist().forEach(m -> {String value = "";String name = "";if (m.getDataType().equalsIgnoreCase(ParamsEnum.Boolean.getValue())) {value = "$" + m.getValue();name = "${" + m.getName() + "}";} else if (m.getDataType().equalsIgnoreCase(ParamsEnum.String.getValue())) {//CustomParameters特殊情况,全string参数if(m.getName().equalsIgnoreCase(ParamsEnum.CustomParameters.getValue())){if(StringUtils.startsWith(m.getValue().toString(),"\"")&&StringUtils.endsWith(m.getValue().toString(),"\"")){value = m.getValue().toString();}else {value = "\"" + m.getValue() + "\"";}}else {value = "\"" + m.getValue() + "\"";}name = "${" + m.getName() + "}";} else if (m.getDataType().equalsIgnoreCase(ParamsEnum.Int.getValue())) {value = m.getValue().toString();name = "${" + m.getName() + "}";} else if (m.getDataType().equalsIgnoreCase(ParamsEnum.File.getValue())) {value = "\"\\" + m.getFileName() + "\"";name = "${" + m.getName() + "}";}finalCode.set(finalCode.get().replace(name, value));});}codeStr.set(codeStr.get() + "\n" + finalCode.get());});}//子参数替换int startIndex2 = scriptcode.indexOf(startCommand);if (startIndex2 != -1) {int endIndex2 = scriptcode.indexOf(endCommand, startIndex2);if (endIndex2 != -1) {scriptcode = scriptcode.substring(0, startIndex2) + codeStr.get() + scriptcode.substring(endIndex2 + endCommand.length());} else {throw new Exception("End tag not found.");}} else {throw new Exception("Start tag not found.");}} else {throw new Exception("error");}return scriptcode;}public static String findSubstringBetween(String source, String start, String end) {// 找到开始字符串的位置int startIndex = source.indexOf(start);// 开始字符串不存在if (startIndex == -1) {return null;}// 在开始字符串之后找到结束字符串的位置int endIndex = source.indexOf(end, startIndex + start.length());// 结束字符串不存在if (endIndex == -1) {return null;}// 提取并返回子字符串return source.substring(startIndex + start.length(), endIndex);}private void writeToFile(ByteArrayOutputStream out, String content) throws IOException {try (OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8")) {writer.write(content);writer.flush();} finally {try {out.close();} catch (Exception e) {throw e;}}}private void addToZipFile(String fileName, byte[] fileContent, ZipOutputStream zipOut) throws IOException {ZipEntry zipEntry = new ZipEntry(fileName);zipOut.putNextEntry(zipEntry);zipOut.write(fileContent);zipOut.closeEntry();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/66018.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在 pandas.Grouper() 中,freq 参数用于指定时间频率,它定义了如何对时间序列数据进行分组。freq 的值可以是多种时间单位

在 pandas.Grouper() 中&#xff0c;freq 参数用于指定时间频率&#xff0c;它定义了如何对时间序列数据进行分组。freq 的值可以是多种时间单位&#xff0c;具体包括以下几类&#xff1a; 常见的时间频率 (freq) 取值&#xff1a; 1. 日频率&#xff08;Daily&#xff09; …

java下载文件流,不生成中间文件。

java下载文件流&#xff0c;不生成中间文件。 代码设计&#xff1a;代码实现 代码设计&#xff1a; 从前端获取的数据经过后端加工后&#xff0c;生成文件流&#xff0c;并返回前端&#xff0c;&#xff08;不生成中间文件&#xff0c;注意内存&#xff0c;记得关闭流&#xf…

【代码】Python|Windows 批量尝试密码去打开加密的 Word 文档(docx和doc)

文章目录 前言完整代码Githubdocxdoc 代码解释1. msoffcrypto 方法&#xff08;用于解密 .docx 文件&#xff09;read_secret_word_file 函数密码生成与解密尝试try_decrypt_file 函数 2. comtypes 方法&#xff08;用于解密 .doc 文件&#xff09;read_secret_word_file 函数注…

职场常用Excel基础04-二维表转换

大家好&#xff0c;今天和大家一起分享一下excel的二维表转换相关内容~ 在Excel中&#xff0c;二维表&#xff08;也称为矩阵或表格&#xff09;是一种组织数据的方式&#xff0c;其中数据按照行和列的格式进行排列。然而&#xff0c;在实际的数据分析过程中&#xff0c;我们常…

python-redis访问指南

Redis&#xff08;Remote Dictionary Server&#xff09;是一种开源的内存数据结构存储&#xff0c;可用作数据库、缓存和消息代理。它功能强大且灵活&#xff0c;可根据需求调整架构和配置&#xff0c;以高性能、简单易用、支持多种数据结构而闻名&#xff0c;广泛应用于各种场…

MySQL锁的概念

锁的基本概念 锁在 MySQL 中是一种并发控制机制&#xff0c;它确保在多用户或多事务环境下数据的完整性和一致性。当多个事务同时访问和操作数据库中的数据时&#xff0c;为了防止数据出现不一致、丢失更新、脏读、不可重复读和幻读等问题&#xff0c;就需要使用锁来协调这些事…

Java-多种方法实现多线程卖票

Java多线程卖票是一个经典的并发编程问题,它展示了如何在多个线程之间安全地共享和修改资 源。以下是几种实现方式: 使用synchronized关键字: 使用synchronized修饰符来同步方法或代码块,确保同一时刻只有一个线程可以访问临界区(即操 作共享资源的代码)。 使用Reen…

Px4 V2.4.8飞控Mavlink命令控制说明

首先&#xff0c;可以使用两种方法连接飞控&#xff0c;使用虚拟机&#xff08;LINUX&#xff09;或使用地面站&#xff08;QGC&#xff09;连接。 在px4的代码文件位置打开命令终端&#xff0c;输入连接命令&#xff1a; ./Tools/mavlink_shell.py 在控制台使用help来获取所有…

【Vue3】h、ref:vue3的两个新特性(重要)-h和ref

h、ref&#xff1a;vue3的两个新特性-重要 h 函数&#xff08; createElement&#xff09;ref 函数总结 在 Vue 3 中&#xff0c;h 和 ref 是两个非常重要的函数&#xff0c;它们在框架的运行和组件的创建中扮演着关键角色。在 Vue 3 中&#xff0c;这两个函数是构建现代 Vue 应…

MySQL8安装与卸载

1.下载mysql MySQL :: Download MySQL Community Serverhttps://dev.mysql.com/downloads/mysql/ 2.解压mysql安装包 解压到自己定义的目录&#xff0c;这里解压就是安装&#xff0c;解压后的路径不要有空格和中文。 3.配置环境变量 配置环境变量可以方便电脑在任何的路径…

简洁安装配置在Windows环境下使用vscode开发pytorch

简洁安装配置在Windows环境下使用vscode开发pytorch 使用anaconda安装pytorch&#xff0c;通过vscode集成环境开发pytorch 下载 anaconda 下载网址&#xff0c;选择对应系统的版本 https://repo.anaconda.com/archive/ windows可以选择Anaconda3-2024.10-1-Windows-x86_64.e…

25.Java JUC 引入(进程与线程、线程的状态、并发与并行、管程、用户线程与守护线程)

一、JUC 简介 JUC 是 java.util.concurrent 工具包的简称&#xff0c;这是一个处理线程的工具包&#xff0c;从 JDK1.5 开始出现 二、进程与线程 1、基本介绍 &#xff08;1&#xff09;进程 进程是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源…

使用 Jupyter Notebook:安装与应用指南

文章目录 安装 Jupyter Notebook1. 准备环境2. 安装 Jupyter Notebook3. 启动 Jupyter Notebook4. 选择安装方式&#xff08;可选&#xff09; 二、Jupyter Notebook 的基本功能1. 单元格的类型与运行2. 可视化支持3. 内置魔法命令 三、Jupyter Notebook 的实际应用场景1. 数据…

快速理解MIMO技术

引言 在无线通信领域&#xff0c;MIMO&#xff08;Multiple-Input Multiple-Output&#xff0c;多输入多输出&#xff09;技术是一项革命性的进步&#xff0c;它通过在发射端和接收端同时使用多个天线&#xff0c;极大地提高了通信系统的容量、可靠性和覆盖范围。本文简要阐释其…

unity学习3:如何从github下载开源的unity项目

目录 1 网上别人提供的一些github的unity项目 2 如何下载github上的开源项目呢&#xff1f; 2.1.0 下载工具 2.1.1 下载方法1 2.1.2 下载方法2&#xff08;适合内部项目&#xff09; 2.1.3 第1个项目 和第4项目 的比较 第1个项目 第2个项目 第3个项目 2.1.4 下载方法…

npm install --global windows-build-tools --save 失败

注意以下点 为啥下载windows-build-tools&#xff0c;是因为node-sass4.14.1 一直下载不成功&#xff0c;提示python2 没有安装&#xff0c;最终要安装这个&#xff0c;但是安装这个又失败&#xff0c;主要有以下几个要注意的 1、node 版本 14.21.3 不能太高 2、管理员运行 …

十二、Vue 路由

文章目录 一、简介二、安装与基本配置安装 Vue Router创建路由实例在应用中使用路由实例三、路由组件与视图路由组件的定义与使用四、动态路由动态路由参数的定义与获取动态路由的应用场景五、嵌套路由嵌套路由的概念与配置嵌套路由的应用场景六、路由导航<router - link>…

NLP 中文拼写检测纠正论文-08-Combining ResNet and Transformer

拼写纠正系列 NLP 中文拼写检测实现思路 NLP 中文拼写检测纠正算法整理 NLP 英文拼写算法&#xff0c;如果提升 100W 倍的性能&#xff1f; NLP 中文拼写检测纠正 Paper java 实现中英文拼写检查和错误纠正&#xff1f;可我只会写 CRUD 啊&#xff01; 一个提升英文单词拼…

深度学习中的离群值

文章目录 深度学习中有离群值吗&#xff1f;深度学习中的离群值来源&#xff1a;处理离群值的策略&#xff1a;1. 数据预处理阶段&#xff1a;2. 数据增强和鲁棒模型&#xff1a;3. 模型训练阶段&#xff1a;4. 异常检测集成模型&#xff1a; 如何处理对抗样本&#xff1f;总结…

儿童坐姿矫正器是如何实现语音提示功能?

儿童坐姿不正确&#xff0c;不仅影响他们的体态美观&#xff0c;更关乎其身体健康与成长发育。长期以往&#xff0c;可能会导致脊柱侧弯、近视加深等一系列健康问题。家长应当对此给予足够重视&#xff0c;及时纠正孩子们的坐姿习惯。 为了改善这一状况&#xff0c;可以从这方…