使用 Spring Boot + EasyExcel 實現百萬級數據導入導出功能開發
在當今數據驅動的業務環境中,高效地處理大量數據是至關重要的。Spring Boot 作為一種流行的 Java 框架,提供了許多方便的功能來簡化開發過程。EasyExcel 則是一個強大的工具,專門用于處理 Excel 文件。本文將介紹如何結合使用 Spring Boot 和 EasyExcel 來實現百萬級數據的導入導出功能。
EasyExcel 框架及特性介紹
EasyExcel 是一個基于 Java 的 Excel 處理框架,具有以下顯著特性:
- 內存優化:能夠高效處理大文件,避免內存溢出問題,尤其在處理百萬級數據時表現出色。
- 簡單易用:提供了簡潔直觀的 API,使開發人員可以輕松地進行 Excel 文件的讀取、寫入和處理操作。
- 性能卓越:在數據處理速度方面具有優勢,能夠快速完成大規模數據的操作。
- 支持多種格式:不僅可以處理常見的 Excel 格式,還能適應不同的需求。
項目創建及依賴配置(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.icoderoad</groupId>
<artifactId>easyexcel-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>EasyExcel Demo</name>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
項目文件結構:
project-root/
src/
main/
java/
com/
icoderoad/
Application.java // Spring Boot 啟動類
controller/ExcelController // 控制器類
service/ExcelService.java // 服務類
config/EasyExcelConfig.java
resources/
application.yaml // 配置文件
static/index.html // 靜態資源,如 CSS、JS、圖片等
pom.xml // Maven 項目配置文件
配置文件(application.yml)
# 在此處可添加您的應用特定配置
easyexcel:
# 例如,設置最大讀取行數
max-read-rows: 1000000
# 大文件處理配置
large-file:
# 啟用大文件處理
enabled: true
# 內存緩沖區大小(字節)
buffer-size: 10485760
# 每次讀取的行數
read-rows-per-time: 10000
啟動類 Application.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
配置類 EasyExcelConfig.java
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.event.AnalysisEventListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.yaml.snakeyaml.Yaml;
/**
* EasyExcel 配置類,負責讀取和設置相關配置參數
*/
@Configuration
public class EasyExcelConfig {
@Value("${excel.read.maxRows}")
private int maxRows;
@Value("${excel.read.useDefaultListener}")
private boolean useDefaultListener;
@Value("${excel.read.readCacheSize}")
private int readCacheSize;
/**
* 創建 Excel 事件監聽器
* @return 分析事件監聽器實例
*/
@Bean
public AnalysisEventListener excelEventListener() {
return new ExcelListener();
}
/**
* 創建 EasyExcel 實例
* @return EasyExcel 實例
*/
@Bean
public EasyExcel easyExcel() {
return new EasyExcel();
}
/**
* 創建并設置 ReadExcelProperties
* @return ReadExcelProperties 實例
*/
@Bean
public ReadExcelProperties readExcelProperties() {
ReadExcelProperties properties = new ReadExcelProperties();
properties.setMaxRows(maxRows);
properties.setUseDefaultListener(useDefaultListener);
properties.setReadCacheSize(readCacheSize);
return properties;
}
}
服務接口定義及實現 ExcelService.java
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import org.springframework.stereotype.Service;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@Service
public class ExcelService {
// 示例方法
public void exportData() {
// 創建數據列表
List<List<String>> data = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
List<String> row = new ArrayList<>();
row.add("Row " + i);
row.add("Column 1");
row.add("Column 2");
data.add(row);
}
// 創建輸出流
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream("exported_data.xlsx");
} catch (IOException e) {
e.printStackTrace();
}
// 創建 ExcelWriter
ExcelWriter excelWriter = EasyExcel.write(outputStream)
.withTemplate("template.xlsx")
.build();
// 創建 WriteSheet
WriteSheet writeSheet = EasyExcel.writerSheet()
.sheetName("Sheet1")
.build();
// 填充數據
excelWriter.fill(data, new FillConfig());
// 關閉 ExcelWriter
excelWriter.finish();
// 關閉輸出流
try {
if (outputStream!= null) {
outputStream.close();
}
}
public void importData() {
EasyExcel.read("imported_data.xlsx", new ExcelListener()).sheet().doRead();
}
// 自定義監聽器,用于處理導入的數據
static class ExcelListener extends AnalysisEventListener {
private List<List<String>> data = new ArrayList<>();
@Override
public void invoke(Object object, AnalysisContext context) {
if (object instanceof List<?>) {
List<String> rowData = (List<String>) object;
data.add(rowData);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 在此處添加導入完成后的其他處理邏輯,例如數據校驗、數據存儲等
System.out.println("數據導入完成,共 " + data.size() + " 行數據。");
}
}
}
控制器類 ExcelController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ExcelController {
@Autowired
private ExcelService excelService;
@GetMapping("/export")
public String exportData() {
excelService.exportData();
return "數據導出成功";
}
@GetMapping("/import")
public String importData() {
excelService.importData();
return "數據導入成功";
}
}
前端頁面 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Excel 操作</title>
</head>
<body>
<h1>Excel 操作</h1>
<button onclick="exportData()">導出數據</button>
<button onclick="importData()">導入數據</button>
<script>
function exportData() {
fetch('/export')
.then(response => response.text())
.then(data => {
alert(data);
})
.catch(error => {
alert('導出數據失敗: 'rror);
});
}
function importData() {
fetch('/import')
.then(response => response.text())
.then(data => {
alert(data);
})
.catch(error => {
alert('導入數據失敗: 'rror);
});
}
</script>
</body>
</html>
在實際開發中,大家需要根據具體的業務需求對數據的處理邏輯進行進一步的優化和完善。同時,還需要考慮異常處理、數據校驗等方面,以確保系統的穩定性和可靠性。希望本文能夠幫助大家成功實現百萬級數據的導入導出功能,為大家的業務提供有力的支持。