亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

java 導(dǎo)出 excel 最佳實(shí)踐,java 大文件 excel 避免OOM(內(nèi)存溢出) exce

K_B_Z / 2182人閱讀

摘要:消費(fèi)之后,多線程處理文件導(dǎo)出,生成文件后上傳到等文件服務(wù)器。前端直接查詢并且展現(xiàn)對(duì)應(yīng)的任務(wù)執(zhí)行列表,去等文件服務(wù)器下載文件即可。這客戶體驗(yàn)不友好,而且網(wǎng)絡(luò)傳輸,系統(tǒng)占用多種問(wèn)題。拓展閱讀導(dǎo)出最佳實(shí)踐框架

產(chǎn)品需求

產(chǎn)品經(jīng)理需要導(dǎo)出一個(gè)頁(yè)面的所有的信息到 EXCEL 文件。

需求分析

對(duì)于 excel 導(dǎo)出,是一個(gè)很常見(jiàn)的需求。

最常見(jiàn)的解決方案就是使用 poi 直接同步導(dǎo)出一個(gè) excel 文件。

客戶體驗(yàn) & 服務(wù)性能

客戶體驗(yàn)

如果導(dǎo)出的文件比較大,比如幾十萬(wàn)條數(shù)據(jù),同步導(dǎo)出頁(yè)面就會(huì)卡主,用戶無(wú)法進(jìn)行其他操作。

服務(wù)性能

導(dǎo)出的時(shí)候,任務(wù)比較耗時(shí)就會(huì)阻塞主線程。

如果導(dǎo)出的服務(wù)是暴露給外部(前后端分離),這種大量的數(shù)據(jù)傳輸十分消耗性能。

解決方案

使用異常處理導(dǎo)出請(qǐng)求,后臺(tái) MQ 通知自己進(jìn)行處理。

MQ 消費(fèi)之后,多線程處理 excel 文件導(dǎo)出,生成文件后上傳到 FTP 等文件服務(wù)器。

前端直接查詢并且展現(xiàn)對(duì)應(yīng)的任務(wù)執(zhí)行列表,去 FTP 等文件服務(wù)器下載文件即可。

EXCEL 導(dǎo)出需要考慮的問(wèn)題 OOM

正常的 poi 在處理比較大的 excel 的時(shí)候,會(huì)出現(xiàn)內(nèi)存溢出。

網(wǎng)上的解決方案也比較多。

比如官方的 SXSSF (Since POI 3.8 beta3) 解決方式。

或者使用封裝好的包

easypoi ExcelBatchExportServer

hutool BigExcelWriter

原理都是強(qiáng)制使用 xssf 版本的Excel。

你也可以使用 easyexcel,當(dāng)然這個(gè)注釋文檔有些欠缺,而且設(shè)計(jì)的比較復(fù)雜,不是很推薦。

我這里使用的是 hutool BigExcelWriter,
懶得自己再寫一遍。

FULL GC

如果一次查詢 100W 條數(shù)據(jù)庫(kù),然后把這些信息全部加載到內(nèi)存中,是不可取的。

建議有2個(gè):

限制每一次分頁(yè)的數(shù)量。比如一次最多查詢 1w 條。分成 100 次查詢。(必須)

限制查詢得總條數(shù)。比如限制為最多 10W 條。(根據(jù)實(shí)際情況選擇)

雖然使用者提出要導(dǎo)出類似于 3 個(gè)月的所有信息,但是數(shù)量太多,毫無(wú)意義。(提出者自己可能體會(huì)不到)

盡量避免 FULL-GC 的情況發(fā)生,因?yàn)槟壳暗乃蟹绞綄?duì)于 excel 的輸出流都會(huì)占用內(nèi)存,100W 條很容易導(dǎo)致 FULL-GC。

數(shù)據(jù)庫(kù)的壓力

去數(shù)據(jù)庫(kù)讀取的時(shí)候一定要記得分頁(yè),免得給數(shù)據(jù)庫(kù)太大的壓力。

一次讀取太多,也會(huì)導(dǎo)致內(nèi)存直線上升。

比如 100W 條數(shù)據(jù),則分成 100 次去數(shù)據(jù)庫(kù)讀取。

網(wǎng)絡(luò)傳輸

傳統(tǒng)的 excel 導(dǎo)出,都是前端一個(gè)請(qǐng)求,直接 HTTP 同步返回。導(dǎo)出 100W 條,就在那里傻等。

這客戶體驗(yàn)不友好,而且網(wǎng)絡(luò)傳輸,系統(tǒng)占用多種問(wèn)題。

