老码农教你:Solon + FastExcel 导出工具
关于 "Excel 导出" ——POI API 是比较复杂的,CellStyle 能把人调得眼冒金星,大数据量导出时内存飙到 90% 的恐惧至今难忘。直到发现了 FastExcel(前身是 Alibaba 的 EasyExcel),从此打开新世界的大门。今天就把这套 "导出大法" 分享给大家,顺便穿插点踩坑经验。
一、先整合项目环境
1. 引入依赖
首先在 pom.xml 里加依赖,这里得注意版本兼容性。fastexcel 最新版本移除了 poi 的依赖,大好特好!
<dependency> <groupId>org.noear</groupId> <artifactId>solon-web</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>cn.idev.excel</groupId> <artifactId>fastexcel</artifactId> <version>1.3.0</version> </dependency>
2. 创建实体类
定义 Excel 里每一列的数据结构,就像给每个字段安排 "座位"。比如导出用户信息:
import cn.idev.excel.annotation.ExcelProperty; import cn.idev.excel.annotation.format.DateTimeFormat; import cn.idev.excel.annotation.write.style.ColumnWidth; import lombok.Data; import java.util.Date; @Data public class UserExcelVO { // 这里是表头名称,宽度设置成20 @ExcelProperty(value = "用户ID", index = 0) @ColumnWidth(20) private Long userId; // 设定日期为"yyyy-MM-dd"格式 @ExcelProperty(value = "注册时间", index = 1) @DateTimeFormat("yyyy-MM-dd") private Date registerTime; // 性别要转换为友好描述 @ExcelProperty(value = "性别", index = 2, converter = SexConverter.class) private Integer sex; }
这里的 @ExcelProperty
就像给数据贴标签,index是列顺序。别标错号,不然数据错位时会怀疑人生 —— 笔者曾把金额和年龄的位置搞反,会被财务小姐姐骂得狗血淋头。
3. 编写导出工具类:避免重复工作
把通用导出逻辑封装起来,以后每次导出就简单了。创建EasyExcelUtils:
import cn.idev.excel.EasyExcel; import org.noear.solon.core.handle.Context; import java.io.IOException; import java.net.URLEncoder; import java.util.List; public class EasyExcelUtils { public static <T> void exportExcel(Context ctx, List<T> dataList, Class<T> clazz, String fileName) throws IOException { ctx.contentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); ctx.charset("utf-8"); // 文件名得处理中文,不然下载下来是乱码 fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20"); ctx.headerSet("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); // 这里用EasyExcel.write()就像启动一个Excel生成器 EasyExcel.write(ctx.outputStream(), clazz) .sheet("数据报表") .doWrite(dataList); } }
二、实战演练:从 "基础导出" 到 "高深玩法"
1. 基础导出
import org.noear.solon.annotation.*; import org.noear.solon.core.handle.Context; import java.io.IOException; import java.util.List; @Controller public class DemoController { @Inject UserService userService; @Get @Mapping("/exportUser") public void exportUser(Context ctx) throws IOException { List<UserExcelVO> dataList = userService.getUserListForExport(); // 假设这是从数据库查的数据 EasyExcelUtils.exportExcel(ctx, dataList, UserExcelVO.class, "用户信息表"); } }
2. 复杂表头,加一层分类
有时候表头需要多级结构,比如 "用户信息" 下分 "基本信息"" 联系方式 "。这时候需要用@ExcelProperty的数组形式:
import cn.idev.excel.annotation.ExcelProperty; import lombok.Data; @Data public class ComplexHeaderVO { @ExcelProperty({"用户信息", "用户ID"}) private Long userId; @ExcelProperty({"用户信息", "姓名"}) private String userName; @ExcelProperty({"联系方式", "手机号"}) private String phone; @ExcelProperty({"联系方式", "邮箱"}) private String email; }
3. 合并单元格
比如导出报表时需要合并相同内容的单元格,这时候得自定义CellWriteHandler。举个例子,合并连续相同的部门名称:
import cn.idev.excel.write.handler.CellWriteHandler; import cn.idev.excel.write.handler.context.CellWriteHandlerContext; public class MergeCellHandler implements CellWriteHandler { @Override public void afterCellDispose(CellWriteHandlerContext context) { // 这里省略具体实现,核心是通过行号和列号判断是否合并 // 就像拼拼图,找到相同的部分粘在一起 } }
在导出时注册这个处理器:
EasyExcel.write(...) .registerWriteHandler(new MergeCellHandler()) .doWrite(...);
4. 自定义格式:美化效果
比如金额需要显示成 "¥1,000.00",日期要显示成 "2025 年 5 月 29 日"。除了前面提到的 @DateTimeFormat,数值格式可以用 @NumberFormat:
@ExcelProperty("金额") @NumberFormat("#,##0.00") private Double amount;
5. 大数据量导出,要避免 OOM
当数据量超过 10 万条时,直接导出会OOM的,这时候要用流式处理。FastExcel 贴心地支持分页导出,分批次写入:
EasyExcel.write(ctx.outputStream(), UserExcelVO.class) .sheet("大数据报表") .registerWriteHandler(...) // 可选的样式处理器 .doWrite(new AnalysisContext() -> { // 这里每次调用获取一页数据,直到没有数据为止 List<UserExcelVO> pageData = userService.getPageData(analysisContext.readRowHolder().getRowIndex()); return pageData; });
三、避坑指南
1. 注解优先级:别让 "标签" 打架
@ExcelProperty 可以写在字段上或方法上,建议统一写在字段上,不然容易混乱。
2. 样式设置:别把 Excel 变成 "花脸猫"
虽然 FastExcel 支持自定义样式,但别过度使用,比如给每个单元格设置不同颜色,导出的 Excel 可能打不开。样式设置要适度,就像化妆,自然美就好。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
豆包正式上线未成年人保护模式
豆包宣布正式上线未成年人保护模式。家长朋友们输入密码,开启该模式后,推荐视频、浏览第三方网页、和豆包以外的智能体对话、AI创作功能将被默认关闭。 此前,有网友反馈称因豆包会在问答结果中提供相应短视频作为参考,部分儿童可能借此浏览视频内容,分散注意力。 开启该功能后,翻译、深入研究等功能仍能正常使用。官方表示,未成年人模式是为家长提供的工具,以方便关闭部分功能,防止小朋友拿到设备后可能的不适当使用。
- 下一篇
谷歌收紧 Android 侧载功能,将仅允许通过“开发者验证”的应用进行安装
谷歌宣布,从 2026 年起,只有通过验证的开发者发布的应用才能安装在认证 Android 设备上。 从明年开始,Android 将要求所有应用程序必须由经过验证的开发者进行注册,用户才能在认证的 Android 设备上安装这些应用程序。 所谓“认证 Android 设备”指的是预装 Google Play Protect 和其他 Google 应用的设备,这些设备需遵循新的开发者验证流程才能安装应用。 开发者在验证过程中将需要向谷歌提供以下信息: 个人开发者:法定全名、地址、电子邮箱和电话号码。 企业开发者:还需提供网站和 D-U-N-S 编号 需要注意的是,这些信息将由谷歌保存用于验证,但“不会向用户公开”。同时,谷歌提供了专门的 Android Developer Console 来处理这些验证流程,这与 Play 商店的开发者控制台有所区别。 谷歌表示,来自网络侧载(非 Play 商店)的应用含有的恶意软件数量是 Play 商店的 50 倍以上,尽管 Play 商店从 2023 年就已要求开发者验证。这项措施旨在提高开发者的责任感,降低匿名恶意开发者传播恶意软件和诈骗行为的机会...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS关闭SELinux安全模块
- Docker安装Oracle12C,快速搭建Oracle学习环境
- MySQL8.0.19开启GTID主从同步CentOS8
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS7设置SWAP分区,小内存服务器的救世主
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Linux系统CentOS6、CentOS7手动修改IP地址