批量下载文件 在线生成 并打压缩包下载

该文章描述了一个技术实现过程,即如何使用Java处理批量生成打印文件的需求。通过内存流而不是本地文件生成,以500条信息为单位分文件,最终合并成ZIP压缩包并通过HTTP响应直接下载。服务层中,代码首先创建内存流,然后构建ZipOutputStream,将内存中的数据写入并发送到响应流中,避免了本地文件的生成和后续清理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求:
批量生成打印机使用的打印文件.
500条信息为一个文件, 超过500条则生成第二个文件, 将最终生成的文件以压缩包形式下载;

接到需求我的第一思路是先使用io流 在服务器生成服务器本地文件, 将所有文件生成好之后, 再讲文件进行压缩然后下载. 然后每天凌晨定时任务扫描文件夹进行文件清理.
后来公司的同事给提供了一个新的思路, 不用在本地生成文件, 而是使用内存流的形式代替, 因为生成的文件内存占用并不是很大.

controller 层

@GetMapping("downloadForStock")
	@ApiOperationSupport(order = 12)
	@ApiOperation(value = "批量下载for指令", notes = "传入货品ids")
	public R downloadForStock(@RequestParam String ids, @ApiIgnore HttpServletResponse response) {
		if (Func.isBlank(ids)) {
			return R.fail("请选择正确的码数据进行下载");
		}
		List<GoodsEntity> goodsList = goodsService.list(Wrappers.<GoodsEntity>lambdaQuery().in(GoodsEntity::getId, Func.toLongList(ids)));
		stockService.downloadForStockGoods(goodsList, response);
		return R.status(true);
	}

service层

	@Override
	@SneakyThrows
	@Transactional(rollbackFor = Exception.class)
	public void downloadForStockGoods(List<GoodsEntity> goodsList, HttpServletResponse response) {
		if (Func.isEmpty(goodsList)) {
			throw new ServiceException("打印失败,货物信息为空!");
		}
		// 创建文件流
		Map<String, byte[]> fileMap = this.creatFile(goodsList);
		//下载压缩包
		ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream());
		response.setContentType("application/octet-stream");
		response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("附件.zip", "UTF-8"));
		// 创建 ZipEntry 对象
		Set<String> keySet = fileMap.keySet();
		for (String key : keySet) {
			ZipEntry zipEntry = new ZipEntry(key);
			zipOutputStream.putNextEntry(zipEntry);
			zipOutputStream.write(fileMap.get(key));
		}
		zipOutputStream.closeEntry();
		zipOutputStream.close();
	}

	@SneakyThrows
	private Map<String, byte[]> creatFile(List<GoodsEntity> goodsList) {
		Map<String, byte[]> resMap = new HashMap();
		Map<Long, GoodsEntity> goodsMap = goodsList.stream().collect(Collectors.toMap(GoodsEntity::getId, o -> o, (v1, v2) -> v1));
		// 获取标识码
		Set<Long> keySet = goodsMap.keySet();
		List<CodesEntity> codes = snmsClient.getCodesByMasterIds(new ArrayList<>(keySet));
		if (codes != null && codes.size() > 0) {
			int size = codes.size();
			int temp = size / 500;
			int rem = size % 500;
			if (rem != 0) {
				temp++;
			}
			ByteArrayOutputStream bo = new ByteArrayOutputStream();
			for (int j = 0; j < temp; j++) {
				String fileName = System.currentTimeMillis() + ".for";
				StringBuffer sb_init = new StringBuffer();
				String qiyeCode = "88.331.111";  // 企业编码
				sb_init.append("#!A1#DC\n");
				sb_init.append("#IMSR50.00/50.00\n");
				sb_init.append("#HV60\n");
				sb_init.append("#PR6/6/\n");
				sb_init.append("#RX0\n");
				// 循环生码
				int start = 500 * j;
				int end = 500 * (j + 1);
				if (end > size) {
					end = size;
				}
				for (int i = start; i < end; i++) {
					CodesEntity code = codes.get(i);
					sb_init.append("#ERN/1//0\n");
					sb_init.append("#R0/0\n");
					// 货物信息
					GoodsEntity goodsEntity = goodsMap.get(code.getMasterId());
					String goodsName = goodsEntity.getGoodsName();
					String goodsIdNumber = goodsEntity.getIdnumber();
//				output.println("#T9.6 #J5.9 #YN901/0/34///物品批次: " + goodsBatch + "#G");
					sb_init.append("#T7.6 #J8.7 #YN901/0/32///名称: " + goodsName + "#G\n");
					sb_init.append("#T7.6 #J12.5 #YN901/0/32///编码: " + goodsIdNumber + "#G\n");
					sb_init.append("#T19.0 #J16.4 #YN901/0/36///" + qiyeCode + "#G\n");
					sb_init.append("#T17.0 #J20.6.75 #SQR2/MA/6/// #VW/L/\"" + snmsClient.getApiHost(code.getCode()) + "\"#G\n");
					sb_init.append("#T6.5 #J42.1 #YN901/0/25///CANGZHOU FOUR STARS GLASS CO.,LTD#G\n");
					sb_init.append("#T6.6 #J45.5 #YN901/0/34///沧 州 四 星 玻 璃 股 份 有 限 公 司\n");
					sb_init.append("#Q1#G\n");
				}
				sb_init.append("#!P1\n");
				bo.write(sb_init.toString().getBytes(StandardCharsets.UTF_8));
				resMap.put(fileName, bo.toByteArray());
				bo.reset();
			}
			bo.close();
		}
		return resMap;
	}

生成内存流的核心代码逻辑

/**
ByteArrayOutputStream 使用的是 apache.commons 包下的
**/


// 创建map集合 用来存放文件内存流
Map<String, byte[]> resMap = new HashMap();
// 创建内存流
ByteArrayOutputStream bo = new ByteArrayOutputStream();
// 创建StringBuffer 准备进行文本拼接
StringBuffer sb_init = new StringBuffer();
String fileName = ""
	for (int i = start; i < end; i++) {
		// 文件名名称
		fileName = "xxx";
		
		// 进行文本内容拼接 (或者进行自己相关的业务逻辑)
		sb_init.append("xxxxx");
		// 写入内存流
		bo.write(sb_init.toString().getBytes(StandardCharsets.UTF_8));
		// 将内存流存入 map集合
		resMap.put(fileName, bo.toByteArray());
		// 重置内存流数据
		bo.reset();
	}
// 关闭流
bo.close();
return resMap;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值