Spring Boot 集成 EasyExcel 輕松搞定百萬級數據導出
在企業級應用開發中,數據導出是一個常見的需求。當面臨百萬級數據導出時,傳統的數據導出方式往往會出現性能瓶頸,導致內存溢出、導出速度慢等問題。Spring Boot 框架提供了靈活的開發環境,而 EasyExcel 是一款基于 Java 的高性能 Excel 操作庫,能夠高效地處理百萬級數據導出。本文將詳細介紹如何在 Spring Boot 項目中集成 EasyExcel,實現輕松搞定百萬級數據導出。
一、環境搭建
在開始之前,我們需要搭建一個 Spring Boot 項目。如果你還沒有搭建過 Spring Boot 項目,可以通過 Spring Initializr (https://start.spring.io/) 快速生成一個項目模板。然后,在項目的pom.xml文件中添加 EasyExcel 的依賴。
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- EasyExcel Starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
</dependencies>
接下來,我們需要配置 Excel 文件的路徑和文件名。在application.yml文件中添加以下配置:
excel:
path: ./excel
filename-prefix: data_
headers:
- id
- name
- age
- department
這里,我們配置了 Excel 文件的存儲路徑為項目根目錄下的excel文件夾,文件名前綴為data_,表頭信息包括id、name、age和department。
二、創建 Excel 模型類
為了將數據寫入 Excel 文件,我們需要創建一個 Excel 模型類。該類用于表示 Excel 文件中的數據結構,并使用@ExcelProperty注解標記每個字段。
import com.alibaba.excel.annotation.ExcelProperty;
public class DataModel {
@ExcelProperty("ID")
private Long id;
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年齡")
private Integer age;
@ExcelProperty("部門")
private String department;
// getter 和 setter 方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
在上面的代碼中,我們創建了一個DataModel類,包含了id、name、age和department四個字段。每個字段都使用@ExcelProperty注解標記了對應的表頭名稱。這樣,當我們將數據寫入 Excel 文件時,字段值會按照注解中的名稱寫入對應的列。
三、編寫數據導出服務類
數據導出服務類是實現數據導出的核心部分。我們需要從數據庫中查詢數據,并使用 EasyExcel 將數據寫入 Excel 文件。
import com.alibaba.excel.EasyExcel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ExportService {
@Value("${excel.path}")
private String excelPath;
@Value("${excel.filename-prefix}")
private String filenamePrefix;
public void exportData(List<DataModel> dataModels) {
// 生成文件名
String fileName = excelPath + "/" + filenamePrefix + System.currentTimeMillis() + ".xlsx";
// 使用 EasyExcel 寫入數據
EasyExcel.write(fileName, DataModel.class).sheet("Sheet1").doWrite(dataModels);
}
}
在上面的代碼中,我們創建了一個ExportService類,用于實現數據導出功能。該類注入了 Excel 文件的存儲路徑和文件名前綴,并提供了一個exportData方法。在exportData方法中,我們生成了一個唯一的文件名,然后使用 EasyExcel 的write方法將數據寫入 Excel 文件。write方法的參數包括文件名、數據模型類和工作表名稱,最后通過doWrite方法將數據寫入文件。
四、創建控制器類
為了方便用戶調用數據導出功能,我們需要創建一個控制器類,暴露 REST API 接口。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ExportController {
@Autowired
private ExportService exportService;
@GetMapping("/export")
public String exportData() {
// 模擬從數據庫中查詢數據
List<DataModel> dataModels = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
DataModel dataModel = new DataModel();
dataModel.setId((long) i);
dataModel.setName("User" + i);
dataModel.setAge(30);
dataModel.setDepartment("Department" + i % 10);
dataModels.add(dataModel);
}
// 調用數據導出服務
exportService.exportData(dataModels);
return "Data exported successfully!";
}
}
在上面的代碼中,我們創建了一個ExportController類,用于處理數據導出的請求。該類注入了ExportService類,并提供了一個/export的 GET 請求接口。在exportData方法中,我們模擬了從數據庫中查詢數據的過程,生成了一個包含 1000000 條數據的列表。然后,調用exportService的數據導出功能,將數據寫入 Excel 文件。
五、性能優化
在處理百萬級數據導出時,性能優化是關鍵。EasyExcel 采用流式讀寫的方式,避免了大量數據對內存的占用。我們可以通過以下方式進行性能優化:
1. 使用異步導出
對于大規模數據導出,可以使用異步處理的方式,避免主線程被阻塞。Spring Boot 提供了@Async注解,可以方便地實現異步導出。
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ExportService {
@Value("${excel.path}")
private String excelPath;
@Value("${excel.filename-prefix}")
private String filenamePrefix;
@Async
public void exportData(List<DataModel> dataModels) {
// 生成文件名
String fileName = excelPath + "/" + filenamePrefix + System.currentTimeMillis() + ".xlsx";
// 使用 EasyExcel 寫入數據
EasyExcel.write(fileName, DataModel.class).sheet("Sheet1").doWrite(dataModels);
}
}
在上面的代碼中,我們在exportData方法上添加了@Async注解,將其標記為異步方法。這樣,當用戶調用數據導出接口時,數據導出將在后臺線程中執行,不會阻塞主線程。
2. 分頁查詢數據
如果數據量非常大,一次性從數據庫中查詢所有數據可能會導致內存不足。可以通過分頁查詢的方式,分批次加載數據,并使用 EasyExcel 將數據分批次寫入 Excel 文件。
import com.alibaba.excel.EasyExcel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ExportService {
@Value("${excel.path}")
private String excelPath;
@Value("${excel.filename-prefix}")
private String filenamePrefix;
public void exportDataByPage() {
// 生成文件名
String fileName = excelPath + "/" + filenamePrefix + System.currentTimeMillis() + ".xlsx";
// 使用 EasyExcel 寫入數據
EasyExcel.write(fileName, DataModel.class).sheet("Sheet1").doWrite(data -> {
// 分頁查詢數據
for (int pageNum = 1; ; pageNum++) {
List<DataModel> dataModels = queryDataByPage(pageNum, 1000);
if (dataModels.isEmpty()) {
break;
}
data.write(dataModels);
}
});
}
private List<DataModel> queryDataByPage(int pageNum, int pageSize) {
// 模擬分頁查詢數據
List<DataModel> dataModels = new ArrayList<>();
int start = (pageNum - 1) * pageSize;
for (int i = start; i < start + pageSize; i++) {
DataModel dataModel = new DataModel();
dataModel.setId((long) i);
dataModel.setName("User" + i);
dataModel.setAge(30);
dataModel.setDepartment("Department" + i % 10);
dataModels.add(dataModel);
}
return dataModels;
}
}
在上面的代碼中,我們使用了分頁查詢的方式,每次查詢 1000 條數據,并將數據分批次寫入 Excel 文件。這樣可以減少內存的占用,并提高數據導出的性能。
六、測試與驗證
在完成數據導出功能的開發后,需要進行測試與驗證。我們可以通過以下步驟進行測試:
1. 準備測試數據
首先,我們需要準備一些測試數據。可以使用數據生成工具,或者手動創建一些數據。例如,可以創建一個包含 1000000 條記錄的數據庫表。
2. 調用數據導出接口
啟動 Spring Boot 應用程序,并訪問/export接口,觸發數據導出功能。
3. 檢查導出結果
檢查生成的 Excel 文件是否包含所有數據,并且數據格式是否正確。可以使用 Excel 軟件打開文件,查看數據是否按照預期排列。
4. 測試性能
可以使用性能測試工具,如 JMeter 或 Gatling,對數據導出接口進行測試,記錄導出時間、內存占用、CPU 使用率等指標,評估數據導出功能的性能表現。