使用 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>
在实际开发中,大家需要根据具体的业务需求对数据的处理逻辑进行进一步的优化和完善。同时,还需要考虑异常处理、数据校验等方面,以确保系统的稳定性和可靠性。希望本文能够帮助大家成功实现百万级数据的导入导出功能,为大家的业务提供有力的支持。