隨着運營系統系統的日益龐大和數據量的持續增長,導出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 }