java Export大量数据导出和打包

 更新时间:2023年06月20日 14:51:30   作者:我是一颗小虎牙_  
这篇文章主要为大家介绍了java Export大量数据的导出和打包实现过程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

项目需求

导出生成大批量数据的文件,一个Excel中最多存有五十万条数据,查询多余五十万的数据写多个Excel中。导出完成是生成的多个Excel文件打包压缩成zip,而后更新导出记录中的压缩文件路径。

大数据量文件一般采用异步生成文件,导出时首先授权生成一个流水号,而后将数据携带流水号请求导出接口。

抛开实际业务,做成一个比较公共的导出功能。

参数说明

{
    "className": "ValideData",         //导出的数据的实体类,类中有别名和顺序相关的注解
    "createUser": "",               //操作人
    "downLoadNo": "202203181504732568468066304",    //下载流水号
    "fileName": "机卡绑定",          //文件名      fileName+HHmmssSSS.xlsx
    "keys": [                       //redis key的数据,分批获取数据
    ],
    "remark": "机卡绑定",               //备注(不关注)
    "type": "机卡绑定"                  //导出类型(不关注)
}

坐标

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-compress</artifactId>
  <version>1.21</version>
</dependency>

注:抛开导出前的参数校验,只关注导出操作 。

主要代码

逻辑说明:

  • 导出前将请求参数更新到导出记录中。
  • 类加载器加载需要导出数据的实体类
  • 设置一个数据量指针,记录到每个文件的数据量
  • 达到阈值时指定文件写出到磁盘并清缓。
  • 重置数据量指针,新增一条文件记录(循环)
  • 数据量指针未到阈值时但数据已经查询完成---->>写入剩余数据
  • 查询该流水号的所有文件记录
  • 压缩文件并返回压缩文件地址
  • 更新到导出记录中

主流程

public void bigDataExport(PortDto dto) throws Exception {
    long start = System.currentTimeMillis();
    log.info("开始导出,批次号:<{}>, 开始时间:{}", dto.getDownLoadNo(), DateUtil.now());
    //修改导出记录
    LambdaUpdateWrapper<PortDto> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.eq(PortDto::getDownLoadNo, dto.getDownLoadNo());
    //生成导出记录
    int row = this.baseMapper.update(dto, updateWrapper);
    if (row > 0) {
        log.info("批次号:<{}>准备生成文件", dto.getDownLoadNo());
        try {
            Iterator<String> iterator = keys.iterator();
            Workbook workbook = null;
            ExportParams params = new ExportParams();
            //加载导出数据实体类
            Class<?> aClass = Class.forName(entityBasePackage + dto.getClassName());
            int element = 0;
            while (iterator.hasNext()) {
                String key = iterator.next();
                Collection<?> list = getList(key, aClass);
                element += list.size();
                workbook = ExcelExportUtil.exportBigExcel(params, aClass, list);
                //文件数据达到阈值
                if (element >= maxDataCount) {
                    String fileName = dto.getFileName() + "_" + DateUtil.format(new Date(),
                            "HHmmssSSS") + ".xlsx";
                    ExcelExportUtil.closeExportBigExcel();
                    FileOutputStream fos =
                            new FileOutputStream(fileProp.getPath().getPath() + fileName);
                    workbook.write(fos);
                    fos.close();
                    element = 0;
                    //更新地址
                    Map<String, Object> map = new HashMap<>();
                    map.put("downloadNo", dto.getDownLoadNo());
                    map.put("filePath", fileProp.getPath().getPath() + fileName);
                    map.put("createTime", new Date());
                    this.baseMapper.insertPathRecord(map);
                    log.info("文件写入完成,文件名:{}", fileName);
                    continue;
                }
                iterator.remove();
            }
            //写入剩余文件
            if (element != 0) {
                String fileName = dto.getFileName() + "_" + DateUtil.format(new Date(),
                        "HHmmssSSS") + ".xlsx";
                ExcelExportUtil.closeExportBigExcel();
                FileOutputStream fos = new FileOutputStream(fileProp.getPath().getPath() + fileName);
                workbook.write(fos);
                fos.close();
                element = 0;
                //更新地址
                Map<String, Object> map = new HashMap<>();
                map.put("downloadNo", dto.getDownLoadNo());
                map.put("filePath", fileProp.getPath().getPath() + fileName);
                map.put("createTime", new Date());
                this.baseMapper.insertPathRecord(map);
                log.info("文件写入完成,文件名:{}", fileName);
            }
            long end = System.currentTimeMillis();
            log.info("导出结束,批次号:<{}>, 结束时间:{}, 耗时:{}", dto.getDownLoadNo(), DateTime.of(end),
                    DateUtil.formatBetween(end - start));
        } catch (Exception e) {
            log.info("批次号<{}>导出异常:", dto.getDownLoadNo(), e);
            throw new BusinessException("");
        } finally {
            log.info("批次号<{}>生成文件结束,准备压缩文件,修改状态", dto.getDownLoadNo());
            //合并文件到导出文件记录主表
            //当只有一个文件记录时直接更新主表文件地址
            List<PortDto> recordList = exportDao.getPathRecord(dto);
            if (recordList.size() > 1) {
                //zipPath
                dto.setFilePath(zcat(dto, recordList));
            } else {
                //xlsxPath
                dto.setFilePath(recordList.size()==0? "":recordList.get(0).getFilePath());
            }
            updateWrapper.clear();
            updateWrapper.set(PortDto::getFilePath, dto.getFilePath());
            updateWrapper.set(PortDto::getSuccessTime, new Date());
            updateWrapper.set(PortDto::getStatus, "1");
            updateWrapper.eq(PortDto::getDownLoadNo, dto.getDownLoadNo());
            this.baseMapper.update(null, updateWrapper);
            log.info("批次号<{}>更新下载记录表文件地址,修改状态成功", dto.getDownLoadNo());
        }
    }
}