建議使用異步處理的方式,將文件上傳到文件服務(wù)器。前端直接去文件服務(wù)器讀取。

編程的便利性

對(duì)于上面提到的工具,比如 Hutool,在表頭的處理方面沒(méi)法很方便的統(tǒng)一。

你可以自己定義類似于 easypoi/easyexcel 中的注解,自己反射解析。

然后統(tǒng)一處理表頭即可。

IExcel 方便優(yōu)雅的 excel 框架 特性

OO 的方式操作 excel,編程更加方便優(yōu)雅。

sax 模式讀取,SXSS 模式寫入。避免 excel 大文件 OOM。

基于注解,編程更加靈活。

寫入可以基于對(duì)象列表,也可以基于 Map,實(shí)際使用更加方便。

設(shè)計(jì)簡(jiǎn)單,注釋完整。方便大家學(xué)習(xí)改造。

后期特性

讀取跳過(guò)空白行

excel 樣式相關(guān)的注解開發(fā)

創(chuàng)作緣由

實(shí)際工作和學(xué)習(xí)中,apache poi 操作 excel 過(guò)于復(fù)雜。

近期也看了一些其他的工具框架:

easypoi

easyexcel

hutool-poi

都或多或少難以滿足自己的實(shí)際需要,于是就自己寫了一個(gè)操作 excel 導(dǎo)出的工具。

快速開始 引入 Jar

使用 maven 管理。


     com.github.houbb
     iexcel
     0.0.2
定義對(duì)象

你可以直接參考 ExcelUtilTest.java

定義一個(gè)需要寫入/讀取的 excel 對(duì)象。

ExcelFieldModel.java

只有聲明了 @ExcelField 的屬性才會(huì)被處理,使用說(shuō)明:@ExcelField

public class ExcelFieldModel {

    @ExcelField
    private String name;

    @ExcelField(headName = "年齡")
    private String age;

    @ExcelField(mapKey = "EMAIL", writeRequire = false, readRequire = false)
    private String email;

    @ExcelField(mapKey = "ADDRESS", headName = "地址", writeRequire = true)
    private String address;
    
    //getter and setter
}
寫入例子 IExcelWriter 的實(shí)現(xiàn)

IExcelWriter 有幾個(gè)實(shí)現(xiàn)類,你可以直接 new 或者借助 ExcelUtil 類去創(chuàng)建。

IExcelWriter 實(shí)現(xiàn)類 ExcelUtil 如何創(chuàng)建 說(shuō)明
HSSFExcelWriter ExcelUtil.get03ExcelWriter() 2003 版本的 excel
XSSFExcelWriter ExcelUtil.get07ExcelWriter() 2007 版本的 excel
SXSSFExcelWriter ExcelUtil.getBigExcelWriter() 大文件 excel,避免 OOM
IExcelWriter 接口說(shuō)明
寫入到 2003

excelWriter03Test()

一個(gè)將對(duì)象列表寫入 2003 excel 文件的例子。

/**
 * 寫入到 03 excel 文件
 */
@Test
public void excelWriter03Test() {
    // 待生成的 excel 文件路徑
    final String filePath = "excelWriter03.xls";

    // 對(duì)象列表
    List models = buildModelList();

    try(IExcelWriter excelWriter = ExcelUtil.get03ExcelWriter();
        OutputStream outputStream = new FileOutputStream(filePath)) {
        // 可根據(jù)實(shí)際需要,多次寫入列表
        excelWriter.write(models);

        // 將列表內(nèi)容真正的輸出到 excel 文件
        excelWriter.flush(outputStream);
    } catch (IOException e) {
        throw new ExcelRuntimeException(e);
    }
}

buildModelList()

/**
 * 構(gòu)建測(cè)試的對(duì)象列表
 * @return 對(duì)象列表
 */
private List buildModelList() {
    List models = new ArrayList<>();
    ExcelFieldModel model = new ExcelFieldModel();
    model.setName("測(cè)試1號(hào)");
    model.setAge("25");
    model.setEmail("123@gmail.com");
    model.setAddress("貝克街23號(hào)");

    ExcelFieldModel modelTwo = new ExcelFieldModel();
    modelTwo.setName("測(cè)試2號(hào)");
    modelTwo.setAge("30");
    modelTwo.setEmail("125@gmail.com");
    modelTwo.setAddress("貝克街26號(hào)");

    models.add(model);
    models.add(modelTwo);
    return models;
}
一次性寫入到 2007 excel

