SpringBoot后臺(tái)使用EasyExcel實(shí)現(xiàn)數(shù)據(jù)報(bào)表導(dǎo)出(含模板、樣式、美化)
引言
在企業(yè)級(jí)系統(tǒng)中,數(shù)據(jù)導(dǎo)出 Excel 是非常常見(jiàn)的需求。本文基于實(shí)際項(xiàng)目經(jīng)驗(yàn),分享如何使用 EasyExcel 實(shí)現(xiàn)復(fù)雜報(bào)表導(dǎo)出,包含:
支持按天/按小時(shí)導(dǎo)出數(shù)據(jù)
使用模板填充 Excel
支持多 Sheet、多段寫入
使用注解設(shè)置單元格樣式
實(shí)現(xiàn)月度數(shù)據(jù)聚合與格式優(yōu)化
一、數(shù)據(jù)報(bào)表導(dǎo)出常見(jiàn)場(chǎng)景
用戶行為日志導(dǎo)出(按小時(shí)、日、月粒度)
電商交易報(bào)表(時(shí)間區(qū)間、訂單、金額匯總)
運(yùn)維監(jiān)控?cái)?shù)據(jù)導(dǎo)出
業(yè)務(wù)經(jīng)營(yíng)分析數(shù)據(jù)導(dǎo)出(如本文場(chǎng)景)
二、常用 Excel 導(dǎo)出方案對(duì)比
| 技術(shù)方案 | 特點(diǎn) | 優(yōu)缺點(diǎn)說(shuō)明 |
|---|---|---|
| Apache POI | 功能強(qiáng)大,支持復(fù)雜格式 | 復(fù)雜笨重、內(nèi)存占用高 |
| JXL | 輕量級(jí) | 不支持 Excel 2007+(.xlsx) |
| EasyExcel(推薦) | 阿里開(kāi)源,流式處理,速度快 | 對(duì)模板語(yǔ)法有一定學(xué)習(xí)成本 |
| CSV 導(dǎo)出 | 簡(jiǎn)單快速 | 不支持樣式、格式、合并單元格等 |
三、為什么選擇 EasyExcel?
支持 大數(shù)據(jù)量導(dǎo)出,寫入不容易 OOM
模板填充能力強(qiáng),能與設(shè)計(jì)好的 Excel 模板結(jié)合
支持注解方式配置樣式、美化表格
支持多個(gè) Sheet、多段寫入
API 友好,文檔完善
四、EasyExcel 使用詳解
1、基本寫法
EasyExcel.write(outputStream, MyData.class)
.sheet("報(bào)表")
.doWrite(dataList);2、使用模板導(dǎo)出(推薦)
ExcelWriter writer = EasyExcel
.write(outputStream, MyData.class)
.withTemplate(templateInputStream)
.build();
WriteSheet sheet = EasyExcel.writerSheet().build();
writer.fill(variableMap, sheet); // 填充 {{變量}}
writer.write(dataList, sheet); // 填充數(shù)據(jù)區(qū)域 {}
writer.finish();五、樣式注解介紹
EasyExcel 提供了豐富的注解用于設(shè)置單元格樣式,無(wú)需寫 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設(shè)置單元格背景色、對(duì)齊方式等@ContentFontStyle設(shè)置字體名稱、字號(hào)、加粗等@ColumnWidth設(shè)置列寬
六、Excel 模板導(dǎo)出詳解
為什么使用模板?
使用模板導(dǎo)出可以:
預(yù)設(shè)表格樣式與布局
避免 Java 中繁瑣的樣式處理
支持多段數(shù)據(jù)寫入(如月份匯總)
和美術(shù)設(shè)計(jì)好的 Excel 完美結(jié)合
模板示例結(jié)構(gòu)

