SpringBoot+EasyPOI實(shí)現(xiàn)百萬級數(shù)據(jù)導(dǎo)出Excel實(shí)戰(zhàn)指南
工具簡介
本文介紹一款基于 EasyPOI 和 Apache POI SXSSF 的批量Excel導(dǎo)出工具類 BatchExcelExporter,支持大數(shù)據(jù)量分頁處理,避免內(nèi)存溢出(OOM),適合百萬級數(shù)據(jù)導(dǎo)出場景。
環(huán)境準(zhǔn)備
1. 引入Maven依賴
在 pom.xml 中添加以下依賴(確保使用最新版本):
<!-- EasyPOI 核心庫 -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
<!-- Apache POI (SXSSF 需要) -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
2. 引入工具類
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
public class BatchExcelExporter<T> {
private final SXSSFWorkbook workbook;
private final Class<T> clazz;
private final List<ExcelExportEntity> exportEntities = new ArrayList<>();
private int currentRowIndex = 0;
public BatchExcelExporter(Class<T> clazz) {
this.clazz = clazz;
this.workbook = new SXSSFWorkbook(100); // 緩存100行到磁盤
initHeader();
}
// 初始化表頭(僅執(zhí)行一次)
private void initHeader() {
// 解析實(shí)體類注解
List<Field> fields = Arrays.stream(clazz.getDeclaredFields())
.filter(f -> f.isAnnotationPresent(Excel.class))
.sorted(Comparator.comparing(f -> {
Excel excel = f.getAnnotation(Excel.class);
return excel.orderNum();
})).collect(Collectors.toList());
// 構(gòu)建導(dǎo)出結(jié)構(gòu)
fields.forEach(f -> {
Excel excel = f.getAnnotation(Excel.class);
exportEntities.add(new ExcelExportEntity(excel.name(), f.getName(), 4000));
});
// 創(chuàng)建表頭
workbook.createSheet("數(shù)據(jù)").createRow(currentRowIndex++);
addHeaderRow(workbook.getSheetAt(0).getRow(0));
}
// 添加表頭行
private void addHeaderRow(org.apache.poi.ss.usermodel.Row headerRow) {
for (int i = 0; i < exportEntities.size(); i++) {
headerRow.createCell(i).setCellValue(exportEntities.get(i).getName());
}
}
// 批量添加數(shù)據(jù)(分頁調(diào)用)
public void addBatchData(List<T> batchData) throws Exception {
org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(0);
for (T data : batchData) {
org.apache.poi.ss.usermodel.Row row = sheet.createRow(currentRowIndex++);
fillDataRow(row, data);
}
// 每500行刷新到磁盤(根據(jù)數(shù)據(jù)量調(diào)整)
if (currentRowIndex % 500 == 0) {
((SXSSFSheet) sheet).flushRows(500);
}
}
// 填充數(shù)據(jù)行(利用反射動態(tài)取值)
private void fillDataRow(org.apache.poi.ss.usermodel.Row row, T data) throws Exception {
for (int i = 0; i < exportEntities.size(); i++) {
Field field = clazz.getDeclaredField((String) exportEntities.get(i).getKey());
field.setAccessible(true);
Object value = field.get(data);
row.createCell(i).setCellValue(value != null ? value.toString() : "");
}
}
// 最終寫入文件
public void exportToFile(String filePath) throws Exception {
try (FileOutputStream fos = new FileOutputStream(filePath)) {
workbook.write(fos);
} finally {
workbook.dispose(); // 清理臨時(shí)文件
}
}
}
工具類核心功能
動態(tài)表頭生成:通過解析實(shí)體類的 @Excel 注解自動生成表頭。
分頁批量寫入:支持分批次添加數(shù)據(jù),減少內(nèi)存占用。
高性能處理:基于 SXSSFWorkbook,默認(rèn)緩存100行到磁盤。
使用示例
1. 定義實(shí)體類
public class User {
@Excel(name = "姓名", orderNum = "0")
private String name;
@Excel(name = "年齡", orderNum = "1")
private Integer age;
@Excel(name = "郵箱", orderNum = "2")
private String email;
// 省略Getter/Setter
}
2. 調(diào)用工具類導(dǎo)出數(shù)據(jù)
public class ExcelExportDemo {
public static void main(String[] args) throws Exception {
// 初始化導(dǎo)出器(指定實(shí)體類)
BatchExcelExporter<User> exporter = new BatchExcelExporter<>(User.class);
// 模擬分頁查詢數(shù)據(jù)(假設(shè)每次查詢1000條)
for (int page = 1; page <= 10; page++) {
List<User> batchData = queryUsersByPage(page, 1000);
exporter.addBatchData(batchData);
}
// 導(dǎo)出到文件
exporter.exportToFile("user_export.xlsx");
}
private static List<User> queryUsersByPage(int page, int size) {
// 模擬數(shù)據(jù)庫查詢(此處返回測試數(shù)據(jù))
List<User> users = new ArrayList<>();
for (int i = 0; i < size; i++) {
users.add(new User("User" + i, 20 + i, "user" + i + "@example.com"));
}
return users;
}
}
關(guān)鍵代碼解析
1.表頭自動生成
通過反射解析實(shí)體類的 @Excel 注解,按 orderNum 排序后生成表頭:
List<Field> fields = Arrays.stream(clazz.getDeclaredFields())
.filter(f -> f.isAnnotationPresent(Excel.class))
.sorted(Comparator.comparing(f -> f.getAnnotation(Excel.class).orderNum()))
.collect(Collectors.toList());
2.數(shù)據(jù)分頁寫入
批量添加數(shù)據(jù)時(shí),每500行刷新到磁盤(避免內(nèi)存堆積):
public void addBatchData(List<T> batchData) throws Exception {
// ... 填充數(shù)據(jù) ...
if (currentRowIndex % 500 == 0) {
((SXSSFSheet) sheet).flushRows(500); // ?? 關(guān)鍵性能優(yōu)化點(diǎn)!
}
}
注意事項(xiàng)
字段類型匹配:確保實(shí)體類字段類型與Excel數(shù)據(jù)兼容(如日期格式需特殊處理)。
性能調(diào)優(yōu):根據(jù)服務(wù)器內(nèi)存調(diào)整 SXSSFWorkbook 的緩存行數(shù)(默認(rèn)100)。
異常處理:建議添加 try-catch 塊捕獲反射和IO異常。
效果展示
導(dǎo)出后的Excel文件示例:
| 姓名 | 年齡 | 郵箱 |
|---|---|---|
| User0 | 20 | user0@example.com |
| User1 | 21 | user1@example.com |
擴(kuò)展優(yōu)化方向
- 樣式自定義:通過
SXSSFCellStyle設(shè)置單元格樣式(如背景色、邊框)。 - 多Sheet支持:擴(kuò)展工具類以支持多Sheet動態(tài)切換。
- 異步導(dǎo)出:結(jié)合線程池實(shí)現(xiàn)異步導(dǎo)出任務(wù)。
到此這篇關(guān)于SpringBoot+EasyPOI實(shí)現(xiàn)百萬級數(shù)據(jù)導(dǎo)出Excel實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)SpringBoot Excel數(shù)據(jù)導(dǎo)出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 使用EasyPoi實(shí)現(xiàn)百萬級數(shù)據(jù)導(dǎo)出的性能優(yōu)化方案
- java easyPOI實(shí)現(xiàn)導(dǎo)出一對多數(shù)據(jù)
- SpringBoot+easypoi實(shí)現(xiàn)數(shù)據(jù)的Excel導(dǎo)出
- SpringBoot種如何使用?EasyExcel?實(shí)現(xiàn)自定義表頭導(dǎo)出并實(shí)現(xiàn)數(shù)據(jù)格式化轉(zhuǎn)換
- SpringBoot利用EasyExcel實(shí)現(xiàn)導(dǎo)出數(shù)據(jù)
- SpringBoot整合EasyExcel實(shí)現(xiàn)導(dǎo)入導(dǎo)出數(shù)據(jù)
相關(guān)文章
java如何動態(tài)的處理接口的返回?cái)?shù)據(jù)
本文主要介紹了java如何動態(tài)的處理接口的返回?cái)?shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
Java注解@Conditional與@Profile的使用區(qū)別
這篇文章主要介紹了Java注解@Conditional與@Profile的使用區(qū)別,@Profile和@Conditional是Spring提供的兩種常用機(jī)制,它們可以根據(jù)不同的條件動態(tài)決定某些Bean是否加載,從而實(shí)現(xiàn)環(huán)境隔離、模塊選擇、特性開關(guān)等功能,需要的朋友可以參考下2025-05-05
FeignClientFactoryBean創(chuàng)建動態(tài)代理詳細(xì)解讀
這篇文章主要介紹了FeignClientFactoryBean創(chuàng)建動態(tài)代理詳細(xì)解讀,當(dāng)直接進(jìn)去注冊的方法中,一步步放下走,都是直接放bean的定義信息中放入值,然后轉(zhuǎn)成BeanDefinitionHolder,最后在注冊到IOC容器中,需要的朋友可以參考下2023-11-11
解決在IDEA中創(chuàng)建多級package的問題
這篇文章主要介紹了解決在IDEA中創(chuàng)建多級package的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Maven入門之使用Nexus搭建Maven私服及上傳下載jar包
這篇文章主要介紹了Maven入門之使用Nexus搭建Maven私服及上傳下載jar包,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12
ibatis學(xué)習(xí)之搭建Java項(xiàng)目
本文的主要內(nèi)容是簡單介紹了ibatis和如何通過iBatis搭建JAVA項(xiàng)目,包含了一個相關(guān)實(shí)例,需要的朋友可以參考下。2017-09-09
java實(shí)現(xiàn)科研信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java科研信息管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02

