[特殊字符]Spring Boot 后台使用 EasyExcel 实现数据报表导出(含模板、样式、美化)

06-01 1080阅读

在企业级系统中,数据导出 Excel 是非常常见的需求。本文基于实际项目经验,分享如何使用 EasyExcel 实现复杂报表导出,包含:

  • 支持按天/按小时导出数据

  • 使用模板填充 Excel

  • 支持多 Sheet、多段写入

  • 使用注解设置单元格样式

  • 实现月度数据聚合与格式优化


    🧾 一、数据报表导出常见场景

    1. 用户行为日志导出(按小时、日、月粒度)

    2. 电商交易报表(时间区间、订单、金额汇总)

    3. 运维监控数据导出

    4. 业务经营分析数据导出(如本文场景)


    🛠️ 二、常用 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 完美结合

          📂 模板示例结构

          [特殊字符]Spring Boot 后台使用 EasyExcel 实现数据报表导出(含模板、样式、美化)

          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 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 cutDataListByMonth(List 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 collect = statisticsDataList.stream()
                  .collect(Collectors.groupingBy(s -> s.getStatTime().substring(0, 6)));
              List result = new ArrayList();
              while (!minTime.isAfter(maxTime)) {
                  String monthKey = LocalDateTimeUtil.format(minTime, "yyyyMM");
                  List 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 灵活使用
          模板导出适合企业复杂格式报表模板和样式提前设计好,开发更轻松

          如果这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐、关注我 💬!如有问题可留言交流。

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码