使用 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 方法即可。

相关推荐
一晌小贪欢6 小时前
【Html模板】电商运营可视化大屏模板 Excel存储 + 一键导出(已上线-可预览)
前端·数据分析·html·excel·数据看板·电商大屏·大屏看板
oh,huoyuyan10 小时前
【实战案例】火语言 RPA 采集豆瓣电影剧名、评分等(加载更多),保存到 Excel 全流程(附完整脚本)
excel·rpa
AntHub12 小时前
vba 输出到日志文件
excel
zhangyao9403301 天前
关于js导入Excel时,Excel的(年/月/日)日期是五位数字的问题。以及对Excel日期存在的错误的分析和处理。
开发语言·javascript·excel
X@AKS2 天前
解决使用EasyExcel导出带公式的excel,公式不自动计算问题
excel
Wang201220132 天前
wps excel中把特定几列除以某一列,然后以百分比显示
excel
LilySesy2 天前
ABAP+在select的时候,可以A=B A=C B=C这样子JOIN吗?
数据库·sql·ai·excel·sap·abap
zhishidi2 天前
Excel表格自适应大小设置方法
excel
缺点内向2 天前
C#: 高效移动与删除Excel工作表
开发语言·c#·.net·excel
程序员晚枫3 天前
Python处理Excel的5个“神仙库”,办公效率直接翻倍!
python·excel