基于java8,EasyExcel 异步导出数据

1.包引用

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.0-beta2</version>
</dependency>

2.工具类封装

@Slf4j
@SuppressWarnings({"unused", "Duplicates"})
public class EasyExcelUtil {

    /**
     * 不封装对象导出excel
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param titles          标题行
     * @param dataList        数据集合,dataList.get(i)中的数据要和标题行一一对应
     * @return : java.io.InputStream
     */
    public static InputStream exportExcelNoClass(String sheetOrFileName, List<List<String>> titles, List<List<String>> dataList) {
        if (StringUtils.isBlank(sheetOrFileName) || CollectionUtils.isEmpty(titles) || CollectionUtils.isEmpty(dataList)
                || titles.size() != dataList.get(0).size()) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        return doExportExcel(sheetOrFileName, titles, null, dataList, null, null);
    }

    /**
     * 封装对象导出excel
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param dataList        模型数据集合
     * @return : java.io.InputStream
     */
    public static <T> InputStream exportExcelWithClass(String sheetOrFileName, List<T> dataList) {
        if (StringUtils.isBlank(sheetOrFileName) || CollectionUtils.isEmpty(dataList)) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        return doExportExcel(sheetOrFileName, null, dataList.get(0).getClass(), dataList, null, null);
    }

    /**
     * 自定义easyExcel实现导出excel
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param doEasyExcel     自定义easyExcel实现
     * @return : java.io.InputStream
     */
    public static InputStream exportExcelCustomize(String sheetOrFileName, DoEasyExcel doEasyExcel) {
        if (StringUtils.isBlank(sheetOrFileName) || Objects.isNull(doEasyExcel)) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        return doExportExcel(sheetOrFileName, null, null, null, doEasyExcel, null);
    }

