EasyExcel进阶:从基础导入导出到复杂报表与Web应用实战

张开发
2026/4/17 10:32:06 15 分钟阅读

分享文章

EasyExcel进阶:从基础导入导出到复杂报表与Web应用实战
1. EasyExcel核心优势与基础操作第一次接触EasyExcel是在2018年处理一个百万级数据导出需求时。当时用传统POI经常内存溢出而EasyExcel只用200MB内存就完成了任务从此它就成了我的Excel处理首选工具。省内存是EasyExcel最突出的特点。它采用逐行解析的SAX模式不像POI那样把整个文件加载到内存。实测导出50万行数据POI需要2GB内存EasyExcel仅需300MB左右。这对企业级应用特别重要能有效避免服务器崩溃。基础使用非常简单Maven依赖只需要一个dependency groupIdcom.alibaba/groupId artifactIdeasyexcel/artifactId version3.3.2/version /dependency写Excel最简示例// 10行代码完成导出 ListUser data Arrays.asList( new User(1, 张三, 男), new User(2, 李四, 女) ); String fileName user.xlsx; EasyExcel.write(fileName, User.class) .sheet(用户列表) .doWrite(data);读Excel同样简洁EasyExcel.read(fileName, User.class, new AnalysisEventListenerUser() { Override public void invoke(User user, AnalysisContext context) { System.out.println(读取到数据 user); } }).sheet().doRead();我特别喜欢它的注解驱动设计。通过ExcelProperty可以灵活控制字段映射Data public class User { ExcelProperty(用户ID) // 自定义列名 private Integer id; ExcelProperty(index 1) // 按列索引匹配 private String name; DateTimeFormat(yyyy-MM-dd) // 日期格式化 private Date hireDate; }2. 企业级报表开发实战去年给某电商做促销报表时需要生成带复杂样式的多sheet文件。通过EasyExcel的模板填充功能原本3天的工作量缩短到2小时。模板填充是我的首选方案。先在Excel设计好样式模板| 订单日期{date} | | 订单号 | 商品名称 | 金额 | | .{orderId} | .{goodsName} | .{amount} |Java代码填充数据MapString, Object data new HashMap(); data.put(date, 2023-07-20); ListOrderDetail details orderService.list(); ExcelWriter writer EasyExcel.write(report.xlsx) .withTemplate(template.xlsx) .build(); writer.fill(data, writerSheet); writer.fill(details, FillConfig.builder().build(), writerSheet);样式控制可以通过注解实现HeadStyle(fillBackgroundColor 42) // 表头背景色 ContentFontStyle(fontName 楷体) public class ReportData { ColumnWidth(20) // 列宽 private String productName; }遇到需要动态合并单元格时可以用编程方式控制writer.merge(1, 5, 0, 0); // 合并1-5行第0列对于大数据量导出我推荐分批次写入ExcelWriter writer EasyExcel.write(fileName).build(); for (int i 0; i pageCount; i) { ListData batch queryBatch(i); writer.write(batch, writerSheet); } writer.finish();3. Web集成与性能优化在Spring Boot项目中集成文件下载非常方便GetMapping(/export) public void export(HttpServletResponse response) throws IOException { response.setContentType(application/vnd.ms-excel); response.setHeader(Content-Disposition, attachment;filenamedata.xlsx); EasyExcel.write(response.getOutputStream(), User.class) .sheet(用户数据) .doWrite(userService.list()); }上传解析要注意内存控制PostMapping(/import) public String import(RequestParam MultipartFile file) { EasyExcel.read(file.getInputStream(), User.class, new AnalysisEventListenerUser() { Override public void invoke(User user, AnalysisContext context) { // 分批处理逻辑 } }).sheet().doRead(); return 导入成功; }性能优化的几个关键点使用共享模板减少IO// 启动时加载 private static final Template template EasyExcel.readTemplate(template.xlsx); // 每次导出复用 ExcelWriter writer EasyExcel.write(outputStream) .withTemplate(template) .build();调整JVM参数-Xms512m -Xmx2g -XX:UseG1GC合理设置批处理大小// 每5000条刷新一次 FillConfig config FillConfig.builder() .bufferSize(5000) .build();4. 高级特性与踩坑记录自定义转换器处理枚举值非常实用public class GenderConverter implements ConverterInteger { public Integer convertToJavaData(CellData cellData) { return 男.equals(cellData.getStringValue()) ? 1 : 0; } public CellData convertToExcelData(Integer value) { return new CellData(value 1 ? 男 : 女); } }图片导出要注意资源释放try (InputStream imageStream getClass().getResourceAsStream(/logo.png)) { ImageData data new ImageData(imageStream); EasyExcel.write(withImage.xlsx) .sheet() .doWrite(Collections.singletonList(data)); }踩过的典型坑及解决方案日期显示异常确保模板单元格格式设置为日期格式数字精度丢失使用String类型接收或NumberFormat格式化样式不生效检查注解是否同时作用在类和字段上大文件超时Nginx增加proxy_read_timeout配置监控建议// 注册WriteHandler监控写入进度 .writeHandler(new WriteHandler() { Override public void sheet(int sheetNo, Sheet sheet) { System.out.println(开始写入Sheet sheetNo); } })最近在金融项目中还实现了动态列导出ListListString head Arrays.asList( Arrays.asList(基本信息, 姓名), Arrays.asList(基本信息, 年龄), Arrays.asList(财务信息, 账户余额) ); EasyExcel.write(dynamic.xlsx) .head(head) .sheet() .doWrite(dataList);

更多文章