SpringBoot后台使用EasyExcel实现数据报表导出(含模板、样式、美化)
引言
在企业级系统中,数据导出 Excel 是非常常见的需求。本文基于实际项目经验,分享如何使用 EasyExcel 实现复杂报表导出,包含:
支持按天/按小时导出数据
使用模板填充 Excel
支持多 Sheet、多段写入
使用注解设置单元格样式
实现月度数据聚合与格式优化
一、数据报表导出常见场景
用户行为日志导出(按小时、日、月粒度)
电商交易报表(时间区间、订单、金额汇总)
运维监控数据导出
业务经营分析数据导出(如本文场景)
二、常用 Excel 导出方案对比
| 技术方案 | 特点 | 优缺点说明 |
|---|---|---|
| Apache POI | 功能强大,支持复杂格式 | 复杂笨重、内存占用高 |
| JXL | 轻量级 | 不支持 Excel 2007+(.xlsx) |
| EasyExcel(推荐) | 阿里开源,流式处理,速度快 | 对模板语法有一定学习成本 |
| CSV 导出 | 简单快速 | 不支持样式、格式、合并单元格等 |
三、为什么选择 EasyExcel?
支持 大数据量导出,写入不容易 OOM
模板填充能力强,能与设计好的 Excel 模板结合
支持注解方式配置样式、美化表格
支持多个 Sheet、多段写入
API 友好,文档完善
四、EasyExcel 使用详解
1、基本写法
EasyExcel.write(outputStream, MyData.class)
.sheet("报表")
.doWrite(dataList);2、使用模板导出(推荐)
ExcelWriter writer = EasyExcel
.write(outputStream, MyData.class)
.withTemplate(templateInputStream)
.build();
WriteSheet sheet = EasyExcel.writerSheet().build();
writer.fill(variableMap, sheet); // 填充 {{变量}}
writer.write(dataList, sheet); // 填充数据区域 {}
writer.finish();五、样式注解介绍
EasyExcel 提供了丰富的注解用于设置单元格样式,无需写 handler:
@ColumnWidth(15)
@ContentStyle(
fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND,
fillForegroundColor = 42,
verticalAlignment = VerticalAlignmentEnum.CENTER,
horizontalAlignment = HorizontalAlignmentEnum.CENTER
)
@ContentFontStyle(
fontName = "宋体",
fontHeightInPoints = 12,
bold = BooleanEnum.TRUE
)
@Data
public class StatisticsData {
private String statTime;
private String regionName;
private Integer userCount;
private BigDecimal amount;
}解释:
@ContentStyle设置单元格背景色、对齐方式等@ContentFontStyle设置字体名称、字号、加粗等@ColumnWidth设置列宽
六、Excel 模板导出详解
为什么使用模板?
使用模板导出可以:
预设表格样式与布局
避免 Java 中繁琐的样式处理
支持多段数据写入(如月份汇总)
和美术设计好的 Excel 完美结合
模板示例结构