文件压缩

/**
 *  多文件压缩
 * @param dto 导出信息
 * @Param recordList 文件路径
 * @return void
 * @throws
 * @author Surpass
 * @date 2022/3/17 9:59
 */
private String zcat(PortDto dto, List<PortDto> recordList) throws Exception {
    String fileName = dto.getFileName() + "_" + DateUtil.format(new Date(), "HHmmssSSS") + ".zip";
    String zipPath = fileProp.getPath().getPath() + fileName;
    Archiver archiver = CompressUtil.createArchiver(
            CharsetUtil.CHARSET_UTF_8,
            ArchiveStreamFactory.ZIP,
            new File(zipPath)
    );
    for (PortDto portDto : recordList) {
        archiver.add(FileUtil.file(portDto.getFilePath()));
    }
    archiver.finish();
    archiver.close();
    return zipPath;
}

查询数据

/**
 *   查询redis数据
 * @param key
 * @param cls
 * @return java.util.Collection<?>
 * @throws
 * @author Surpass
 * @date 2022/3/18 15:51
 */
private Collection<?> getList(String key, Class<?> cls) {
    List<String> list = redis.getList(key);
    return list.stream().map(item -> JSONObject.parseObject(item, cls)).collect(Collectors.toList());
}

补充

导出还设置了队列计数器来限制同一时间最大的导出请求,使用aop在申请流水号时计数器+1,导出完成或者异常时队列计数器-1。导出完成后根据操作人发送邮件通知导出结果。

以上就是java Export大量数据导出和打包的详细内容,更多关于java Export数据导出打包的资料请关注脚本之家其它相关文章!

相关文章

  • Java 中引入内部类的意义?

    Java 中引入内部类的意义?

    这篇文章主要介绍了Java 中引入内部类的意义?文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,,需要的朋友可以参考下
    2019-06-06
  • SpringBoot基于AbstractRoutingDataSource实现多数据源动态切换

    SpringBoot基于AbstractRoutingDataSource实现多数据源动态切换

    本文主要介绍了SpringBoot基于AbstractRoutingDataSource实现多数据源动态切换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Spring Boot实现分布式系统中的服务发现和注册(最新推荐)

    Spring Boot实现分布式系统中的服务发现和注册(最新推荐)

    在本文中,我们深入探讨了Spring Boot如何实现分布式系统中的服务发现和注册,我们使用Eureka作为服务注册中心,Ribbon作为负载均衡器,Hystrix作为熔断器,成功地实现了服务发现、服务注册、负载均衡和服务熔断等功能,需要的朋友参考下吧
    2023-06-06
  • Springboot并发调优之大事务和长连接

    Springboot并发调优之大事务和长连接

    这篇文章主要介绍了Springboot并发调优之大事务和长连接,重点分享长事务以及长连接导致的并发排查和优化思路和示例,具有一定的参考价值,感兴趣的可以了解一下
    2022-05-05
  • Java Swing JSlider滑块的实现示例

    Java Swing JSlider滑块的实现示例

    这篇文章主要介绍了Java Swing JSlider滑块的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 详解SpringBoot上传图片到阿里云的OSS对象存储中

    详解SpringBoot上传图片到阿里云的OSS对象存储中

    这篇文章主要介绍了SpringBoot上传图片到阿里云的OSS对象存储中,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • 一文讲通Java为什么不支持多继承原理

    一文讲通Java为什么不支持多继承原理

    这篇文章主要为大家介绍了java为什么不支持多继承原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Java查找不重复无序数组中是否存在两个数字的和为某个值

    Java查找不重复无序数组中是否存在两个数字的和为某个值

    今天小编就为大家分享一篇关于Java查找不重复无序数组中是否存在两个数字的和为某个值,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • 如何使用拦截器获取请求的入参并将其转化为Java对象详解

    如何使用拦截器获取请求的入参并将其转化为Java对象详解

    这篇文章主要介绍了如何使用拦截器获取请求的入参并将其转化为Java对象的相关资料,文中介绍了两种实现的方法,并给出了详细的代码示例,需要的朋友可以参考下
    2025-02-02
  • Java实现布隆过滤器的几种方式总结

    Java实现布隆过滤器的几种方式总结

    这篇文章给大家总结了几种Java实现布隆过滤器的方式,手动硬编码实现,引入Guava实现,引入hutool实现,通过redis实现等几种方式,文中有详细的代码和图解,需要的朋友可以参考下
    2023-07-07

最新评论