EasyExcel是阿里巴巴开源的一款基于Java语言的Excel处理框架,相比传统的Apache POI,它采用流式读写方式,有效降低了大文件导出时的内存占用,因此在企业级系统中被广泛应用。实际业务开发中,Excel导出往往不只是单个Sheet的数据输出,而是需要按照业务模块、用户分类、时间范围等维度生成多个Sheet页。基于EasyExcel实现多Sheet数据导出,可以满足复杂报表、数据分析、运营统计等场景需求。
一、多Sheet导出的应用场景
单Sheet导出适用于数据结构简单的业务,例如用户列表、订单列表等。但随着系统功能不断扩展,数据展示需求也更加复杂,多Sheet Excel文件逐渐成为常见方案。
常见应用场景包括:
1. 分类数据导出
例如企业管理系统中,需要将不同部门的数据分别导出:
-
Sheet1:研发部门人员信息
-
Sheet2:销售部门人员信息
-
Sheet3:财务部门人员信息
用户打开Excel后即可快速定位对应数据。
2. 多维度报表生成
统计系统通常需要生成多个分析页面:
-
销售汇总数据
-
产品销售明细
-
客户订单记录
-
区域销售排名
通过多个Sheet展示不同维度的数据,可以提高报表可读性。
3. 数据分批导出
当单个Sheet数据量较大时,可以按照日期、区域或者业务类型拆分:
-
2026年1月数据
-
2026年2月数据
-
2026年3月数据
避免单个Sheet数据过多导致Excel打开缓慢。
二、EasyExcel多Sheet导出的核心原理
EasyExcel导出Excel文件主要依赖ExcelWriter对象。
普通单Sheet导出通常直接调用:
JavaEasyExcel.write(response.getOutputStream(), UserData.class) .sheet("用户信息") .doWrite(dataList);
而多Sheet导出需要使用ExcelWriter持续写入不同Sheet:
JavaExcelWriter excelWriter = EasyExcel.write(outputStream, UserData.class) .build(); WriteSheet sheet1 = EasyExcel.writerSheet(0, "用户信息") .build(); WriteSheet sheet2 = EasyExcel.writerSheet(1, "订单信息") .build(); excelWriter.write(userList, sheet1); excelWriter.write(orderList, sheet2); excelWriter.finish();
其中:
-
ExcelWriter负责整个Excel文件生命周期管理 -
WriteSheet代表一个具体Sheet页 -
write()方法负责向指定Sheet写入数据 -
finish()用于释放资源并完成文件生成
三、Spring Boot项目集成EasyExcel
在Spring Boot项目中,可以通过Maven引入EasyExcel依赖。
XMLcom.alibaba easyexcel 3.3.4
引入依赖后即可使用EasyExcel提供的导出功能。
项目结构示例:
controller └── ExcelController.java service └── ExcelExportService.java entity └── UserData.java └── OrderData.java
通常将Excel生成逻辑放在Service层,Controller只负责接收请求并返回文件流。
四、定义Excel数据实体类
EasyExcel通过实体类映射Excel列。
例如用户数据:
Java@Data public class UserData { @ExcelProperty("用户编号") private Long id; @ExcelProperty("用户名") private String username; @ExcelProperty("手机号") private String phone; }
订单数据:
Java@Data public class OrderData { @ExcelProperty("订单编号") private String orderNo; @ExcelProperty("订单金额") private BigDecimal amount; @ExcelProperty("创建时间") private Date createTime; }
通过@ExcelProperty注解,可以控制Excel表头名称和字段映射关系。
五、实现多Sheet导出完整示例
假设系统需要导出用户信息和订单信息两个Sheet。
Controller代码:
Java@GetMapping("/export") public void export(HttpServletResponse response) throws IOException { response.setContentType( "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ); response.setCharacterEncoding("UTF-8"); String fileName = URLEncoder.encode( "业务数据报表", StandardCharsets.UTF_8 ); response.setHeader( "Content-Disposition", "attachment;filename=" + fileName + ".xlsx" ); excelService.export(response.getOutputStream()); }
Service实现:
Javapublic void export(OutputStream outputStream) { List<UserData> userList = getUserData(); List<OrderData> orderList = getOrderData(); ExcelWriter excelWriter = EasyExcel.write(outputStream) .build(); WriteSheet userSheet = EasyExcel.writerSheet(0, "用户信息") .head(UserData.class) .build(); WriteSheet orderSheet = EasyExcel.writerSheet(1, "订单信息") .head(OrderData.class) .build(); excelWriter.write(userList, userSheet); excelWriter.write(orderList, orderSheet); excelWriter.finish(); }
生成后的Excel文件结构:
业务数据报表.xlsx ├── 用户信息 │ ├── 用户编号 │ ├── 用户名 │ └── 手机号 │ └── 订单信息 ├── 订单编号 ├── 订单金额 └── 创建时间
六、不同Sheet使用不同数据模型
实际开发中,不同Sheet的数据结构通常不同。
例如:
员工信息:
Java@Data public class EmployeeExcel { @ExcelProperty("员工姓名") private String name; @ExcelProperty("职位") private String position; }
薪资信息:
Java@Data public class SalaryExcel { @ExcelProperty("员工编号") private String employeeId; @ExcelProperty("基本工资") private Double salary; }
导出时:
JavaExcelWriter writer = EasyExcel.write(outputStream) .build(); writer.write( employeeList, EasyExcel.writerSheet("员工信息") .head(EmployeeExcel.class) .build() ); writer.write( salaryList, EasyExcel.writerSheet("薪资信息") .head(SalaryExcel.class) .build() ); writer.finish();
这种方式可以让每个Sheet拥有独立的表头和数据结构,更符合复杂业务需求。
七、多Sheet动态生成实现方式
很多系统中的Sheet数量并不是固定的,例如按照月份生成Sheet。
示例:
JavaExcelWriter writer = EasyExcel.write(outputStream) .build(); for(int i = 1; i <= 12; i++){ List<OrderData> list = queryOrderByMonth(i); WriteSheet sheet = EasyExcel.writerSheet( i - 1, i + "月份订单" ) .head(OrderData.class) .build(); writer.write(list, sheet); } writer.finish();
最终生成:
订单统计.xlsx ├── 1月份订单 ├── 2月份订单 ├── 3月份订单 ... └── 12月份订单
这种方式非常适合年度报表、财务统计等业务场景。
八、多Sheet导出的性能优化技巧
1. 避免一次加载全部数据
如果数据量达到几十万甚至百万级,不建议直接查询全部数据:
JavaList<Data> list = mapper.selectAll();
这种方式容易造成内存压力。
推荐分页查询:
Javaint page = 1; while(true){ List<Data> list = queryPage(page,1000); if(list.isEmpty()){ break; } writer.write(list,sheet); page++; }
利用EasyExcel流式写入,可以明显降低内存消耗。
2. 合理控制Sheet数量
虽然Excel支持多个Sheet,但过多Sheet会影响文件打开速度。
建议:
-
按业务维度拆分
-
避免生成大量空Sheet
-
控制单个文件大小
3. 使用自动关闭机制
如果手动管理资源,容易出现文件损坏。
推荐:
Javatry(ExcelWriter writer = EasyExcel.write(outputStream).build()){ writer.write(data,sheet); }
确保异常情况下资源正常释放。
九、设置Sheet样式优化展示效果
EasyExcel支持自定义样式,例如:
-
表头加粗
-
设置背景颜色
-
调整列宽
-
日期格式化
示例:
Java@HeadStyle( fillPatternType = FillPatternType.SOLID_FOREGROUND ) public class UserData { }
也可以通过WriteHandler实现更加复杂的样式控制。
十、常见问题及解决方案
1. 导出的Excel打不开
常见原因:
-
ExcelWriter.finish()未调用 -
输出流提前关闭
-
文件名编码异常
解决:
确保完整执行:
Javawriter.finish();
2. Sheet名称重复导致异常
Excel要求同一个文件中的Sheet名称不能完全相同。
错误:
JavawriterSheet("用户") writerSheet("用户")
应该修改为:
JavawriterSheet("用户1") writerSheet("用户2")
3. 大数据导出内存溢出
原因:
一次性加载大量数据到List。
解决:
-
分页查询
-
流式写入
-
控制单Sheet数据规模
4. 日期格式显示异常
可以使用:
Java@DateTimeFormat( pattern="yyyy-MM-dd" )
或者:
Java@ExcelProperty("创建时间") private String createTime;
提前格式化时间。
十一、EasyExcel多Sheet导出的优势总结
相比传统POI手动创建Workbook,EasyExcel实现多Sheet导出具有明显优势:
-
API简单,开发效率高
-
支持百万级数据流式写入
-
内存占用低
-
支持复杂表头和样式扩展
-
与Spring Boot项目结合方便
-
适合企业级报表系统开发
在实际项目中,多Sheet导出通常需要结合数据查询、权限控制、异步任务、文件存储等模块共同实现。掌握EasyExcel的多Sheet写入机制,可以有效提升Java后台系统处理Excel报表需求的能力。