在企业应用中,经常需要把后台数据导出成 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();
}
❌ 缺点:
-
每个导出都要重复写响应头、流操作。
-
代码臃肿,可维护性差。
-
不方便支持多 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层了)

✅ 优点:
-
代码简洁:控制器只负责数据处理,不关心 Excel 流操作。
-
复用性高:任何 VO/DTO 都可以直接导出。
-
支持多 Sheet :将来需要在同一个 Excel 文件中导出多张表时,只需调用
exportMultiSheet
即可。
4. 总结
通过 ExcelExportUtil
工具类,我们可以:
-
轻松实现单个 Sheet 导出。
-
支持多 Sheet 导出,实现复杂报表的汇总。
-
封装响应头和流操作,减少重复代码,提高可维护性。
💡 Tip:如果将来需要"每个表单生成独立 Excel",只需多次调用 export
方法即可。