随着运营系统系统的日益庞大和数据量的持续增长,导出excel成了系统占用资源的大头,最近系统频繁出现OOM和响应慢的问题,和导出数据脱不了干系。

 

故周六抽时间写了个工具类,用于异步导出,依赖 EasyExcel ,如果项目中已经引入,那么可以无缝接入。

 

 

 

1.支持游标数据

2.支持回调进度、成功、失败

3.不会出现OOM

4.易于使用

 

 

使用:

        ExportWriter.New(out, data, DemoData.class)
                .dataSize(2000)
                .progress((progress) -> {
                    // 进度设置
                    log.info("当前进度......" + progress);
                    return null;
                })
                .success(() -> {
                    // 成功
                    log.info("下载完成......");
                    return null;
                })
                .error(() -> {
                    // 失败
                    log.info("下载失败......");
                    return null;
                })
                .asyncWrite();

 

 

源代码:

  1 package com.wangjie.lee.nice;
  2 
  3 import com.alibaba.excel.EasyExcel;
  4 import com.alibaba.excel.ExcelWriter;
  5 import com.alibaba.excel.write.builder.ExcelWriterBuilder;
  6 import com.alibaba.excel.write.metadata.WriteSheet;
  7 
  8 import java.io.OutputStream;
  9 import java.util.ArrayList;
 10 import java.util.List;
 11 import java.util.concurrent.ExecutorService;
 12 import java.util.concurrent.Executors;
 13 import java.util.concurrent.atomic.AtomicLong;
 14 import java.util.function.Function;
 15 import java.util.function.Supplier;
 16 
 17 /**
 18  * @author shaozhengmao
 19  * @create 2021-11-13 9:36 下午
 20  * @desc
 21  */
 22 public class ExportWriter<T> {
 23 
 24     private static final ExecutorService THREAD_POOL_EXECUTOR = Executors.newFixedThreadPool(8);
 25 
 26     private OutputStream out;
 27     private Supplier<Void> callback = () -> null;
 28     private Supplier<Void> errorCallBack = () -> null;
 29     private Function<Integer, Void> progressCallback = (Integer p) -> null;
 30     private Iterable<T> iterable;
 31     private Class<T> head;
 32 
 33     private Long dataSize = 0L;
 34 
 35     public ExportWriter<T> dataSize(Long dataSize) {
 36         this.dataSize = dataSize;
 37         return this;
 38     }
 39 
 40     /**
 41      * 非list类型需要指定数据量
 42      *
 43      * @param dataSize
 44      * @return
 45      */
 46     public ExportWriter<T> dataSize(Integer dataSize) {
 47         if (this.dataSize==0L){
 48             this.dataSize = dataSize.longValue();
 49         }
 50         return this;
 51     }
 52 
 53     private ExportWriter(OutputStream out, Iterable<T> iterable, Class<T> head, Long dataSize) {
 54         this.out = out;
 55         this.iterable = iterable;
 56         this.head = head;
 57         this.dataSize = dataSize;
 58     }
 59 
 60     public static <T> ExportWriter<T> New(OutputStream out, Iterable<T> iterable, Class<T> head) {
 61         if (iterable instanceof List) {
 62             List<T> collection = (List<T>) iterable;
 63             return new ExportWriter<>(out, iterable, head, (long) collection.size());
 64         }
 65         return new ExportWriter<>(out, iterable, head, 0L);
 66     }
 67 
 68     public void asyncWrite() {
 69         THREAD_POOL_EXECUTOR.submit(() -> {
 70             try {
 71                 write();
 72                 this.out.close();
 73                 this.callback.get();
 74             } catch (Exception e) {
 75                 e.printStackTrace();
 76                 this.errorCallBack.get();
 77             }
 78         });
 79     }
 80 
 81     public ExportWriter<T> success(Supplier<Void> callback) {
 82         this.callback = callback;
 83         return this;
 84     }
 85 
 86     private void write() {
 87         final ExcelWriterBuilder builder = EasyExcel.write(this.out);
 88         builder.head(this.head);
 89         final ExcelWriter writer = builder.build();
 90         WriteSheet writeSheet = new WriteSheet();
 91         writeSheet.setSheetName("DATA");
 92         writeSheet.setSheetNo(1);
 93 
 94         this.progressCallback.apply(0);
 95         AtomicLong count = new AtomicLong(0);
 96         iterable.iterator().forEachRemaining(e -> {
 97             if (count.get() % 10000 == 0) {
 98                 final double progress = ((double) count.incrementAndGet() / (double) this.dataSize) * 100.0;
 99                 if (progress > 100) {
100                     // error size
101                     this.progressCallback.apply(60);
102                 } else {
103                     this.progressCallback.apply((int) progress);
104                 }
105             }
106             final ArrayList<T> data = new ArrayList<>();
107             data.add(e);
108             writer.write(data, writeSheet);
109             count.getAndIncrement();
110         });
111 
112         writer.finish();
113         this.progressCallback.apply(100);
114     }
115 
116     public ExportWriter<T> error(Supplier<Void> errorCallBack) {
117         this.errorCallBack = errorCallBack;
118         return this;
119     }
120 
121     public ExportWriter<T> progress(Function<Integer, Void> progressCallback) {
122         this.progressCallback = progressCallback;
123         return this;
124     }
125 }