poi-tl合并word模版表格单元格

最近在做word的打印,有很多的复杂的表格格式,需要合并单个格这些,网上查了许多资料,也试过重写DynamicTableRenderPolicy类,但是打出来的表格有很多问题,比如需要设置单元格列表、行高、字体这些,因为模版的表格跟生成的表格不统一,非常麻烦!!!

我看官方给出的样例和我参考的文章打出来的格式都是统一的,没有出现我遇见的那种情况,不知道怎么回事,可能是我没调出来

参考的文章:

Poi导出动态表格-数据渲染(支持单元格合并)-Word_poi-tl 动态表格-CSDN博客

最后同事想了一个取巧的方法,就是我们继承LoopRowTableRenderPolicy类,等数据都填充好了,再合并相同的类型的单元格,上代码:

package cn.com.yced.sample.cdy.common.poiPolicy;

import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;

import java.util.Objects;

/**
 * @description: 单元格合并策略类
 */
@Data
@AllArgsConstructor
public class MergeTablePolicy extends LoopRowTableRenderPolicy {
    /**
     * 纵向合并列数(1开始)
     */
    private Integer verticallyMergeColumn;
    /**
     * 纵向合并开始行数(0开始)
     */
    private Integer verticallyMergeStartRow;
    /**
     * 横向合并列数(1开始)
     */
    private Integer horizontallyMergeColumn;
    /**
     * 横向合并开始行数(0开始)
     */
    private Integer horizontallyMergeStartRow;

    @Override
    protected void afterloop(XWPFTable table, Object data) {
        // 先处理纵向相邻相同的单元格合并
        if (verticallyMergeColumn != null && verticallyMergeStartRow != null) {
            mergeTableCellsVertically(table);
        }
        // 再处理横向相邻相同的单元格合并
        if (horizontallyMergeColumn != null && horizontallyMergeStartRow != null) {
            mergeTableCellsHorizontally(table);
        }
    }


    /**
     * @description:  合并纵向相同内容的单元格
     */
    private void mergeTableCellsVertically(XWPFTable table) {
        for (int col = 0; col < verticallyMergeColumn; col++) {
            // 前4行是表头,数据从第5行开始
            int mergeStart = verticallyMergeStartRow;
            String prevValue = null;

            for (int row = verticallyMergeStartRow; row < table.getNumberOfRows(); row++) {
                String currentValue = Objects.nonNull(table.getRow(row).getCell(col)) ? table.getRow(row).getCell(col).getText() : "";

                // 如果当前单元格不为空且与前一个值相等,则继续
                if (!currentValue.isBlank() && currentValue.equals(prevValue)) {
                    continue;
                }

                // 合并前一组单元格
                if (mergeStart < row - 1) {
                    TableTools.mergeCellsVertically(table, col, mergeStart, row - 1);
                }

                // 更新合并起点和前一个值
                mergeStart = row;
                prevValue = currentValue;
            }

            // 处理最后一组合并
            if (mergeStart < table.getNumberOfRows() - 1) {
                TableTools.mergeCellsVertically(table, col, mergeStart, table.getNumberOfRows() - 1);
            }
        }
    }

    /**
     * @description:  合并横向相同内容的单元
     */
    private void mergeTableCellsHorizontally(XWPFTable table) {
        for (int row = horizontallyMergeStartRow; row < table.getNumberOfRows(); row++) {
            int mergeStart = 0;
            String prevValue = null;

            for (int col = 0; col < horizontallyMergeColumn; col++) {
                String currentValue = Objects.nonNull(table.getRow(row).getCell(col)) ? table.getRow(row).getCell(col).getText() : "";

                // 如果当前单元格为空或与前一个值不同,则处理合并
                if (currentValue.isBlank() || !currentValue.equals(prevValue)) {
                    // 执行合并逻辑
                    if (mergeStart < col - 1) {
                        TableTools.mergeCellsHorizonal(table, row, mergeStart, col - 1);
                    }
                    // 更新起始合并位置和前一个值
                    mergeStart = col;
                    prevValue = currentValue;
                } else {
                    // 如果当前值等于前一个值,继续
                    continue;
                }
            }

            // 处理最后一组的合并
            if (mergeStart < horizontallyMergeColumn - 1) {
                TableTools.mergeCellsHorizonal(table, row, mergeStart, horizontallyMergeColumn - 1);
            }
        }
    }
}

我们使用的时候在导出的时候传入这个策略类就好;

实现效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值