vue+springboot单个文件下载,多个文件先压缩再下载

可以使用weindo.open(URL)直接打开,但考虑到体验用了blob,这里前端和后端有几个坑,先上代码

//批量下载
    batchDownload() {
      let _this = this;
      console.log(this.$refs.selectedData.selection);
      let sheetData = this.$refs.selectedData.selection;
      if (sheetData.length > 0) {
        let url = _this.BASEURL + "/DbCaseMgr/batchDownload";
        let idList = [];
        for (let i = 0; i < sheetData.length; i++) {
          idList.push(sheetData[i]["C_ID"]);
        }
        let postData = { idList: idList };
        _this.$axios
          .post(url, postData, { responseType: "blob" })
          .then(function(res) {
            console.log(res);
            let contentDisposition = res.headers["content-disposition"];
            let fileName = decodeURIComponent(
              contentDisposition.substring(contentDisposition.indexOf("=") + 1)
            );
            console.log("fileName=" + fileName);
            _this.download1(res, fileName);
            //window.open(url + "?filePath=" + filePath);
          })
          .catch(function(err) {
            console.log(err);
          });
      } else {
        _this.$message({
          showClose: true,
          message: "请选择至少一条数据",
          type: "error"
        });
      }
       download1(res, fileName) {
      let blob = new Blob([res.data], { type: res.headers["content-type"] });
      //let blob = new Blob([res.data]);
      let a = document.createElement("a");
      a.style.display = "none";
      document.body.appendChild(a);
      const url = window.URL || window.webkitURL || window.moxURL;
      let link = url.createObjectURL(blob);
      a.href = link;
      a.download = fileName;
      a.click();
      document.body.removeChild(a);
      window.URL.revokeObjectURL(link);
    },

后端

/**
	 * 批量下载
	 * 
	 * @param response
	 */
	@PostMapping(value = "/batchDownload")
	public void batchDownload(@RequestBody(required = true) HashMap<String, Object> paraMap, HttpServletResponse response) {
		
		List<String> idList = (List<String>) (paraMap.containsKey("idList")? paraMap.get("idList") : new ArrayList<String>());
		List<Map<String, Object>> caseList = dataClassifyTagService.queryCaseByIdList(idList);
		// 存放--服务器上zip文件的目录
		String directory = "F:/picture";
		
		
		List<String> paths = new ArrayList<>();
		List<String> names = new ArrayList<>();
		for (Map<String, Object> map : caseList) {
			paths.add((String) map.get("C_PHYSICAL_PATH"));
			names.add((String) map.get("C_CASE_NAME"));
		}
		
		File directoryFile = new File(directory);
		if (!directoryFile.isDirectory() && !directoryFile.exists()) {
			directoryFile.mkdirs();
		}
		// 设置最终输出zip文件的目录+文件名
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
		String zipFileName = formatter.format(new Date()) + ".zip";
		String strZipPath = directory + "\\" + zipFileName;

		ZipOutputStream zipStream = null;
		FileInputStream zipSource = null;
		BufferedInputStream bufferStream = null;
		File zipFile = new File(strZipPath);
		try {
			// 构造最终压缩包的输出流
			zipStream = new ZipOutputStream(new FileOutputStream(zipFile));
			for (int i = 0; i < paths.size(); i++) {
				// 解码获取真实路径与文件名
				String realFileName = java.net.URLDecoder.decode(names.get(i), "UTF-8");
				String realFilePath = java.net.URLDecoder.decode(paths.get(i), "UTF-8");
				File file = new File(realFilePath);
				// TODO:未对文件不存在时进行操作,后期优化。
				if (file.exists()) {
					zipSource = new FileInputStream(file);// 将需要压缩的文件格式化为输入流
					/**
					 * 压缩条目不是具体独立的文件,而是压缩包文件列表中的列表项,称为条目,就像索引一样这里的name就是文件名,
					 * 文件名和之前的重复就会导致文件被覆盖
					 */
					ZipEntry zipEntry = new ZipEntry(realFileName);// 在压缩目录中文件的名字
					zipStream.putNextEntry(zipEntry);// 定位该压缩条目位置,开始写入文件到压缩包中
					bufferStream = new BufferedInputStream(zipSource, 1024 * 10);
					int read = 0;
					byte[] buf = new byte[1024 * 10];
					while ((read = bufferStream.read(buf, 0, 1024 * 10)) != -1) {
						zipStream.write(buf, 0, read);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭流
			try {
				if (null != bufferStream)
					bufferStream.close();
				if (null != zipStream) {
					zipStream.flush();
					zipStream.close();
				}
				if (null != zipSource)
					zipSource.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// 判断系统压缩文件是否存在:true-把该压缩文件通过流输出给客户端后删除该压缩文件 false-未处理
		if (zipFile.exists()) {
			try {
				download(response, zipFileName, strZipPath);
			} catch (IOException e) {
				e.printStackTrace();
			}
			zipFile.delete();
		}
	}
public void download(HttpServletResponse response, String filename, String path) throws IOException {
		 response.setCharacterEncoding("UTF-8"); 
		if (filename != null) {
			FileInputStream is = null;
			BufferedInputStream bs = null;
			OutputStream os = null;
			try {
				File file = new File(path);
				if (file.exists()) {
					// 设置Headers
					response.setHeader("Content-Type", "application/octet-stream;charset=UTF-8");
					// 设置下载的文件的名称-该方式已解决中文乱码问题
					response.setHeader("Content-Disposition",
							"attachment;filename=" + java.net.URLEncoder.encode(filename, "UTF-8"));
					
					is = new FileInputStream(file);
					bs = new BufferedInputStream(is);
					os = response.getOutputStream();
					byte[] buffer = new byte[1024];
					int len = 0;
					while ((len = bs.read(buffer)) != -1) {
						os.write(buffer, 0, len);
					}
				} else {
					String error = "下载的文件资源不存在";
					response.sendRedirect("error=" + error);
				}
			} finally {

				if (is != null) {
					is.close();
				}
				if (bs != null) {
					bs.close();
				}
				if (os != null) {
					os.flush();
					os.close();
				}
			}
		}
	}

下面记录一下自己遇到的一些坑
1: // 设置Headers
response.setHeader(“Content-Type”, “application/octet-stream;charset=UTF-8”);
// 设置下载的文件的名称-该方式已解决中文乱码问题
response.setHeader(“Content-Disposition”,
“attachment;filename=” + java.net.URLEncoder.encode(filename, “UTF-8”));
这两点很重要

因为涉及到跨域的问题,前端可能获取不到content-disposition,需要在跨域设置的地方标记,跨域设置有两种方式,自行百度
2:前端使用了blob进行下载,正常情况下设置了blob的,axios会自动帮我们将文件流转化成blob,但前端的数据不一定都是blob
这种是错误类型
在这里插入图片描述
这是因为前端设置的responseType没有生效,困扰了很久,后来发现是因为前端的框架使用了mock.js,mock,js将请求拦截其内部将responseType置空,所以要先消除mock,不同的项目引用mock,js的方式和位置有所不同,需要自己找到配置文件注释.add(’@/mock’) 或者有的是require(’@/mock’),然后重启
这种是正确类型
在这里插入图片描述

VueSpring Boot中实现文件下载的方法有多种。根据提供的引用内容,我们可以使用文件流的方式来实现。首,在Vue的前端代码中需要定义一个下载文件的方法,可以通过点击按钮触发该方法。 在Vue的前端代码中,我们可以使用Element UI等前端框架来创建一个按钮,绑定一个click事件方法,例如: ```html <template> <div> <el-button size="medium" type="success" plain @click="downLoadFile">下载</el-button> </div> </template> ``` 接着,在VueJavaScript逻辑部分,使用axios调用后端接口来进行文件下载。具体的JavaScript代码如下所示: ```javascript export default { name: "xxx", data() { return { filePath: 'D:\file\文件名称.pdf', // 文件路径 fileName: '文件名称.pdf', // 文件名称 } }, methods: { // 下载文件方法 downLoadFile() { this.$axios.get("/downFile/downLoadFile", { params: { path: this.filePath, name: this.fileName }, responseType: 'blob' }).then(res => { const blob = new Blob([res.data]); const fileName = res.headers["content-disposition"].split(";")[1].split("filename=")[1]; if ('download' in document.createElement("a")) { const link = document.createElement("a"); link.download = fileName; link.style.display = 'none'; link.href = URL.createObjectURL(blob); document.body.appendChild(link); link.click(); URL.revokeObjectURL(link.href); document.body.removeChild(link); } else { navigator.msSaveBlob(blob, fileName); } }) } }, } ``` 在上述代码中,我们通过axios发送GET请求到后端接口`"/downFile/downLoadFile"`,并传递文件的路径和名称作为请求参数。同时,我们指定了`responseType`为`blob`,以便获取到文件的二进制数据。在获取到文件数据后,我们将其保存为Blob对象,并使用创建的下载链接进行文件下载。 请注意,以上代码仅为示例,实际的路径和文件名需要根据具体情况进行修改。此外,需要确保后端接口正确处理文件下载请求,并返回文件的二进制数据。 综上所述,以上代码演示了在VueSpring Boot中实现文件下载的方法,你可以根据需要进行调整和扩展。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span> #### 引用[.reference_title] - *1* *2* *3* *4* [vue+springboot使用文件实现文件下载](https://blog.csdn.net/xc9711/article/details/127485603)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值