有時(shí)候列表只寫入一次很常見(jiàn),所有就簡(jiǎn)單的封裝了下:

/**
 * 只寫入一次列表
 * 其實(shí)是對(duì)原來(lái)方法的簡(jiǎn)單封裝
 */
@Test
public void onceWriterAndFlush07Test() {
    // 待生成的 excel 文件路徑
    final String filePath = "onceWriterAndFlush07.xlsx";

    // 對(duì)象列表
    List models = buildModelList();

    // 對(duì)應(yīng)的 excel 寫入對(duì)象
    IExcelWriter excelWriter = ExcelUtil.get07ExcelWriter();

    // 只寫入一次列表
    ExcelUtil.onceWriteAndFlush(excelWriter, models, filePath);
}
讀取例子

excel 讀取時(shí)會(huì)根據(jù)文件名稱判斷是哪個(gè)版本的 excel。

IExcelReader 的實(shí)現(xiàn)

IExcelReader 有幾個(gè)實(shí)現(xiàn)類,你可以直接 new 或者借助 ExcelUtil 類去創(chuàng)建。

IExcelReader 實(shí)現(xiàn)類 ExcelUtil 如何創(chuàng)建 說(shuō)明
ExcelReader ExcelUtil.getExcelReader() 小文件的 excel 讀取實(shí)現(xiàn)
Sax03ExcelReader ExcelUtil.getBigExcelReader() 大文件的 2003 excel 讀取實(shí)現(xiàn)
Sax07ExcelReader ExcelUtil.getBigExcelReader() 大文件的 2007 excel 讀取實(shí)現(xiàn)
IExcelReader 接口說(shuō)明
excel 讀取的例子
/**
 * 讀取測(cè)試
 */
@Test
public void readWriterTest() {
    File file = new File("excelWriter03.xls");
    IExcelReader excelReader = ExcelUtil.getExcelReader(file);
    List models = excelReader.readAll(ExcelFieldModel.class);
    System.out.println(models);
}
ExcelField 注解說(shuō)明

@ExcelField 的屬性說(shuō)明如下:

屬性 類型 默認(rèn)值 說(shuō)明
mapKey String "" 僅用于生成的入?yún)?map 時(shí),會(huì)將 map.key 對(duì)應(yīng)的值映射到 bean 上。如果不傳:默認(rèn)使用當(dāng)前字段名稱
headName String "" excel 表頭字段名稱,如果不傳:默認(rèn)使用當(dāng)前字段名稱
writeRequire boolean true excel 文件是否需要寫入此字段
readRequire boolean true excel 文件是否讀取此字段
IExcelWriter 接口說(shuō)明
/**
 * 寫出數(shù)據(jù),本方法只是將數(shù)據(jù)寫入Workbook中的Sheet,并不寫出到文件
*

* data中元素支持的類型有: *

 * 1. Bean,既元素為一個(gè)Bean,第一個(gè)Bean的字段名列表會(huì)作為首行,剩下的行為Bean的字段值列表,data表示多行 
*
* @param data 數(shù)據(jù) * @return this */ IExcelWriter write(Collection data); /** * 寫出數(shù)據(jù),本方法只是將數(shù)據(jù)寫入Workbook中的Sheet,并不寫出到文件
* 將 map 按照 targetClass 轉(zhuǎn)換為對(duì)象列表 * 應(yīng)用場(chǎng)景: 直接 mybatis mapper 查詢出的 map 結(jié)果,或者其他的構(gòu)造結(jié)果。 * @param mapList map 集合 * @param targetClass 目標(biāo)類型 * @return this */ IExcelWriter write(Collection> mapList, final Class targetClass); /** * 將Excel Workbook刷出到輸出流 * * @param outputStream 輸出流 * @return this */ IExcelWriter flush(OutputStream outputStream);
指定 sheet

創(chuàng)建 IExcelWriter 的時(shí)候,可以指定 sheet 的下標(biāo)或者名稱。來(lái)指定寫入的 sheet。

是否包含表頭

創(chuàng)建 IExcelWriter 的后,可以調(diào)用 excelWriter.containsHead(bool) 指定是否生成 excel 表頭。

IExcelReader 接口說(shuō)明
/**
 * 讀取當(dāng)前 sheet 的所有信息
 * @param tClass 對(duì)應(yīng)的 javabean 類型
 * @return 對(duì)象列表
 */
List readAll(Class tClass);

