excel数据的导出(百万)

文章讲述了在导出大量数据时如何应对内存使用、性能和超时问题,通过分批导出和异步执行来提高效率,同时使用EasyExcel和Maven库进行Excel数据导出。作者分享了基于SpringBoot的服务实现,包括分页查询、多线程操作以及导出Excel的代码片段。
摘要由CSDN通过智能技术生成

前面已经实现过导出excel导出下拉框操作和正常数据的导出,伴随着业务发展的需求,需要进行导出最少10万+数据,但是导出大量数据时可能会面临一些挑战,包括内存使用、性能和超时等问题。如果在导出过程中发生错误,这可能会导致部分数据未能成功导出,用户可能会得到不完整的 Excel 文件。
所以在处理大量数据导出时,我采用一下方式进行:

1、分批导出: 尝试将数据分成较小的批次进行导出,而不是一次性导出所有数据。这可以通过在代码中实现分页或分批查询的逻辑来完成。
2、异步导出: 如果导出过程较为耗时,可以考虑将导出任务放到异步任务中执行,以避免对用户请求的阻塞。

maven

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version>
</dependency>

pojo

package com.jaxf.electric.excel;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
@Data
public class MonitorDataExcel{

    @ExcelIgnore
    private Integer id;

    @ExcelProperty("时间")
    private String beginTime;

    @ExcelProperty("设备id")
    private String deviceId;

    @ExcelProperty("温度")
    private String Temperature;

    @ExcelProperty("电压")
    private String Voltage;

    @ExcelProperty("湿度")
    private String Humidity;
}

serviceImpl

public void exportDeviceDate(HttpServletResponse response) {
    Long pageSize = (long) this.count();
    List<MonitorDataExcel> allData = new ArrayList<>();
    for (int i = 0; i < (1L + 1); i++) {
        Long pageNum = (long) i;
        List<MonitorDataExcel> list = limitDictData(pageNum * pageSize, pageSize);
        allData.addAll(list);
    }
    // 获取当前年月
    YearMonth currentYearMonth = YearMonth.now();

    // 使用自定义格式化方式打印当前年月
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
    String formattedYearMonth = currentYearMonth.format(formatter);
    String filename = formattedYearMonth + "月数据统计表.xlsx";
    try (OutputStream out = response.getOutputStream()) {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));

        // 配置 WriteSheet 以允许单元格编辑
        WriteSheet writeSheet = EasyExcel.writerSheet(formattedYearMonth + "月数据统计").build();

        // 将 Excel 版本设置为 XLSX(Excel 2007或更高版本),以支持编辑
        ExcelWriter excelWriter = EasyExcel.write(out, ElectricalMonitorExcel.class).excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .build();
        // 将数据写入 Excel
        excelWriter.write(allData, writeSheet);
        excelWriter.finish();
    } catch (Exception e) {
        log.error("导出excel时发生异常:{}", e.getMessage(), e);
    }
}

多线程操作

/*
 * 多线程读写
 * */
@GetMapping
public void exportDeviceDate() {
    CountDownLatch countDownLatch = new CountDownLatch(5);
    Long pageSize = 100000L;
    int count = (int) dictService.count();

    for(int i=0;i<(count/pageSize+1);i++){
        Long pageNum = Long.valueOf(i);
        new Thread(() -> {

            List<MonitorDataExcel> list = electricalMonitorDataService.limitDictData(pageNum*pageSize, pageSize);
            // 获取当前年月
    YearMonth currentYearMonth = YearMonth.now();

    // 使用自定义格式化方式打印当前年月
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
    String formattedYearMonth = currentYearMonth.format(formatter);
    String filename = formattedYearMonth + "月数据统计表.xlsx";
            //导出到本地
            File file = new File("D:/" + filename);
            if (!file.exists()){
                file.mkdirs();
            }
            String filename = "D:/" + filename;
            EasyExcel.write(filename, ExcelDict.class).sheet("统计表").doWrite(list);
            countDownLatch.countDown();
        }).start();

    }
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    long pagStart = System.currentTimeMillis();
    //打包
ZipUtil.zipDirectory("D:/demo","D:/demo.zip");
}

service && serviceImpl

List<MonitorDataExcel> limitDictData(Long pageNum, Long pageSize);

public List<ExcelDict> limitDictData(Long pageNum, Long pageSize){
    //获取第1页,10条内容,默认查询总数count
    PageHelper.offsetPage(pageNum.intValue(), pageSize.intValue());
    List<ExcelDict> dictList = dictMapper.queryAll();
    PageInfo<ExcelDict> pageInfo = new PageInfo<>(dictList);
    return pageInfo.getList();
}

由于公司的也无需求还不明了,故此只能先建立基础框架,上面也进行了测试,导出数据在10万+以上,耗时大致接近1分钟。暂时先记录到这吧(属于烂尾项目,没走完整个业务流程,到时候在提出需求的时候进行更新)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值