使用 EasyExcel 轻松实现 Java Excel 导入导出:从入门到实战
在企业级应用开发中,Excel 文件的导入导出是非常常见的需求。传统的 POI 框架虽然功能强大,但 API 复杂且对大数据量处理不够友好。阿里巴巴开源的 EasyExcel 框架基于 POI 进行了高度封装,提供了更简洁的 API 和更高效的内存管理,尤其适合处理大规模数据。本文将通过一个完整的 Spring Boot 项目,详细讲解如何使用 EasyExcel 实现 Excel 的导入导出功能。
一、开发环境准备
1. 技术栈选择
- Java 8+:主流开发语言
- Spring Boot 2.7.5:快速构建 Java 应用
- EasyExcel 3.1.1:轻量级 Excel 处理框架
- Lombok:简化 JavaBean 开发
2. Maven 依赖配置
在pom.xml中添加核心依赖:
<dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- EasyExcel核心库 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.1.1</version> </dependency> <!-- Lombok注解 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency></dependencies>
二、核心功能实现
1. 定义数据实体类
创建Student实体类,通过 EasyExcel 注解配置字段映射和表头样式:
@Data@AllArgsConstructor@NoArgsConstructorpublic class Student { // 表头名称为"学号",列宽20 @ExcelProperty(value = "学号", index = 0) @ColumnWidth(20) private Long studentId; // 表头名称为"姓名",列宽15 @ExcelProperty(value = "姓名", index = 1) @ColumnWidth(15) private String studentName; // 表头名称为"年龄",指定格式转换器 @ExcelProperty(value = "年龄", index = 2) private Integer age; // 忽略该字段,不参与Excel读写 @ExcelIgnore private String remark;}
2. 实现数据监听器(导入功能)
通过流式读取处理大数据量,避免内存溢出:
public class StudentDataListener extends AnalysisEventListener<Student> { private List<Student> studentList = new ArrayList<>(); // 逐行读取时调用 @Override public void invoke(Student student, AnalysisContext context) { studentList.add(student); // 每5000条数据批量处理(可根据需求调整) if (studentList.size() >= 5000) { saveData(studentList); studentList.clear(); } } // 所有数据读取完成后调用 @Override public void doAfterAllAnalysed(AnalysisContext context) { saveData(studentList); // 处理剩余数据 } private void saveData(List<Student> data) { // 这里可以替换为实际的数据库批量插入操作 System.out.println("批量处理数据,数据量:" + data.size()); }}
3. 封装业务服务类
实现 Excel 导出的核心逻辑,支持普通导出和带样式导出:
@Servicepublic class ExcelService { // 简单导出(默认样式) public void exportSimpleExcel(HttpServletResponse response) throws IOException { List<Student> dataList = generateTestData(); // 生成测试数据 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("学生信息表", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); EasyExcel.write(response.getOutputStream(), Student.class).sheet("学生列表").doWrite(dataList); } // 复杂导出(自定义样式) public void exportStyledExcel(HttpServletResponse response) throws IOException { List<Student> dataList = generateTestData(); // 配置标题样式 WriteCellStyle headCellStyle = new WriteCellStyle(); headCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); // 配置内容样式 WriteCellStyle contentCellStyle = new WriteCellStyle(); contentCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); // 注册样式策略 HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(headCellStyle, contentCellStyle); EasyExcel.write(response.getOutputStream(), Student.class) .registerWriteHandler(styleStrategy) .sheet("学生列表") .doWrite(dataList); } // 导入功能核心方法 public void importExcel(MultipartFile file) throws IOException { EasyExcel.read(file.getInputStream(), Student.class, new StudentDataListener()).sheet().doRead(); } private List<Student> generateTestData() { // 生成100条测试数据(可根据需要扩展) List<Student> dataList = new ArrayList<>(); for (int i = 1; i <= 100; i++) { dataList.add(new Student((long) i, "学生" + i, 18 + i % 5)); } return dataList; }}
4. 创建控制器接口
提供 RESTful 接口实现功能调用:
@RestController@RequestMapping("/excel")public class ExcelController { @Resource private ExcelService excelService; // 简单导出接口 @GetMapping("/export/simple") public void exportSimpleExcel(HttpServletResponse response) throws IOException { excelService.exportSimpleExcel(response); } // 带样式导出接口 @GetMapping("/export/styled") public void exportStyledExcel(HttpServletResponse response) throws IOException { excelService.exportStyledExcel(response); } // 导入接口 @PostMapping("/import") public String importExcel(@RequestParam("file") MultipartFile file) { try { excelService.importExcel(file); return "导入成功"; } catch (Exception e) { return "导入失败:" + e.getMessage(); } }}
三、项目核心特性解析
1. 高效的内存管理
- 流式处理:采用 SAX 模式逐行读取,内存占用低(处理 10 万条数据仅需约 100MB 内存)
- 批量处理:通过数据监听器实现分批数据持久化,避免单次处理数据量过大
2. 灵活的注解配置
注解 | 功能说明 | 示例用法 |
@ExcelProperty | 字段与表头映射,支持索引或名称 | @ExcelProperty("学号") |
@ColumnWidth | 自定义列宽 | @ColumnWidth(20) |
@ExcelIgnore | 忽略字段 | @ExcelIgnore |
@DateTimeFormat | 日期格式转换 | @DateTimeFormat("yyyy-MM-dd") |
@NumberFormat | 数字格式转换 | @NumberFormat("#.##") |
3. 完善的异常处理
- 文件格式校验:自动识别 Excel 2003/2007 格式
- 类型转换异常:支持自定义异常处理器
- 内存溢出保护:通过数据分片策略避免 OOM
四、功能测试验证
1. 导出功能测试
- 使用 Postman 发送 GET 请求到/excel/export/simple,浏览器会自动下载 Excel 文件
- 带样式导出接口/excel/export/styled会生成带灰色表头和居中对齐的表格
2. 导入功能测试
- 通过表单上传 Excel 文件(需符合 Student 实体类字段要求),成功后返回 "导入成功"
- 支持批量处理最大 10 万条数据(可通过AnalysisContext配置调整批次大小)
五、总结与最佳实践
1. 适用场景
- 大数据量 Excel 处理(建议单文件不超过 50MB)
- 复杂表头格式配置
- 高性能要求的批量导入导出
2. 优化建议
- 数据校验:在数据监听器中添加字段合法性校验
- 日志记录:对导入导出操作添加完整的日志跟踪
- 事务管理:在批量数据持久化时添加数据库事务
- 文件存储:支持本地文件系统、云存储等多种存储方式
3. 开源生态
EasyExcel 提供了丰富的扩展能力:
- 支持自定义转换器(Converter接口)
- 灵活的写入处理器(WriteHandler接口)
- 集成 Spring Boot 实现自动配置
通过本文的实战案例,我们展示了如何利用 EasyExcel 简化 Excel 操作,实现高效的导入导出功能。相比传统 POI 框架,EasyExcel 在代码简洁性和性能上都有明显优势,尤其适合企业级应用开发。完整的项目代码可以在GitHub 仓库获取,欢迎 Star 和 Fork。
如果在实际开发中遇到复杂格式处理或性能优化问题,建议参考官方文档(EasyExcel 官方文档)或加入技术交流群,获取更多最佳实践。