/**
 * 讀取指定范圍內(nèi)的
 * @param tClass 泛型
 * @param startIndex 開始的行信息(從0開始)
 * @param endIndex 結(jié)束的行信息
 * @return 讀取的對(duì)象列表
 */
List read(Class tClass, final int startIndex, final int endIndex);
指定 sheet

創(chuàng)建 IExcelReader 的時(shí)候,可以指定 sheet 的下標(biāo)或者名稱。來(lái)指定讀取的 sheet。

注意:大文件 sax 讀取模式,只支持指定 sheet 的下標(biāo)。

是否包含表頭

創(chuàng)建 IExcelReader 的后,可以調(diào)用 excelReader.containsHead(bool) 指定是否讀取 excel 表頭。

拓展閱讀

excel 導(dǎo)出最佳實(shí)踐

iexcel 框架

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/72442.html

相關(guān)文章

  • Excel批量數(shù)據(jù)的導(dǎo)入和導(dǎo)出,如何做優(yōu)化?

    摘要:并且在對(duì)的抽象中,每一行,每一個(gè)單元格都是一個(gè)對(duì)象。對(duì)支持使用官方例子需要繼承,覆蓋方法,每讀取到一個(gè)單元格的數(shù)據(jù)則會(huì)回調(diào)次方法。概要Java對(duì)Excel的操作一般都是用POI,但是數(shù)據(jù)量大的話可能會(huì)導(dǎo)致頻繁的FGC或OOM,這篇文章跟大家說(shuō)下如果避免踩POI的坑,以及分別對(duì)于xls和xlsx文件怎么優(yōu)化大批量數(shù)據(jù)的導(dǎo)入和導(dǎo)出。一次線上問(wèn)題這是一次線上的問(wèn)題,因?yàn)橐粋€(gè)大數(shù)據(jù)量的Excel導(dǎo)出...

    Tecode 評(píng)論0 收藏0
  • POI讀取文件最佳實(shí)踐

    摘要:我最近做的一個(gè)工具就是讀取計(jì)算機(jī)中的以及文件。經(jīng)常在讀取某些特別大的文件的時(shí)候都會(huì)帶來(lái)一個(gè)內(nèi)存溢出的問(wèn)題。以上,就是我在使用讀取文件的一些探索和發(fā)現(xiàn),希望對(duì)你能有所幫助。 POI是 Apache 旗下一款讀寫微軟家文檔聲名顯赫的類庫(kù)。應(yīng)該很多人在做報(bào)表的導(dǎo)出,或者創(chuàng)建 word 文檔以及讀取之類的都是用過(guò) POI。POI 也的確對(duì)于這些操作帶來(lái)很大的便利性。我最近做的一個(gè)工具就是讀取計(jì)...

    bingchen 評(píng)論0 收藏0
  • Java開發(fā)

    摘要:大多數(shù)待遇豐厚的開發(fā)職位都要求開發(fā)者精通多線程技術(shù)并且有豐富的程序開發(fā)調(diào)試優(yōu)化經(jīng)驗(yàn),所以線程相關(guān)的問(wèn)題在面試中經(jīng)常會(huì)被提到。將對(duì)象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對(duì)象稱之為反序列化。 JVM 內(nèi)存溢出實(shí)例 - 實(shí)戰(zhàn) JVM(二) 介紹 JVM 內(nèi)存溢出產(chǎn)生情況分析 Java - 注解詳解 詳細(xì)介紹 Java 注解的使用,有利于學(xué)習(xí)編譯時(shí)注解 Java 程序員快速上手 Kot...

    LuDongWei 評(píng)論0 收藏0
  • PHP實(shí)時(shí)生成并下載超數(shù)據(jù)量的EXCEL文件

    摘要:而常用的包需要把所有數(shù)據(jù)拿到后才能生成,在面對(duì)生成超大數(shù)據(jù)量的文件時(shí)這顯然是會(huì)造成內(nèi)存溢出的,所以考慮使用讓邊寫入輸出流邊讓瀏覽器下載的形式來(lái)完成需求。 最近接到一個(gè)需求,通過(guò)選擇的時(shí)間段導(dǎo)出對(duì)應(yīng)的用戶訪問(wèn)日志到excel中, 由于用戶量較大,經(jīng)常會(huì)有導(dǎo)出50萬(wàn)加數(shù)據(jù)的情況。而常用的PHPexcel包需要把所有數(shù)據(jù)拿到后才能生成excel, 在面對(duì)生成超大數(shù)據(jù)量的excel文件時(shí)這顯然...

    Neilyo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

K_B_Z

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<