你的ExcelUtil簡單、高效、易擴展嗎

你的ExcelUtil簡單、高效、易擴展嗎

Author: Dorae
Date: 2018年10月23日12:30:15
轉載請注明出處


一、背景

最近接到了和Excel導出相關的需求,但是:

  1. 項目中的excelutil工具類會存在安全問題,而且無法擴展;
  2. 一些開源的Excel工具太過重量級,并且不不能完全適合業務定制;
  3. 于是乎產生了easyExcel(巧合,和阿里的easeExcel重名了??)。

HSS、XSS

如果數據量較小的話,這種方式并不會存在問題,但是當數據量比較大時,存在非常嚴重的問題:

  1. OOM(因為數據并沒有被即使的寫入磁盤);
  2. 耗時(串行化);
  3. HSS對單sheet的數據量限制(65535),XSS為100萬+。
    HSSFWorkbook workbook = new HSSFWorkbook();
    HSSFSheet sheet = workbook.createSheet(sheetName);
    // 創建表頭
    ...
    // 寫入數據
    for (...) {
        HSSFRow textRow = sheet.createRow(rowIndex);
        for (...) {
            HSSFCell textcell = textRow.createCell(colIndex);
            textcell.setCellValue(value);
        }
    }

SXSS

為了改善上出方案的問題,SXSS采用了緩沖的方式,即按照某種策略定期刷盤。從而解決了OOM與耗時太長的問題。使用姿勢:

InputStream inputStream = new FileInputStream(file);
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(inputStream);
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(xssfWorkbook,properties.getRowAccessWindowsize());
Sheet sheet = sxssfWorkbook.getSheet(properties.getSheetName());
if (sheet == null) {
    sheet = sxssfWorkbook.createSheet(properties.getSheetName());
}
// 創建表頭
...
// 寫入數據
for (...) {
    Row row = sheet.createRow(row);
    row.setValue(value);
}
FileOutputStream outputStream = new FileOutputStream(file);
sxssfWorkbook.write(outputStream);

二、EasyUtil

雖然SXSS解決了OMM與耗時的問題,但是使用起來不太方便,會造成很多重復代碼,于是產生了EasyUtil,在介紹之前我們先思考幾個問題:

  1. excel操作有哪些公用邏輯可以抽離;
  2. 業務需求是什么,有哪些邏輯可以抽離;
  3. 如何開放較好的擴展點。

架構

按照上述的幾個問題,EasyUtil-1.0的架構如圖1-1所示,其中綠色部分為擴展點。

  1. IFillSheet為填充excel的接口,可以擴展自定義格式,目前在FillSheetModeEnums中提供了兩種(建議使用APPENDMODE);
  2. AbstractDataSupplier為需要根據業務實現的數據獲取接口,類似于stream;
  3. IExcelProcesor生成的file的后處理接口,比如可以將文件上傳到某個公共空間。
圖1-1

使用姿勢

git

戳這里

pom

<groupId>com.github.Dorae132</groupId>
<artifactId>easyutil.easyexcel</artifactId>
<version>1.1.0</version>

test
static class TestValue {
    @ExcelCol(title = "姓名")
    private String name;
    @ExcelCol(title = "年齡", order = 1)
    private String age;
    @ExcelCol(title = "學校", order = 3)
    private String school;
    @ExcelCol(title = "年級", order = 2)
    private String clazz;

    public TestValue(String name, String age, String school, String clazz) {
        super();
        this.name = name;
        this.age = age;
        this.school = school;
        this.clazz = clazz;
    }
}

private List<TestValue> getData(int count) {
    List<TestValue> dataList = Lists.newArrayListWithCapacity(10000);
    for (int i = 0; i < count; i++) {
        dataList.add(new TestValue("張三" + i, "age: " + i, null, "clazz: " + i));
    }
    return dataList;
}

@Test
public void testAppend() throws Exception {
    List<TestValue> dataList = getData(10000);
    long start = System.currentTimeMillis();
    ExcelProperties<TestValue, File> properties = ExcelProperties.produceAppendProperties("",
            "C:\\Users\\Dorae\\Desktop\\ttt\\", "append.xlsx", 0, TestValue.class, 0, null, new AbstractDataSupplier<TestValue>() {
                private int i = 0;

                @Override
                public Pair<List<TestValue>, Boolean> getDatas() {
                    boolean hasNext = i < 10;
                    i++;
                    return Pair.of(dataList, hasNext);
                }
            });
    File file = (File) ExcelUtils.excelExport(properties, FillSheetModeEnums.APPEND_MODE.getValue());
    System.out.println("apendMode: " + (System.currentTimeMillis() - start));
}

效果

  1. 10萬行4列數據耗時3s左右(我的渣渣筆記本);
  2. 對內存基本沒消耗(當然需要合適的緩沖參數)。

三、To do

  1. 導出excel和獲取數據的接口并行化;
  2. 完善utils。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,814評論 25 708
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,825評論 2 59
  • 1.每天一個水果送到嘴邊 2.每天一起跑步 3.每周一起讀一本書 4.每周親自給你下廚一次 5.每周抽出時間陪你逛...
    小寵同學閱讀 338評論 0 0
  • 甲狀腺檢查,一切安好。心安。 我盼望著你的到來,欣喜,雀躍~ 每每是平安的消息,就情不自禁的開心 兩個月零一天 依...
    藥一味閱讀 196評論 2 1
  • 我已經很多年沒有在南方過冬。據說今年的深圳經歷了最冷的一冬。從這點來看,確實令我感到有些奇妙的驚異。 在早些年之前...
    劉峰閱讀 311評論 0 2