老码农教你Solon EasyExcel 导出工具作为一名在 Java 领域摸爬滚打十余年的老码农我深知数据导出功能在企业应用中的重要性。无论是报表生成、数据备份还是用户管理导出 Excel 都是常见需求。今天我将带你深入理解如何将 Solon 框架与 EasyExcel 结合快速构建一个高效、内存友好的 Excel 导出工具。本文将从原理到实践逐步剖析并提供可运行的代码示例助你掌握这一技能。## 为什么选择 Solon EasyExcel在开始之前我们先聊聊选型背景。Solon 是一个轻量级的 Java 微服务框架强调性能与简洁相比 Spring Boot 更轻量启动速度更快适合对资源敏感的场景。而 EasyExcel 是阿里巴巴开源的 Excel 处理库专为大数据量设计采用流式读写避免内存溢出。两者结合能打造一个高效、低资源的导出方案。从原理上讲Solon 基于事件驱动和 IoC 容器支持插件化扩展而 EasyExcel 利用 Apache POI 底层但优化了内存模型——通过逐行写入而不是一次性加载整个工作簿。这让我想起早期用 POI 直接导出时几十万行数据导致堆内存崩溃的惨痛教训。EasyExcel 的“一行一写”机制正是解决这一痛点的利器。## 环境准备与依赖配置首先搭建一个 Solon 项目。你可以通过 Maven 或 Gradle 引入依赖。以下是一个典型的pom.xml配置xmldependencies !-- Solon 核心 -- dependency groupIdorg.noear/groupId artifactIdsolon-web/artifactId version2.5.10/version /dependency !-- EasyExcel -- dependency groupIdcom.alibaba/groupId artifactIdeasyexcel/artifactId version3.3.2/version /dependency !-- Lombok可选简化代码 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version scopeprovided/scope /dependency/dependenciesSolon 的启动类简单至极无需繁琐的注解扫描配置。这里我选择solon-web它内置了嵌入式服务器方便开发。## 核心原理EasyExcel 的流式写入EasyExcel 的核心是ExcelWriter和WriteSheet。当你调用write()方法时它会创建一个临时文件逐行追加数据最后生成目标文件。这种设计避免了将整个数据集加载到内存特别适合百万级数据导出。从底层看EasyExcel 使用了“模板模式”先写入表头再分批写入数据行。每写完一批就刷新到磁盘。Solon 作为控制器只需将 HTTP 响应流传递给 EasyExcel就能实现直接下载无需中间文件。## 实战代码示例导出用户列表下面我带你实现一个完整的导出功能。假设我们有一个用户实体类需要导出为 Excel。### 第一步定义数据模型javaimport com.alibaba.excel.annotation.ExcelProperty;import lombok.Data;Datapublic class User { ExcelProperty(用户ID) private Long id; ExcelProperty(用户名) private String name; ExcelProperty(邮箱) private String email; ExcelProperty(注册时间) private String registerTime; // 为简化使用字符串}注解ExcelProperty指定了列名EasyExcel 会据此生成表头。### 第二步编写 Solon 控制器javaimport com.alibaba.excel.EasyExcel;import org.noear.solon.annotation.Controller;import org.noear.solon.annotation.Mapping;import org.noear.solon.core.handle.Context;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.ArrayList;import java.util.List;Controllerpublic class ExportController { Mapping(/export/users) public void exportUsers(Context ctx) throws IOException { // 模拟数据源实际应用中可从数据库查询 ListUser userList generateUserData(10000); // 生成1万条数据 // 设置响应头告诉浏览器这是一个Excel文件 HttpServletResponse response ctx.response(); response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); response.setHeader(Content-Disposition, attachment; filenameusers.xlsx); // 核心使用EasyExcel写入到响应流 try (var outputStream response.getOutputStream()) { EasyExcel.write(outputStream, User.class) .sheet(用户列表) // 工作表名称 .doWrite(userList); // 写入数据 } } // 模拟生成数据 private ListUser generateUserData(int count) { ListUser list new ArrayList(count); for (long i 1; i count; i) { User user new User(); user.setId(i); user.setName(用户 i); user.setEmail(user i example.com); user.setRegisterTime(2024-01-01); list.add(user); } return list; }}代码注释解析-Controller和Mapping是 Solon 的注解类似 Spring 的RestController和RequestMapping。-Context是 Solon 的上下文对象通过它获取响应流。-EasyExcel.write()的第一个参数是输出流这里直接是 HTTP 响应流实现即时下载。-doWrite()方法会遍历列表逐行写入 Excel。启动 Solon 应用后访问/export/users即可下载 Excel 文件。这个例子虽然简单但已展示了核心流程。## 进阶示例大数据量分页导出真实场景中数据量可能达到百万级一次性加载到内存会 OOM。EasyExcel 支持分页写入我们只需分批从数据库查询并写入。下面是一个模拟分页导出的例子配合 Solon 的异步处理。javaimport com.alibaba.excel.EasyExcel;import com.alibaba.excel.write.handler.WriteHandler;import org.noear.solon.annotation.Controller;import org.noear.solon.annotation.Mapping;import org.noear.solon.core.handle.Context;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.ArrayList;import java.util.List;Controllerpublic class LargeExportController { Mapping(/export/large-users) public void exportLargeUsers(Context ctx) throws IOException { HttpServletResponse response ctx.response(); response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); response.setHeader(Content-Disposition, attachment; filenamelarge_users.xlsx); try (var outputStream response.getOutputStream()) { // 创建ExcelWriter对象不立即写入数据 var excelWriter EasyExcel.write(outputStream, User.class).build(); var writeSheet EasyExcel.writerSheet(用户数据).build(); // 分页写入每页1000条共100页模拟10万条数据 int pageSize 1000; int totalPages 100; for (int page 1; page totalPages; page) { // 模拟分页查询实际中替换为数据库查询 ListUser pageData simulatePageQuery(page, pageSize); if (pageData.isEmpty()) { break; // 无数据时提前结束 } // 写入当前页数据 excelWriter.write(pageData, writeSheet); } // 完成写入刷新流 excelWriter.finish(); } } // 模拟分页查询 private ListUser simulatePageQuery(int page, int pageSize) { ListUser list new ArrayList(pageSize); long startId (long) (page - 1) * pageSize 1; for (long i 0; i pageSize; i) { User user new User(); user.setId(startId i); user.setName(用户 (startId i)); user.setEmail(user (startId i) example.com); user.setRegisterTime(2024-06-15); list.add(user); } return list; }}原理深入这里我们手动控制ExcelWriter的生命周期。build()方法创建写入器writerSheet()定义工作表然后循环调用write()方法分批写入。每批数据写入后EasyExcel 会自动刷新到流不会累积在内存。finish()方法会关闭资源并写入文件尾部。这种模式非常适合与数据库游标或分页查询配合。例如使用 MyBatis-Plus 的Page分页每次查询 1000 条写入后再查询下一页直到数据取完。内存占用稳定在几 MB即使导出百万级数据也毫无压力。## 总结通过本文我们深入剖析了 Solon EasyExcel 导出工具的原理与实战。从依赖配置到两个可运行的代码示例你看到了如何利用 EasyExcel 的流式写入特性结合 Solon 的轻量级架构实现高效、内存友好的 Excel 导出。第一个示例展示了基础用法第二个示例则演示了大数据量分页导出的最佳实践。作为老码农我建议你在实际项目中务必注意两点一是始终使用 try-with-resources 确保流关闭二是对于超大数据量考虑异步导出如 Solon 的Async注解避免阻塞 HTTP 请求。EasyExcel 还支持自定义样式、合并单元格等高级功能感兴趣的可以进一步探索。希望这篇文章能帮你少走弯路写出更健壮的导出代码。
老码农教你:Solon + EasyExcel 导出工具
老码农教你Solon EasyExcel 导出工具作为一名在 Java 领域摸爬滚打十余年的老码农我深知数据导出功能在企业应用中的重要性。无论是报表生成、数据备份还是用户管理导出 Excel 都是常见需求。今天我将带你深入理解如何将 Solon 框架与 EasyExcel 结合快速构建一个高效、内存友好的 Excel 导出工具。本文将从原理到实践逐步剖析并提供可运行的代码示例助你掌握这一技能。## 为什么选择 Solon EasyExcel在开始之前我们先聊聊选型背景。Solon 是一个轻量级的 Java 微服务框架强调性能与简洁相比 Spring Boot 更轻量启动速度更快适合对资源敏感的场景。而 EasyExcel 是阿里巴巴开源的 Excel 处理库专为大数据量设计采用流式读写避免内存溢出。两者结合能打造一个高效、低资源的导出方案。从原理上讲Solon 基于事件驱动和 IoC 容器支持插件化扩展而 EasyExcel 利用 Apache POI 底层但优化了内存模型——通过逐行写入而不是一次性加载整个工作簿。这让我想起早期用 POI 直接导出时几十万行数据导致堆内存崩溃的惨痛教训。EasyExcel 的“一行一写”机制正是解决这一痛点的利器。## 环境准备与依赖配置首先搭建一个 Solon 项目。你可以通过 Maven 或 Gradle 引入依赖。以下是一个典型的pom.xml配置xmldependencies !-- Solon 核心 -- dependency groupIdorg.noear/groupId artifactIdsolon-web/artifactId version2.5.10/version /dependency !-- EasyExcel -- dependency groupIdcom.alibaba/groupId artifactIdeasyexcel/artifactId version3.3.2/version /dependency !-- Lombok可选简化代码 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version scopeprovided/scope /dependency/dependenciesSolon 的启动类简单至极无需繁琐的注解扫描配置。这里我选择solon-web它内置了嵌入式服务器方便开发。## 核心原理EasyExcel 的流式写入EasyExcel 的核心是ExcelWriter和WriteSheet。当你调用write()方法时它会创建一个临时文件逐行追加数据最后生成目标文件。这种设计避免了将整个数据集加载到内存特别适合百万级数据导出。从底层看EasyExcel 使用了“模板模式”先写入表头再分批写入数据行。每写完一批就刷新到磁盘。Solon 作为控制器只需将 HTTP 响应流传递给 EasyExcel就能实现直接下载无需中间文件。## 实战代码示例导出用户列表下面我带你实现一个完整的导出功能。假设我们有一个用户实体类需要导出为 Excel。### 第一步定义数据模型javaimport com.alibaba.excel.annotation.ExcelProperty;import lombok.Data;Datapublic class User { ExcelProperty(用户ID) private Long id; ExcelProperty(用户名) private String name; ExcelProperty(邮箱) private String email; ExcelProperty(注册时间) private String registerTime; // 为简化使用字符串}注解ExcelProperty指定了列名EasyExcel 会据此生成表头。### 第二步编写 Solon 控制器javaimport com.alibaba.excel.EasyExcel;import org.noear.solon.annotation.Controller;import org.noear.solon.annotation.Mapping;import org.noear.solon.core.handle.Context;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.ArrayList;import java.util.List;Controllerpublic class ExportController { Mapping(/export/users) public void exportUsers(Context ctx) throws IOException { // 模拟数据源实际应用中可从数据库查询 ListUser userList generateUserData(10000); // 生成1万条数据 // 设置响应头告诉浏览器这是一个Excel文件 HttpServletResponse response ctx.response(); response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); response.setHeader(Content-Disposition, attachment; filenameusers.xlsx); // 核心使用EasyExcel写入到响应流 try (var outputStream response.getOutputStream()) { EasyExcel.write(outputStream, User.class) .sheet(用户列表) // 工作表名称 .doWrite(userList); // 写入数据 } } // 模拟生成数据 private ListUser generateUserData(int count) { ListUser list new ArrayList(count); for (long i 1; i count; i) { User user new User(); user.setId(i); user.setName(用户 i); user.setEmail(user i example.com); user.setRegisterTime(2024-01-01); list.add(user); } return list; }}代码注释解析-Controller和Mapping是 Solon 的注解类似 Spring 的RestController和RequestMapping。-Context是 Solon 的上下文对象通过它获取响应流。-EasyExcel.write()的第一个参数是输出流这里直接是 HTTP 响应流实现即时下载。-doWrite()方法会遍历列表逐行写入 Excel。启动 Solon 应用后访问/export/users即可下载 Excel 文件。这个例子虽然简单但已展示了核心流程。## 进阶示例大数据量分页导出真实场景中数据量可能达到百万级一次性加载到内存会 OOM。EasyExcel 支持分页写入我们只需分批从数据库查询并写入。下面是一个模拟分页导出的例子配合 Solon 的异步处理。javaimport com.alibaba.excel.EasyExcel;import com.alibaba.excel.write.handler.WriteHandler;import org.noear.solon.annotation.Controller;import org.noear.solon.annotation.Mapping;import org.noear.solon.core.handle.Context;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.ArrayList;import java.util.List;Controllerpublic class LargeExportController { Mapping(/export/large-users) public void exportLargeUsers(Context ctx) throws IOException { HttpServletResponse response ctx.response(); response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); response.setHeader(Content-Disposition, attachment; filenamelarge_users.xlsx); try (var outputStream response.getOutputStream()) { // 创建ExcelWriter对象不立即写入数据 var excelWriter EasyExcel.write(outputStream, User.class).build(); var writeSheet EasyExcel.writerSheet(用户数据).build(); // 分页写入每页1000条共100页模拟10万条数据 int pageSize 1000; int totalPages 100; for (int page 1; page totalPages; page) { // 模拟分页查询实际中替换为数据库查询 ListUser pageData simulatePageQuery(page, pageSize); if (pageData.isEmpty()) { break; // 无数据时提前结束 } // 写入当前页数据 excelWriter.write(pageData, writeSheet); } // 完成写入刷新流 excelWriter.finish(); } } // 模拟分页查询 private ListUser simulatePageQuery(int page, int pageSize) { ListUser list new ArrayList(pageSize); long startId (long) (page - 1) * pageSize 1; for (long i 0; i pageSize; i) { User user new User(); user.setId(startId i); user.setName(用户 (startId i)); user.setEmail(user (startId i) example.com); user.setRegisterTime(2024-06-15); list.add(user); } return list; }}原理深入这里我们手动控制ExcelWriter的生命周期。build()方法创建写入器writerSheet()定义工作表然后循环调用write()方法分批写入。每批数据写入后EasyExcel 会自动刷新到流不会累积在内存。finish()方法会关闭资源并写入文件尾部。这种模式非常适合与数据库游标或分页查询配合。例如使用 MyBatis-Plus 的Page分页每次查询 1000 条写入后再查询下一页直到数据取完。内存占用稳定在几 MB即使导出百万级数据也毫无压力。## 总结通过本文我们深入剖析了 Solon EasyExcel 导出工具的原理与实战。从依赖配置到两个可运行的代码示例你看到了如何利用 EasyExcel 的流式写入特性结合 Solon 的轻量级架构实现高效、内存友好的 Excel 导出。第一个示例展示了基础用法第二个示例则演示了大数据量分页导出的最佳实践。作为老码农我建议你在实际项目中务必注意两点一是始终使用 try-with-resources 确保流关闭二是对于超大数据量考虑异步导出如 Solon 的Async注解避免阻塞 HTTP 请求。EasyExcel 还支持自定义样式、合并单元格等高级功能感兴趣的可以进一步探索。希望这篇文章能帮你少走弯路写出更健壮的导出代码。