基于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
     */
    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);

你可能感兴趣的:(java,servlet,前端)