| A列 | B列 | C列 |
|---|---|---|
| 统计时间: | {{startTime}} ~ {{endTime}} | |
| 当前时间: | {{currentTime}} | |
| 月份: | {{month}} | |
| 日期 | 用户数 | 销售额 |
| {data} | ||
| 月汇总: | {monthAggregation} |
Java 填充代码
ExcelWriter excelWriter = EasyExcel
.write(response.getOutputStream(), StatisticsData.class)
.withTemplate(getClass().getClassLoader().getResourceAsStream("static/day_statistics_template.xlsx"))
.autoCloseStream(false)
.registerWriteHandler(easyExcelUtil)
.build();
Map<String, Object> map = new HashMap<>();
map.put("startTime", "2025-01-01");
map.put("endTime", "2025-01-31");
map.put("currentTime", "2025/05/04 10:00:00");
excelWriter.fill(map, writeSheet);
excelWriter.write(dataList, writeSheet); // 支持多段填充
excelWriter.finish();七、项目实战关键代码讲解
数据导出主入口
@Override
public void downloadStatistics(LocalDateTime minTime, LocalDateTime maxTime) throws IOException {
// 校验时间范围
if (LocalDateTimeUtil.between(minTime, maxTime, ChronoUnit.DAYS) > 365) {
throw new ForbiddenOperationException("查询时间区间不能超过一年");
}
HttpServletResponse response = ResponseUtils.getResponse();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
response.setHeader(BODY_PROCESSED, "1");
try {
if (LocalDateTimeUtil.beginOfDay(maxTime).equals(minTime)) {
downloadHourStatisticsData(response, minTime); // 按小时导出
} else {
downloadDayStatisticsData(response, minTime, maxTime); // 按天导出
}
} catch (Exception e) {
response.reset();
response.setContentType("application/json");
response.getWriter().println(JSON.toJSONString(Map.of(
"status", "failure",
"message", "下载失败: " + e.getMessage()
)));
}
}按月分组聚合逻辑
private List<ExcelMonthData> cutDataListByMonth(List<StatisticsData> statisticsDataList) {
LocalDateTime minTime = LocalDateTimeUtil.parse(statisticsDataList.get(0).getStatTime(), DatePattern.PURE_DATE_PATTERN);
LocalDateTime maxTime = LocalDateTimeUtil.parse(statisticsDataList.get(statisticsDataList.size() - 1).getStatTime(), DatePattern.PURE_DATE_PATTERN);
Map<String, List<StatisticsData>> collect = statisticsDataList.stream()
.collect(Collectors.groupingBy(s -> s.getStatTime().substring(0, 6)));
List<ExcelMonthData> result = new ArrayList<>();
while (!minTime.isAfter(maxTime)) {
String monthKey = LocalDateTimeUtil.format(minTime, "yyyyMM");
List<StatisticsData> monthList = collect.getOrDefault(monthKey, new ArrayList<>());
monthList.forEach(s -> s.setStatTime(excelDateFormatter(s.getStatTime())));
AggregationStatisticsData monthSummary = getAggregationStatisticsData(monthList, "月统计");
ExcelMonthData data = new ExcelMonthData();
data.setMonth(minTime.getMonthValue() + "月");
data.setStatisticsDataList(monthList);
data.setMonthAggregation(monthSummary);
result.add(data);
minTime = minTime.plusMonths(1);
}
return result;
}八、总结与建议
| 优势 | 建议 |
|---|---|
| EasyExcel 写入快、内存占用低 | 强烈建议使用模板填充,提升开发效率 |
| 支持注解设置样式、美化单元格 | 可结合注解 + WriteHandler 灵活使用 |
| 模板导出适合企业复杂格式报表 | 模板和样式提前设计好,开发更轻松 |
以上就是SpringBoot后台使用EasyExcel实现数据报表导出(含模板、样式、美化)的详细内容,更多关于SpringBoot EasyExcel数据报表导出的资料请关注脚本之家其它相关文章!
相关文章
Spring Boot 3 集成 RabbitMQ 实践指南(原理解析
本文介绍了SpringBoot 3集成RabbitMQ的实践指南,涵盖了RabbitMQ的核心原理、核心概念、高级特性、应用场景、环境搭建、核心配置类、消息生产者、消息消费者、接口控制器、监控与运维、最佳实践以及常见问题与解决方案等内容,感兴趣的朋友一起看看吧2025-02-02
Java基于Google zxing生成带logo的二维码图片
zxing是一个开放源码的,用java实现的多种格式的1D/2D条码图像处理库,本文主要介绍了Java基于Google zxing生成带logo的二维码图片,具有一定的参考价值,感兴趣的可以了解一下2023-10-10
Java多线程Queue、BlockingQueue和使用BlockingQueue实现生产消费者模型方法解析
这篇文章主要介绍了Java多线程Queue、BlockingQueue和使用BlockingQueue实现生产消费者模型方法解析,涉及queue,BlockingQueue等有关内容,具有一定参考价值,需要的朋友可以参考。2017-11-11
java为什么使用BlockingQueue解决竞态条件问题面试精讲
这篇文章主要为大家介绍了java为什么使用BlockingQueue解决竞态条件问题面试精讲,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-10-10
SpringBoot中EasyExcel实现Excel文件的导入导出
这篇文章主要介绍了SpringBoot中EasyExcel实现Excel文件的导入导出,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2020-10-10
Java中的UrlDecoder 和 UrlEncoder_动力节点Java学院整理
HTML 格式编码的实用工具类。该类包含了将 String 转换为 application/x-www-form-urlencoded MIME 格式的静态方法。下文通过实例代码给大家介绍Java中的UrlDecoder 和 UrlEncoder知识,感兴趣的的朋友一起看看吧2017-07-07


最新评论