ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Fesod 单元格合并完全指南:注解合并、LoopMergeStrategy 与自定义合并策略实战

Fesod 单元格合并完全指南:注解合并、LoopMergeStrategy 与自定义合并策略实战 后端【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址https://gitcode.com/gh_mirrors/fast/fesod点击查看免费下载生成 Excel 报表时单元格合并是高频需求——合并列中重复的类别名称、创建汇总行、让表头更紧凑。Fesod 提供了三种由浅入深的合并方式ContentLoopMerge注解、LoopMergeStrategy写入处理器以及继承AbstractMergeStrategy的自定义策略。本文以官方文档为主线结合仓库源码剖析每种方式的实现原理与适用边界帮助你在最简单与最灵活之间做出正确选择并直接照搬到自己的项目里。合并方案总览Fesod 的单元格合并能力集中在两个层次对应 annotation/write/style 与 write/merge 两个包方式声明位置灵活性典型场景ContentLoopMerge(eachRow N)数据类字段上的注解固定、内置于 POJO按固定行数周期合并某一列LoopMergeStrategy(eachRow, columnIndex)运行时注册的写入处理器动态、与数据类解耦运行时配置应用于任意列可与模板填充配合AbstractMergeStrategy子类自定义写入处理器完全可控基于数据内容或自定义规则的复杂合并前两种解决按固定行数循环合并的规则化需求第三种则把合并逻辑完全交给你。此外源码中还提供了用于一次性绝对区域合并的OnceAbsoluteMergeStrategy对应OnceAbsoluteMerge注解下文会一并说明。基于注解的合并ContentLoopMerge用法与效果使用ContentLoopMerge(eachRow N)注解字段Fesod 会自动合并该列中每 N 行的单元格。定义一个带合并注解的 POJOGetter Setter EqualsAndHashCode public class DemoMergeData { ContentLoopMerge(eachRow 2) ExcelProperty(字符串标题) private String string; ExcelProperty(日期标题) private Date date; ExcelProperty(数字标题) private Double doubleData; }写入代码与普通写 Excel 完全一致无需额外配置Test public void annotationMergeWrite() { String fileName annotationMergeWrite System.currentTimeMillis() .xlsx; FesodSheet.write(fileName, DemoMergeData.class) .sheet() .doWrite(data()); }假设data()返回 4 条记录且字符串标题列的值两两相同生成的表格效果如下ABC1字符串标题日期标题数字标题2字符串0与第 3 行合并2026-07-31 20:50:230.5632026-07-31 20:50:230.564字符串1与第 5 行合并2026-07-31 20:50:230.5652026-07-31 20:50:230.56第 2、3 行的字符串标题单元格被合并为一块第 4、5 行同理而 B、C 列保持原样。注解的完整语义从源码看ContentLoopMerge是一个运行时保留、可被继承、仅能标注在字段上的注解ContentLoopMerge.javaTarget({ElementType.FIELD}) Retention(RetentionPolicy.RUNTIME) Inherited public interface ContentLoopMerge { int eachRow() default 1; // 每多少行合并一次 int columnExtend() default 1; // 横向扩展合并的列数 }它只有两个属性eachRow合并周期即每 N 行合并一次默认 1columnExtend向右侧扩展合并的列数默认 1即只合并当前列。例如ContentLoopMerge(columnExtend 2)会把当前列和右侧一列一并合并——FillAnnotationData.java 的测试数据类就是这么用的。注解本身只承载配置真正的合并行为由底层的LoopMergeStrategy执行在 LoopMergeProperty.build() 中注解会被转换为LoopMergeProperty(eachRow, columnExtend)随后由ExcelWriteHeadProperty结合列下标实例化对应的策略处理器。也就是说注解合并本质上就是内置版的策略合并。基于策略的合并LoopMergeStrategy用法当合并规则需要在运行时决定或不想把合并逻辑写进数据类时可以注册LoopMergeStrategy(eachRow, columnIndex)作为写入处理器Test public void strategyMergeWrite() { String fileName strategyMergeWrite System.currentTimeMillis() .xlsx; // 合并第 0 列中每 2 行 LoopMergeStrategy strategy new LoopMergeStrategy(2, 0); FesodSheet.write(fileName, DemoData.class) .registerWriteHandler(strategy) .sheet() .doWrite(data()); }registerWriteHandler是写入参数构建器上公开的方法AbstractExcelWriterParameterBuilder.java处理器会被收集进customWriteHandlerList在写行、写单元格的生命周期中被依次回调。LoopMergeStrategy实现了RowWriteHandler属于行级处理器。构造参数与校验规则LoopMergeStrategy提供两个构造器LoopMergeStrategy.javapublic LoopMergeStrategy(int eachRow, int columnIndex) // columnExtend 取默认值 1 public LoopMergeStrategy(int eachRow, int columnExtend, int columnIndex)参数含义与注解一致eachRow合并周期、columnExtend横向扩展列数、columnIndex目标列下标从 0 开始。构造时会做严格校验非法参数直接抛IllegalArgumentExceptioneachRow 1→ EachRows must be greater than 1columnExtend 1→ ColumnExtend must be greater than 1columnExtend 1 eachRow 1→ ColumnExtend or eachRows must be greater than 1即至少要有一维大于 1否则合并无意义columnIndex 0→ ColumnIndex must be greater than 0合并逻辑的实现细节LoopMergeStrategy的核心逻辑在afterRowDisposeLoopMergeStrategy.javaOverride public void afterRowDispose(RowWriteHandlerContext context) { if (context.getHead() || context.getRelativeRowIndex() null) { return; } if (context.getRelativeRowIndex() % eachRow 0) { CellRangeAddress cellRangeAddress new CellRangeAddress( context.getRowIndex(), context.getRowIndex() eachRow - 1, columnIndex, columnIndex columnExtend - 1); context.getWriteSheetHolder().getSheet().addMergedRegionUnsafe(cellRangeAddress); } }三个关键行为值得注意跳过表头行context.getHead()为真正在写表头或relativeRowIndex为空时直接返回合并只作用于数据区。周期判定relativeRowIndex % eachRow 0时触发合并即每个周期块的第一行发起合并覆盖rowIndex到rowIndex eachRow - 1的连续行。文档示例new LoopMergeStrategy(2, 0)中第 0、2、4…行相对数据区起始行会各发起一次 2 行合并。使用addMergedRegionUnsafe这是 POI 提供的不做重叠检查的合并方法能提升大文件写入性能代价是调用方需自行保证合并区域不冲突——这也是使用eachRow等规则化合并时通常不会出问题的原因。测试侧同样覆盖了该能力StyleDataTest.loopMergeStrategy 演示了对 10 条数据注册new LoopMergeStrategy(2, 1)合并第 1 列每 2 行FillDataTest.complexFillImpl 则展示了在模板填充excelWriter.fill(...)场景中通过FesodSheet.writerSheet().registerWriteHandler(new LoopMergeStrategy(2, 0))让填充结果按周期合并这说明策略合并可以自由地与其他写入能力组合。自定义合并策略继承 AbstractMergeStrategy用法对于复杂合并逻辑例如基于数据内容的合并可以继承AbstractMergeStrategy并实现merge方法public class CustomMergeStrategy extends AbstractMergeStrategy { Override protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { if (relativeRowIndex ! null relativeRowIndex % 2 0 head.getColumnIndex() 0) { // 注意1 假设只有一行表头。多行表头场景请使用 cell.getRowIndex() 代替。 int startRow relativeRowIndex 1; int endRow startRow 1; sheet.addMergedRegion(new CellRangeAddress(startRow, endRow, 0, 0)); } } }使用方式与LoopMergeStrategy相同通过registerWriteHandler注册Test public void customMergeWrite() { String fileName customMergeWrite System.currentTimeMillis() .xlsx; FesodSheet.write(fileName, DemoData.class) .registerWriteHandler(new CustomMergeStrategy()) .sheet() .doWrite(data()); }源码揭示的回调机制AbstractMergeStrategy实现了CellWriteHandler属于单元格级处理器AbstractMergeStrategy.javapublic abstract class AbstractMergeStrategy implements CellWriteHandler { Override public void afterCellDispose(CellWriteHandlerContext context) { if (context.getHead()) { return; } merge( context.getWriteSheetHolder().getSheet(), context.getCell(), context.getHeadData(), context.getRelativeRowIndex()); } protected abstract void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex); }框架在每个数据单元格写完后调用afterCellDispose自动跳过表头单元格然后把四个关键上下文交给你的merge实现sheet当前写入的 POISheet用于调用addMergedRegion(...)cell当前单元格可通过它拿到getRowIndex()、getColumnIndex()等真实坐标head当前列的表头元数据Headhead.getColumnIndex()是这一列在表头中的列下标relativeRowIndex当前行相对数据区起始行的下标从 0 开始用于在多行表头场景下计算绝对行号。文档示例的注释点出了新手最容易踩的坑示例中startRow relativeRowIndex 1假设只有一行表头一旦表头变成两行相对行号换算出的绝对行号就会错位。源码层面更稳健的做法是直接用cell.getRowIndex()拿绝对行号与表头行数彻底解耦。同理merge方法体内的head.getColumnIndex() 0判断用于把合并限定到某一列你也可以改为按cell.getColumnIndex()判断。补充一次性绝对区域合并write/merge包中还提供了与循环合并互补的OnceAbsoluteMergeStrategyOnceAbsoluteMergeStrategy.java。它实现的是SheetWriteHandler在工作表创建完成时把指定绝对区域firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex合并一次适合做固定位置的汇总行、标题区。其对应的类级别注解是OnceAbsoluteMergeOnceAbsoluteMerge.java四个下标属性默认均为 -1表示未指定。与循环合并不同它的四个构造参数要求均不小于 0否则抛IllegalArgumentException。三种方式如何选方式最佳适用场景ContentLoopMerge固定模式的简单合并内置于数据类中LoopMergeStrategy动态合并运行时配置AbstractMergeStrategy基于数据内容或自定义规则的复杂合并实操建议能注解就注解合并规则固定且与数据强绑定如按 ID 归组的类别列直接用ContentLoopMerge代码量最小规则要动态化用策略合并周期、目标列来自运行时配置或外部参数用LoopMergeStrategy它还能和模板填充、样式策略等写入处理器自由组合见 FillDataTest内容驱动用自定义策略合并与否取决于单元格的值、跨列判断等继承AbstractMergeStrategy并把行号计算统一建立在cell.getRowIndex()的绝对坐标上避免多行表头时错位留意区域冲突LoopMergeStrategy使用addMergedRegionUnsafe不做重叠校验多个合并策略同时注册时请自行保证各合并区域互不重叠表头行数要牢记所有相对行号relativeRowIndex都是从数据区首行算起的换算绝对行号时务必把表头行数算进去。参考链接官方文档单元格合并英文原版、中文版注解定义ContentLoopMerge.java、OnceAbsoluteMerge.java策略实现LoopMergeStrategy.java、AbstractMergeStrategy.java、OnceAbsoluteMergeStrategy.java处理器注册入口AbstractExcelWriterParameterBuilder.registerWriteHandler测试用例StyleDataTest.java、FillDataTest.java、FillAnnotationData.java赞分享后端【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址https://gitcode.com/gh_mirrors/fast/fesod点击查看免费下载相关推荐Apache Fesod 写 Excel 单元格合并全攻略注解、策略与自定义实现Apache Fesod 写 Excel 单元格合并全攻略注解、策略与自定义实现 在生成 Excel 报表时合并单元格是常见需求——例如将一列中重复出现的分后端EasyExcel单元格合并功能详解LoopMergeStrategy实战EasyExcel单元格合并功能详解LoopMergeStrategy实战 1. 痛点直击Excel合并单元格的三宗罪 你是否还在为以下Excel合并问后端Apache Fesod合并策略完全指南LoopMerge与OnceAbsoluteMerge实战解析Apache Fesod合并策略完全指南LoopMerge与OnceAbsoluteMerge实战解析 Apache Fesod作为easyexcel作者最新后端上一篇三步免费解锁Wand专业版告别游戏时间限制的终极方案下一篇免费解锁Wand游戏修改器3分钟掌握完整功能增强技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表