使用 EasyExcel 封装通用 Excel 导出工具类

在企业应用中,经常需要把后台数据导出成 Excel 文件供用户下载。在我们的项目中,涉及"成品"、"材料"等模块的数据导出。本文将分享如何使用 EasyExcel 封装一个通用的 Excel 导出工具类 ExcelExportUtil,支持单个 Sheet 和多 Sheet 导出。

1. 背景问题

在没有封装工具类之前,导出 Excel 的代码通常是这样的:

复制代码
@PostMapping("/export/{orderNumber}")
private void exportModal2BillHead(@PathVariable String orderNumber, HttpServletResponse response) throws IOException {
    List<Modal2BillHeadVO> list = modal2BillHeadService.getQueryOrderInfo(orderNumber);

    // 转换为导出 VO
    List<Modal2BillExportVO> exportList = list.stream().map(v -> {
        Modal2BillExportVO vo = new Modal2BillExportVO();
        vo.setMaterialStockOutId(String.valueOf(v.getMaterialStockOutId()));
        vo.setDoCno(v.getDoCno());
        vo.setCreatedOn(String.valueOf(v.getCreatedOn()));
        vo.setCreatedBy(v.getCreatedBy());
        vo.setOrderNumber(v.getOrderNumber());
        vo.setItemCode(v.getItemCode());
        vo.setItemName(v.getItemName());
        vo.setItemSpecs(v.getItemSpecs());
        vo.setStoreUomoty(v.getStoreUomoty());
        vo.setCostUomoty(v.getCostUomoty());
        vo.setUom(v.getUom());
        vo.setWhName(v.getWhName());
        vo.setDoctype(v.getDoctype());
        vo.setTransferFormType(v.getTransferFormType());
        vo.setPurchasePrice(v.getPurchasePrice());
        return vo;
    }).collect(Collectors.toList());

    // Excel 导出逻辑
    String fileName = "材料提库导出";
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    response.setCharacterEncoding("utf-8");
    String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
    response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodedFileName + ".xlsx");

    ServletOutputStream out = response.getOutputStream();
    EasyExcel.write(out, Modal2BillExportVO.class)
            .sheet("成品提库")
            .doWrite(exportList == null ? new ArrayList<>() : exportList);

    out.flush();
    out.close();
}

❌ 缺点:

  1. 每个导出都要重复写响应头、流操作。

  2. 代码臃肿,可维护性差。

  3. 不方便支持多 Sheet 或通用导出。

2. 封装工具类:ExcelExportUtil

为了提高可复用性,我们封装了一个通用工具类,核心设计思想:

  • 单个 Sheet 导出:快速导出单个 Excel。

  • 多 Sheet 导出:在一个 Excel 文件中包含多个 Sheet 标签页。

  • 泛型支持 :通过 <T> 泛型,可以导出任意带 @ExcelProperty 注解的实体类。

    public class ExcelExportUtil {

    复制代码
      // 单个 Sheet 导出
      public static <T> void export(HttpServletResponse response, String fileName, Class<T> clazz, List<T> dataList) {
          try {
              setResponseHeader(response, fileName);
              ServletOutputStream out = response.getOutputStream();
              EasyExcel.write(out, clazz)
                      .sheet(fileName)
                      .doWrite(dataList == null ? new ArrayList<>() : dataList);
              out.flush();
              out.close();
          } catch (Exception e) {
              throw new RuntimeException("Excel 导出失败:" + e.getMessage(), e);
          }
      }
    
      // 多 Sheet 导出
      public static void exportMultiSheet(HttpServletResponse response, String fileName, Map<String, SheetData<?>> sheets) {
          try {
              setResponseHeader(response, fileName);
              try (ServletOutputStream out = response.getOutputStream();
                   ExcelWriter writer = EasyExcel.write(out).build()) {
    
                  int sheetNo = 0;
                  for (Map.Entry<String, SheetData<?>> entry : sheets.entrySet()) {
                      String sheetName = entry.getKey();
                      SheetData<?> sheetData = entry.getValue();
    
                      WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo, sheetName)
                              .head(sheetData.getClazz())
                              .build();
    
                      writer.write(sheetData.getData() == null ? new ArrayList<>() : sheetData.getData(), writeSheet);
                      sheetNo++;
                  }
              }
          } catch (Exception e) {
              throw new RuntimeException("Excel 多 Sheet 导出失败:" + e.getMessage(), e);
          }
      }
    
      // 设置响应头
      private static void setResponseHeader(HttpServletResponse response, String fileName) throws Exception {
          response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
          response.setCharacterEncoding("utf-8");
          String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
          response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodedFileName + ".xlsx");
      }
    
      // 多 Sheet 封装类
      public static class SheetData<T> {
          private Class<T> clazz;
          private List<T> data;
    
          public SheetData(Class<T> clazz, List<T> data) {
              this.clazz = clazz;
              this.data = data;
          }
    
          public Class<T> getClazz() { return clazz; }
          public List<T> getData() { return data; }
      }

    }

3. 控制器使用示例(我只是为了方便代码量少直接写到contact层了)

✅ 优点:

  1. 代码简洁:控制器只负责数据处理,不关心 Excel 流操作。

  2. 复用性高:任何 VO/DTO 都可以直接导出。

  3. 支持多 Sheet :将来需要在同一个 Excel 文件中导出多张表时,只需调用 exportMultiSheet 即可。

4. 总结

通过 ExcelExportUtil 工具类,我们可以:

  • 轻松实现单个 Sheet 导出。

  • 支持多 Sheet 导出,实现复杂报表的汇总。

  • 封装响应头和流操作,减少重复代码,提高可维护性。

💡 Tip:如果将来需要"每个表单生成独立 Excel",只需多次调用 export 方法即可。

相关推荐
用户0332126663678 小时前
使用 Python 设置 Excel 行列自适应 【代码示例】
python·excel
企业数字化笔记9 小时前
固定资产Excel批量导入怎么防重复?资产编码、重复检查和错误回执
java·后端·excel
CORNERSTONE36514 小时前
低代码开发有哪些应用场景?
低代码·excel·erp·mes·企业数字化
小葱炖豆腐1 天前
python绘制excel折线图
python·excel·numpy·pandas·matplotlib
cspttty2 天前
2026年财务分析岗JD中的Excel、SQL、BI与业务分析要求
大数据·sql·excel
cspttty2 天前
HR数字化校招准备路线:Excel、SQL、BI和AI工具怎么学
人工智能·sql·excel
鲲穹AI种草3 天前
Excel 表格批量处理与数据整理,多款表格工具能力客观记录
excel·表格处理
cspttty3 天前
2026秋招供应链分析师技能栈:SQL、Excel、BI与业务分析
数据库·sql·excel
Zzq_Fighting4 天前
Excel批量匹配数据
excel
E_ICEBLUE4 天前
Python 实现 Excel 转 Markdown,支持工作表、单元格区域和批量处理
python·excel·markdown·格式转换