关于 "Excel 导出" ——POI API 是比较复杂的,CellStyle 能把人调得眼冒金星,大数据量导出时内存飙到 90% 的恐惧至今难忘。直到发现了 Alibaba 的 EasyExcel,从此打开新世界的大门。今天就把这套 "导出救命锦囊" 分享给大家,顺便穿插点踩坑经验。

一、先整合项目环境

1. 引入依赖

首先在 pom.xml 里加依赖,这里得注意版本兼容性。加完后记得刷新 Maven。

<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-web</artifactId>
<version>3.5.0</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.3</version>
</dependency>

2. 创建实体类

定义 Excel 里每一列的数据结构,就像给每个字段安排 "座位"。比如导出用户信息:

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
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 com.alibaba.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 com.alibaba.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 com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.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的,这时候要用流式处理。EasyExcel 贴心地支持分页导出,分批次写入:

EasyExcel.write(ctx.outputStream(), UserExcelVO.class)
.sheet("大数据报表")
.registerWriteHandler(...) // 可选的样式处理器
.doWrite(new AnalysisContext() -> {
// 这里每次调用获取一页数据,直到没有数据为止
List<UserExcelVO> pageData = userService.getPageData(analysisContext.readRowHolder().getRowIndex());
return pageData;
});

三、避坑指南

1. 依赖冲突:当 Maven 开始 "闹别扭"

如果有引入旧版 POI 依赖,可能会和 EasyExcel 的 POI 版本冲突。这时候可用 mvn dependency:tree 命令排查,然后在pom.xml里用排除冲突项。

2. 注解优先级:别让 "标签" 打架

@ExcelProperty 可以写在字段上或方法上,建议统一写在字段上,不然容易混乱。

3. 样式设置:别把 Excel 变成 "花脸猫"

虽然 EasyExcel 支持自定义样式,但别过度使用,比如给每个单元格设置不同颜色,导出的 Excel 可能打不开。样式设置要适度,就像化妆,自然美就好。

老码农教你:Solon + EasyExcel 导出工具的更多相关文章

  1. 老码农教你在 StackOverflow 上谈笑风生

    作为一个高大上的码农,你肯定用到过 StackOverflow,必须的.会有人否定这个断言么?那他恐怕不是真正的码农,或者说还没入门.StackOverflow 对于码农的重要性,基本就和诸葛亮对刘备 ...

  2. 老码农冒死揭开行业黑幕:如何编写无法维护的代码[ZZ]

    下面是一篇有意思的"代码大全",可谓 逆软件工程. 老码农冒死揭开行业黑幕:如何编写无法维护的代码 原文如下 让自己稳拿铁饭碗 ;-) – Roedy Green(翻译版略有删节) ...

  3. Java老码农心得:卷了这么多年,您真的卷会了吗?

    前言 大家好,我是福隆苑居士,今天跟大家聊一下程序员在当下内卷成风的情况下,使用什么方法可以了解行业发展趋势,知道哪些该学,哪些可以略过,今年应该掌握什么,可以放弃什么,让自己时刻紧跟行业的步伐永不掉 ...

  4. 2020互联网寒冬之下,作为一个Android老码农,是如何进入腾讯的?

    由于众所周知的原因,原生Android开发如今已经日渐凋敝,作为一个Android程序员,不仅要会Java,Kotlin,JavaScript,Css,Html,还要会Flutter,C++,FFmp ...

  5. 码农的好助手:版本管理工具git的使用

    一.什么是github? GitHub 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub. GitHub 于 2008 年 4 月 10 日 ...

  6. 【转载】 大龄码农那些事——也谈996.ICU

    原文地址: https://www.cnblogs.com/helloyaren/p/10657414.html 请扫码关注!!! 您的关注将是您做的最正确的事情!!! 大龄码农那些事专注分享大龄码农 ...

  7. 大龄码农那些事——也谈996.ICU

    1.背景 近期Github突然有一个开源项目火了,叫“996.icu”,开源地址:https://github.com/996icu/996.ICU ,目前star的人数截止我写这篇博文时已经高达17 ...

  8. 6年DotNet码农的盲目经历

    前言   第一篇没有选择记录与技术相关的文档,是考虑到有必要给查阅这篇文档的伙伴们“自我介绍”一下,大佬们看了求带或指导,我很愿意学习,初学者们看了千万不要重复走我之前的“学习之路”:我老家贵州,再过 ...

  9. 码农英语四级考了6次,也能进知名IT外企

    程序员学英语 这显然不是新鲜的话题,但再怎么重复强调都不过分! 为啥要学 IT是当今世界发展最快的行业,没有之一!作为其中的从业人员,要始终保持对最新技术的关注度,难免需要阅读英文新闻或文章 平时工作 ...

  10. 【整理】待毕业.Net码农就业求职储备

    声明:本文题目来源于互联网,仅供即将从学校毕业的.Net码农(当然,我本人也是菜逼一个)学习之用.当然,学习了这些题目不一定会拿到offer,但是针对就业求职做些针对性的准备也是不错的.此外,除了技术 ...