    /**
     * 封装对象通过分页导出excel
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param pageSize        每页大小(可为0,当为0时,默认pageSize为2万,并且会查询数据总数,
     *                        如果总数小于等于pageSize,则不分页直接查询所有;
     *                        反之,则分页查询导出)
     * @param clazz           数据的class类型
     * @param supplier        数据提供者
     * @return : java.io.InputStream
     */
    public static <T> InputStream exportExcelWithClassByPage(String sheetOrFileName, int pageSize, Class clazz, Supplier<List<T>> supplier) {
        if (StringUtils.isBlank(sheetOrFileName) || Objects.isNull(supplier) || pageSize < 0 || Objects.isNull(clazz)) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        ByteArrayOutputStream byteArrayOutputStream = doPageExport(sheetOrFileName, pageSize, clazz, supplier, null
                , null);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

    /**
     * 封装对象通过分页异步导出excel
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param pageSize        每页大小(可为0,当为0时,默认pageSize为2万,并且会查询数据总数,
     *                        如果总数小于等于pageSize,则不分页直接查询所有;
     *                        反之,则分页查询导出)
     * @param clazz           数据的class类型
     * @param supplier        数据提供者
     * @param executor        线程池
     * @return : java.io.InputStream
     */
    public static <T> InputStream asyncExportExcelWithClassByPage(String sheetOrFileName, int pageSize, Class clazz,
                                                                  Supplier<List<T>> supplier, Executor executor) {
        if (StringUtils.isBlank(sheetOrFileName) || Objects.isNull(supplier) || pageSize < 0 || Objects.isNull(clazz)
                || Objects.isNull(executor)) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        ByteArrayOutputStream byteArrayOutputStream = doPageExport(sheetOrFileName, pageSize, clazz, supplier, null
                , executor);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

    /**
     * 分页导出excel处理逻辑
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param pageSize        每页大小
     * @param clazz           数据的class类型
     * @param supplier        数据提供者
     * @param biFunction      导出压缩包逻辑
     * @return : java.io.ByteArrayOutputStream
     */
    private static <T> ByteArrayOutputStream doPageExport(String sheetOrFileName, int pageSize, Class clazz, Supplier<List<T>> supplier,
                                                          BiFunction<String, ByteArrayOutputStream, ZipOutputStream> biFunction, Executor executor) {
        long count = PageHelper.count(supplier::get);
        if (count <= 0L) {
            throw new ExportException(HttpStatusEnum.RECORD_NOT_EXIST.getCode(), HttpStatusEnum.RECORD_NOT_EXIST.getMessage());
        }
        int finalPageSize = pageSize == 0 ? 20000 : pageSize;
        int  indexSize = 1000000 / finalPageSize;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ExcelWriter excelWriter = EasyExcel.write(Objects.nonNull(biFunction) ? biFunction.apply(sheetOrFileName, byteArrayOutputStream)
                : byteArrayOutputStream, clazz).excelType(ExcelTypeEnum.XLSX).build();
        //WriteSheet writeSheet = EasyExcel.writerSheet(sheetOrFileName).build();
        ExcelWriterSheetBuilder excelWriterSheetBuilder = new ExcelWriterSheetBuilder(excelWriter);
        LongAdder adder = new LongAdder();
        adder.add(1);
        excelWriterSheetBuilder.sheetNo(adder.intValue());
        excelWriterSheetBuilder.sheetName(sheetOrFileName+adder.intValue());
        AtomicReference<WriteSheet> writeSheet = new AtomicReference<>(excelWriterSheetBuilder.build());
        int pages = (int) Math.ceil((double) count / finalPageSize);
        if (pages == 1) {
            List<T> dataList = supplier.get();
            excelWriter.write(dataList, writeSheet.get());
            dataList.clear();
        } else {
            if (Objects.nonNull(executor)) {
                LinkedBlockingQueue<List<T>> blockingQueue = new LinkedBlockingQueue<>(pages);
                LongAdder longAdder = new LongAdder();
                longAdder.add(pages);
                LongAdder increment = new LongAdder();
                CompletableFuture<Void> writeFuture = CompletableFuture.runAsync(() -> {
                    while (longAdder.intValue() > 0) {
                        try {
                            List<T> dataList = blockingQueue.poll(500, TimeUnit.MILLISECONDS);
                            if (CollectionUtils.isNotEmpty(dataList)) {
                                increment.increment();
                                log.info("doPageExport get to write sheetOrFileName [{}] clazz [{}] longAdder [{}] increment [{}]", sheetOrFileName, clazz, longAdder.intValue(),increment.intValue());
                                if(increment.intValue() % indexSize == 0){
                                    adder.increment();
                                    excelWriterSheetBuilder.sheetNo(adder.intValue());
                                    excelWriterSheetBuilder.sheetName(sheetOrFileName+adder.intValue());
                                    writeSheet.set(excelWriterSheetBuilder.build());
                                }
                                excelWriter.write(dataList, writeSheet.get());
                                longAdder.decrement();
                                dataList.clear();
                            }
                        } catch (Throwable e) {
                            longAdder.decrement();
                            log.error("doPageExport write data sheetOrFileName [{}] clazz [{}] error", sheetOrFileName, clazz, e);
                        }
                    }
                }, executor);
                IntStream.rangeClosed(1, pages).forEach(i -> CompletableFuture.runAsync(() -> {
                    try {
                        PageHelper.startPage(i, finalPageSize, false);
                        blockingQueue.put(supplier.get());
                    } catch (Throwable e) {
                        longAdder.decrement();
                        log.error("doPageExport read data sheetOrFileName [{}] clazz [{}] error", sheetOrFileName, clazz, e);
                    }
                }, executor));
                writeFuture.join();
            } else {
                IntStream.rangeClosed(1, pages).forEach(i -> {
                    PageHelper.startPage(i, finalPageSize, false);
                    if(i % indexSize == 0){
                        adder.increment();
                        excelWriterSheetBuilder.sheetNo(adder.intValue());
                        excelWriterSheetBuilder.sheetName(sheetOrFileName+adder.intValue());
                        writeSheet.set(excelWriterSheetBuilder.build());
                    }
                    List<T> dataList = supplier.get();
                    excelWriter.write(dataList, writeSheet.get());
                    dataList.clear();
                });
            }
        }
        excelWriter.finish();
        return byteArrayOutputStream;
    }

    /**
     * 不封装对象导出excel压缩包
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param titles          标题行
     * @param dataList        数据集合,dataList.get(i)中的数据要和标题行一一对应
     * @return : java.io.InputStream
     */
    public static InputStream exportExcelZipNoClass(String sheetOrFileName, List<List<String>> titles, List<List<String>> dataList) {
        if (StringUtils.isBlank(sheetOrFileName) || CollectionUtils.isEmpty(titles) || CollectionUtils.isEmpty(dataList)
                || titles.size() != dataList.get(0).size()) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        return doExportExcel(sheetOrFileName, titles, null, dataList, null, getZipExportBiFunction());
    }

    /**
     * 获取导出压缩包逻辑
     *
     * @return : java.util.function.BiConsumer<java.lang.String,java.io.ByteArrayOutputStream>
     */
    private static BiFunction<String, ByteArrayOutputStream, ZipOutputStream> getZipExportBiFunction() {
        return (String fileName, ByteArrayOutputStream byteArrayOutputStream) -> {
            ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream);
            ZipEntry zipEntry = new ZipEntry(fileName + ExcelTypeEnum.XLSX.getValue());
            try {
                zipOut.putNextEntry(zipEntry);
            } catch (IOException e) {
                log.error("exportExcelZipWithClassByPage sheetOrFileName [{}]", fileName, e);
            }
            return zipOut;
        };
    }

    /**
     * 封装对象导出excel压缩包
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param dataList        模型数据集合
     * @return : java.io.InputStream
     */
    public static <T> InputStream exportExcelZipWithClass(String sheetOrFileName, List<T> dataList) {
        if (StringUtils.isBlank(sheetOrFileName) || CollectionUtils.isEmpty(dataList)) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        return doExportExcel(sheetOrFileName, null, dataList.get(0).getClass(), dataList, null, getZipExportBiFunction());
    }

    /**
     * 自定义easyExcel实现导出excel压缩包
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param doEasyExcel     自定义easyExcel实现
     * @return : java.io.InputStream
     */
    public static InputStream exportExcelZipCustomize(String sheetOrFileName, DoEasyExcel doEasyExcel) {
        if (StringUtils.isBlank(sheetOrFileName) || Objects.isNull(doEasyExcel)) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        return doExportExcel(sheetOrFileName, null, null, null, doEasyExcel, getZipExportBiFunction());
    }

    /**
     * 封装对象通过分页导出excel压缩包
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param pageSize        每页大小(可为0,当为0时,默认pageSize为2万,并且会查询数据总数,
     *                        如果总数小于等于pageSize,则不分页直接查询所有;
     *                        反之,则分页查询导出)
     * @param clazz           数据的class类型
     * @param supplier        数据提供者
     * @return : java.io.InputStream
     */
    public static <T> InputStream exportExcelZipWithClassByPage(String sheetOrFileName, int pageSize, Class clazz, Supplier<List<T>> supplier) {
        if (StringUtils.isBlank(sheetOrFileName) || Objects.isNull(supplier) || pageSize < 0 || Objects.isNull(clazz)) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        ByteArrayOutputStream byteArrayOutputStream = doPageExport(sheetOrFileName, pageSize, clazz, supplier,
                getZipExportBiFunction(), null);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

    /**
     * 封装对象通过分页异步导出excel压缩包
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param pageSize        每页大小(可为0,当为0时,默认pageSize为2万,并且会查询数据总数,
     *                        如果总数小于等于pageSize,则不分页直接查询所有;
     *                        反之,则分页查询导出)
     * @param clazz           数据的class类型
     * @param supplier        数据提供者
     * @param executor        线程池
     * @return : java.io.InputStream
     */
    public static <T> InputStream asyncExportExcelZipWithClassByPage(String sheetOrFileName, int pageSize, Class clazz,
                                                                     Supplier<List<T>> supplier, Executor executor) {
        if (StringUtils.isBlank(sheetOrFileName) || Objects.isNull(supplier) || pageSize < 0 || Objects.isNull(clazz)
                || Objects.isNull(executor)) {
            throw new ExportException(HttpStatusEnum.BAD_REQUEST.getCode(), HttpStatusEnum.BAD_REQUEST.getMessage());
        }
        ByteArrayOutputStream byteArrayOutputStream = doPageExport(sheetOrFileName, pageSize, clazz, supplier,
                getZipExportBiFunction(), executor);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

    /**
     * 导出excel处理逻辑
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param titles          标题行
     * @param clazz           模型
     * @param dataList        数据集合
     * @param doEasyExcel     自定义easyExcel实现
     * @param biFunction      导出压缩包逻辑
     * @return : java.io.InputStream
     */
    private static <T> InputStream doExportExcel(String sheetOrFileName, List<List<String>> titles, Class clazz, List<T> dataList,
                                                 DoEasyExcel doEasyExcel, BiFunction<String, ByteArrayOutputStream, ZipOutputStream> biFunction) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        doEasyExcel(sheetOrFileName, titles, clazz, dataList, doEasyExcel, Objects.nonNull(biFunction)
                ? biFunction.apply(sheetOrFileName, byteArrayOutputStream) : byteArrayOutputStream);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

    /**
     * 导出excel
     *
     * @param sheetOrFileName sheet或者excel文件名称
     * @param titles          标题行
     * @param clazz           模型
     * @param dataList        数据集合
     * @param doEasyExcel     自定义easyExcel实现
     * @param outputStream    输出流
     */
    private static <T> void doEasyExcel(String sheetOrFileName, List<List<String>> titles, Class clazz, List<T> dataList,
                                        DoEasyExcel doEasyExcel, OutputStream outputStream) {
        if (Objects.nonNull(doEasyExcel)) {
            doEasyExcel.doEasyExcel(outputStream, sheetOrFileName);
        } else if (Objects.nonNull(clazz)) {
            EasyExcel.write(outputStream, clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetOrFileName).doWrite(dataList);
        } else {
            EasyExcel.write(outputStream).excelType(ExcelTypeEnum.XLSX).head(titles).sheet(sheetOrFileName).doWrite(dataList);
        }
        if (CollectionUtils.isNotEmpty(titles)) {
            titles.clear();
        }
        if (CollectionUtils.isNotEmpty(dataList)) {
            dataList.clear();
        }
    }
}

3.实体

@Data
public class DemoData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}

4,使用

     InputStream inputStream = EasyExcelUtil.asyncExportExcelWithClassByPage("客户网络覆盖区域", 8000,
                    CustomerNetworkCoverDto.class, () -> {
                        //核销信息查询
                        List<CustomerNetworkCoverDto> customerNetworkCoverList = customerDao.getCustomerNetworkCoverList(customerNetworkCoverExportRequest);
                        if (CollectionUtils.isNotEmpty(customerNetworkCoverList)) {
                            //维护字段值
                            maintainCustomerNetworkCoverFields(customerNetworkCoverList);
                        }
                        return customerNetworkCoverList;
                    }, threadPoolTaskExecutor);
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java EasyExcel是一个基于POI封装的Excel操作工具,它可以快速地读取、写入和操作Excel文件。EasyExcel异步导出可以提高导出效率,防止大数据导出时造成内存溢出。 下面是Java EasyExcel异步导出的步骤: 1. 首先定义一个实现了AnalysisEventListener接口的监听器类,用于处理Excel读取的每一行数据。例如: ``` public class DemoDataListener extends AnalysisEventListener<DemoData> { private List<DemoData> dataList = new ArrayList<>(); @Override public void invoke(DemoData data, AnalysisContext context) { dataList.add(data); // 每隔1000条处理一次数据,防止数据量过大导致内存溢出 if (dataList.size() >= 1000) { saveData(); dataList.clear(); } } @Override public void doAfterAllAnalysed(AnalysisContext context) { saveData(); } private void saveData() { // 处理数据的逻辑代码,例如保存数据数据库 } } ``` 2. 在需要导出Excel的地方,使用EasyExcel的Sax方式读取Excel文件,并将监听器类传入。例如: ``` EasyExcel.read(file.getInputStream(), DemoData.class, new DemoDataListener()).sheet().doRead(); ``` 3. 使用EasyExcel的WriteTable方式写入Excel文件,将数据分批写入,避免内存溢出。例如: ``` // 定义每个sheet的数据 List<List<DemoData>> dataList = new ArrayList<>(); // 将数据分批添加到sheet中 for (int i = 0; i < totalPage; i++) { List<DemoData> pageData = getDataListByPage(i, pageSize); dataList.add(pageData); } // 使用WriteTable方式写入Excel文件 EasyExcel.write(response.getOutputStream(), DemoData.class).sheet().doWrite(dataList); ``` 其中,getDataListByPage方法是根据页码和每页大小获取对应数据的方法。 通过以上步骤,就可以实现Java EasyExcel异步导出功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值