| A列 | B列 | C列 |
|---|---|---|
| 統(tǒng)計(jì)時(shí)間: | {{startTime}} ~ {{endTime}} | |
| 當(dāng)前時(shí)間: | {{currentTime}} | |
| 月份: | {{month}} | |
| 日期 | 用戶數(shù) | 銷售額 |
| {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();七、項(xiàng)目實(shí)戰(zhàn)關(guān)鍵代碼講解
數(shù)據(jù)導(dǎo)出主入口
@Override
public void downloadStatistics(LocalDateTime minTime, LocalDateTime maxTime) throws IOException {
// 校驗(yàn)時(shí)間范圍
if (LocalDateTimeUtil.between(minTime, maxTime, ChronoUnit.DAYS) > 365) {
throw new ForbiddenOperationException("查詢時(shí)間區(qū)間不能超過(guò)一年");
}
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); // 按小時(shí)導(dǎo)出
} else {
downloadDayStatisticsData(response, minTime, maxTime); // 按天導(dǎo)出
}
} 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, "月統(tǒng)計(jì)");
ExcelMonthData data = new ExcelMonthData();
data.setMonth(minTime.getMonthValue() + "月");
data.setStatisticsDataList(monthList);
data.setMonthAggregation(monthSummary);
result.add(data);
minTime = minTime.plusMonths(1);
}
return result;
}八、總結(jié)與建議
| 優(yōu)勢(shì) | 建議 |
|---|---|
| EasyExcel 寫入快、內(nèi)存占用低 | 強(qiáng)烈建議使用模板填充,提升開(kāi)發(fā)效率 |
| 支持注解設(shè)置樣式、美化單元格 | 可結(jié)合注解 + WriteHandler 靈活使用 |
| 模板導(dǎo)出適合企業(yè)復(fù)雜格式報(bào)表 | 模板和樣式提前設(shè)計(jì)好,開(kāi)發(fā)更輕松 |
以上就是SpringBoot后臺(tái)使用EasyExcel實(shí)現(xiàn)數(shù)據(jù)報(bào)表導(dǎo)出(含模板、樣式、美化)的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot EasyExcel數(shù)據(jù)報(bào)表導(dǎo)出的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot種如何使用?EasyExcel?實(shí)現(xiàn)自定義表頭導(dǎo)出并實(shí)現(xiàn)數(shù)據(jù)格式化轉(zhuǎn)換
- SpringBoot整合EasyExcel實(shí)現(xiàn)大規(guī)模數(shù)據(jù)的并行導(dǎo)出與壓縮下載
- SpringBoot利用EasyExcel實(shí)現(xiàn)導(dǎo)出數(shù)據(jù)
- 使用VUE+SpringBoot+EasyExcel?整合導(dǎo)入導(dǎo)出數(shù)據(jù)的教程詳解
- SpringBoot整合EasyExcel實(shí)現(xiàn)導(dǎo)入導(dǎo)出數(shù)據(jù)
相關(guān)文章
Spring Boot 3 集成 RabbitMQ 實(shí)踐指南(原理解析
本文介紹了SpringBoot 3集成RabbitMQ的實(shí)踐指南,涵蓋了RabbitMQ的核心原理、核心概念、高級(jí)特性、應(yīng)用場(chǎng)景、環(huán)境搭建、核心配置類、消息生產(chǎn)者、消息消費(fèi)者、接口控制器、監(jiān)控與運(yùn)維、最佳實(shí)踐以及常見(jiàn)問(wèn)題與解決方案等內(nèi)容,感興趣的朋友一起看看吧2025-02-02
基于Redisson實(shí)現(xiàn)注解式分布式鎖的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何基于Redisson實(shí)現(xiàn)注解式分布式鎖,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,需要的可以了解一下2023-07-07
Java基于Google zxing生成帶logo的二維碼圖片
zxing是一個(gè)開(kāi)放源碼的,用java實(shí)現(xiàn)的多種格式的1D/2D條碼圖像處理庫(kù),本文主要介紹了Java基于Google zxing生成帶logo的二維碼圖片,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10
使用curator實(shí)現(xiàn)zookeeper鎖服務(wù)的示例分享
這篇文章主要介紹了使用curator實(shí)現(xiàn)zookeeper鎖服務(wù)的示例,需要的朋友可以參考下2014-02-02
Java多線程Queue、BlockingQueue和使用BlockingQueue實(shí)現(xiàn)生產(chǎn)消費(fèi)者模型方法解析
這篇文章主要介紹了Java多線程Queue、BlockingQueue和使用BlockingQueue實(shí)現(xiàn)生產(chǎn)消費(fèi)者模型方法解析,涉及queue,BlockingQueue等有關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以參考。2017-11-11
java為什么使用BlockingQueue解決競(jìng)態(tài)條件問(wèn)題面試精講
這篇文章主要為大家介紹了java為什么使用BlockingQueue解決競(jìng)態(tài)條件問(wèn)題面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
SpringBoot中EasyExcel實(shí)現(xiàn)Excel文件的導(dǎo)入導(dǎo)出
這篇文章主要介紹了SpringBoot中EasyExcel實(shí)現(xiàn)Excel文件的導(dǎo)入導(dǎo)出,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
Java中的UrlDecoder 和 UrlEncoder_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
HTML 格式編碼的實(shí)用工具類。該類包含了將 String 轉(zhuǎn)換為 application/x-www-form-urlencoded MIME 格式的靜態(tài)方法。下文通過(guò)實(shí)例代碼給大家介紹Java中的UrlDecoder 和 UrlEncoder知識(shí),感興趣的的朋友一起看看吧2017-07-07

