抽象类通过模板方法模式固定excel导出流程,子类仅需实现createheaderrow、filldatarows等钩子方法;支持泛型、注解配置样式及前后置扩展,避免线程安全问题。

在报表导出组件中,用抽象类固定 Excel 生成的骨架步骤,核心是把“不变的流程”抽出来,把“变化的细节”留给子类实现。这样既保证所有导出行为遵循统一结构(比如创建工作簿、写表头、填数据、设置样式、输出流),又支持不同报表(用户报表、订单报表、库存报表)灵活定制内容。
定义抽象导出骨架:封装标准流程
抽象类不负责具体数据或字段,只定义完整的导出生命周期方法,并用 template method 模式 控制执行顺序:
- export():模板方法,public final,按固定顺序调用各钩子方法,禁止子类重写流程
- createWorkbook():返回 Workbook,子类决定用 HSSFWorkbook 还是 XSSFWorkbook(.xls/.xlsx)
- createHeaderRow():由子类提供列名数组(如 ["用户名", "手机号", "注册时间"])
- fillDataRows():传入 Sheet 和数据列表,子类逐行写入单元格(可处理空值、日期格式、金额千分位等)
- applyStyles():可选,子类为标题行、数值列等设置字体、边框、对齐方式
- writeToStream():接收 OutputStream,完成 write() 和 close()
子类只需关注业务差异,不重复造轮子
比如一个订单导出类只需继承抽象基类,实现几个关键方法:
- getHeaders() → 返回 ["订单号", "客户姓名", "下单时间", "总金额", "状态"]
- getDataList() → 调用订单服务查分页数据(已自动分页处理?可在抽象类加分页钩子)
- fillOneRow() → 接收 Row 和 Order 对象,分别 setCellValue,处理 BigDecimal 格式化、状态枚举转中文等
无需再操心文件流怎么关、workbook 怎么初始化、响应头怎么设——这些都在抽象类里一次写好、全局复用。
增强扩展性的小技巧
实际项目中可进一步解耦:
- 用泛型 AbstractExcelExporter
,让 fillDataRows 接收 List ,子类明确数据类型 - 把样式配置外移到配置类或注解(如 @ExcelColumn(title = "金额", format = "¥#,##0.00")),抽象类通过反射读取,减少硬编码
- 增加 beforeExport() 和 afterExport() 钩子,方便子类做日志记录、临时文件清理、异步通知等
- 配合 Spring,抽象类用 @Scope("prototype"),避免多线程下 workbook 状态污染
避免常见陷阱
用抽象类组织导出逻辑时要注意:
- 不要在抽象类里 new ArrayList() 或 new HashMap() 做缓存——子类并发调用会共享状态;应确保每个 export() 调用都新建局部对象
- Workbook、Sheet、Row、Cell 都是 POI 的非线程安全对象,抽象类中不要持有实例变量,所有操作基于方法参数传递
- 异常要分层处理:IO 异常在 writeToStream 中捕获并包装成业务异常;数据转换异常应在 fillOneRow 中抛出,带行号便于排查
- 如果支持多 sheet 导出,把单 sheet 逻辑封装为 protected 方法,export() 内循环调用,保持主干清晰
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