随机推荐

  1. 从零开始学Flink:揭开实时计算的神秘面纱

    一.为什么需要Flink? 当你在电商平台秒杀商品时,1毫秒的延迟可能导致交易失败:当自动驾驶汽车遇到障碍物时,10毫秒的计算延迟可能酿成事故.这些场景揭示了一个残酷事实:数据的价值随时间呈指数级衰减 ...

  2. AES256加密解密

    REPORT zged_aes. DATA lv_message_string TYPE string. DATA lv_message_decrypted TYPE XSTRING. " ...

  3. PVE折腾笔记 (3) 在原QNAP使用的硬盘上创建ZFS

    前言 在经过一番研究后,我决定使用ZFS作为俩机械硬盘的文件系统,本来也可以和QNAP一样直接ext4的,但ZFS比较安全,有自愈功能,可以处理比特位翻转的问题,总之就是好用. 如果追求灵活性可以使用 ...

  4. 技术干货|如何利用 ChunJun 实现数据离线同步?

    ChunJun 是⼀款稳定.易⽤.⾼效.批流⼀体的数据集成框架,基于计算引擎 Flink 实现多种异构数据源之间的数据同步与计算.ChunJun 可以把不同来源.格式.特点性质的数据在逻辑上或物理上有 ...

  5. AI 对冲基金模拟系统

    content: AI 对冲基金模拟系统 项目概述 AI对冲基金模拟系统是一个教育研究项目,通过模拟16位著名投资策略师(包括沃伦·巴菲特.查理·芒格等)的决策过程,探索AI在金融投资领域的应用潜力. ...

  6. H20 大模型推理系统环境配置踩坑

    基础环境 CPU:INTEL(R) XEON(R) PLATINUM 8558P 48 Cores 96 Threads × 2 GPU:NVIDIA H20-3e NVL 141G × 8,NVLI ...

  7. 4.分布式事务方案-Saga

    1. Saga是什么 保证最终一致性的一种分布式事务方案 2. Saga流程 有多个事务参与者,每个参与者都有两块逻辑:正向操作和逆向操作 把事务分成两个阶段 第一阶段每个参与者执行正向操作 第二阶段 ...

  8. Xamarin.Android 禁止横屏 /竖屏

    this.RequestedOrientation = Android.Content.PM.ScreenOrientation.Portrait;//竖屏,禁止横屏 this.RequestedOr ...

  9. 前端开发系列034-基础篇之RegExp正则表达式

    本文介绍RegExp相关的知识点,包括正则表达式的创建.匹配规则等内容. RegExp简单介绍 正则表达式Regular Expression是描述字符模式的对象,在JavaScript语言中提供了内 ...

  10. Games 103 cloth PDB 浅析

    简介 PDB 比 隐式积分法 速度快很多. 全称 Position Based Dynamics 粒子动力学系统, 什么是PBD呢? 个人的理解就是, 多次迭代, 达到一步的稳定状态. 然后更新整个系 ...