Poi-tl列表渲染,当列表不存在或空时默认填充一行“无”的实现

笔者接触Poi-tl是为了解决项目中遇到的打印需求,后面项目上遇到了遇到在列表渲染的时候,列表不存在时补充一整行水平居中的“无”,即“无”占据一行。这个需求笔者找了很多文章也没有找到很好的解决方案,官方的文档是实现动态表格重写表格渲染,继承DynamicTableRenderPolicy

但是重写了DynamicTableRenderPolicy类就意味着需要完全重写表格的渲染逻辑,这不是笔者需要的,笔者需要的是,当列表有数据时执行原有表格的渲染逻辑,没有数据的时候走笔者渲染“无“的逻辑,而不是完全的重写。

从官方文档并没有找到很好的解决方案,笔者突然想起来Java的继承机制,如果我不继承DynamicTableRenderPolicy而是继承LoopRowTableRenderPolicy类,使用过Poi-tl的应该知道,这个类就是官方提供的表格渲染类。我继承这个类,重写渲染(render)方法,有值则使用父类渲染表格的方法,否则使用自定义渲染逻辑,说干就干,经过长久的调试,笔者写下如下代码:



import cn.hutool.core.collection.CollUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.Rows;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.policy.TableRenderPolicy;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.util.TableTools;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.data.repository.query.ParameterOutOfBoundsException;

import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;


public class MyLoopRowTableRenderPolicy extends LoopRowTableRenderPolicy {

    /**
     * 创建单元格的数量,因为每个票都不同,创建不同的单元格合并才会合并成一整行
     */
    private Integer cellSize;

    public MyLoopRowTableRenderPolicy() {
        super();
        //默认13
        this.cellSize = 13;
    }

    public MyLoopRowTableRenderPolicy(int cellSize) {
        super();
        if(cellSize <= 1){
            throw new RuntimeException("参数错误,只能是大于1的整数");
        }
        this.cellSize = cellSize;
    }

    @Override
    public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
        //数据必须是集合类,否则不应该使用这个渲染器
        if (data instanceof Collection && CollUtil.isEmpty((Collection) data)) {
            //为空时默认补充一行无
            renderEmpty(eleTemplate);
        } else {
            super.render(eleTemplate, data, template);
        }
    }

    /**
     * 渲染空数据,在表格钟默认增加一行无
     *
     * @param eleTemplate
     */
    private void renderEmpty(ElementTemplate eleTemplate) {
        RunTemplate runTemplate = (RunTemplate) eleTemplate;
        XWPFRun run = runTemplate.getRun();
        //消除标签值
        run.setText("", 0);
        XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
        //获取当前表格
        XWPFTable table = tagCell.getTableRow().getTable();
        //获取模板所在行,即表格标签下一行
        int rowIndex = getTemplateRowIndex(tagCell) + 1;
        //删除表格标签下一行
        table.removeRow(rowIndex);
        //插入一行
        XWPFTableRow row = table.insertNewTableRow(rowIndex);
        Stream.iterate(0, i -> i + 1)
                .limit(cellSize).forEach(i -> row.createCell());
        TableTools.mergeCellsHorizonal(table, rowIndex, 0, cellSize - 1);
        try {
            TableRenderPolicy.Helper.renderRow(table.getRow(rowIndex),
                    Rows.of("无").center().textFontFamily("宋体").textFontSize(11).create());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private int getTemplateRowIndex(XWPFTableCell tagCell) {
        XWPFTableRow tagRow = tagCell.getTableRow();
        return this.getRowIndex(tagRow);
    }

    private int getRowIndex(XWPFTableRow row) {
        List<XWPFTableRow> rows = row.getTable().getRows();
        return rows.indexOf(row);
    }

}

可以看到,这样实现很简单,只需要实现当表格数据不存在时的逻辑即可,事实证明,也是可以真正实现的。其中cellSize的作用非常重要,实例化对象的时候需要指定当前渲染”无“的列数,这个需要自己调试,因为如果使用

            TableRenderPolicy.Helper.renderRow(table.getRow(rowIndex),
                    Rows.of("无").center().textFontFamily("宋体").textFontSize(11).create());

以上代码是没办法实现”无“占据一整行的,需要自己指定插入的列数,当列数足够时,就会充满一行,再合并整行实现整行变成一个单元格,当然,如果您有更好的实现,也可以跟我说一说,这已经是我所能想到最灵活的方式,但不是各位大佬的极限。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
poi-tl是一个基于POIJava模板引擎,可以用于导出Word文档。在poi-tl中,可以使用foreach指令实现循环,并根据需要循环输出列表行和列。 在poi-tl中,可以将需要循环的数据存储在一个List对象中,然后使用foreach指令进行循环遍历。假设我们有一个List<RowData>对象,其中RowData是自定义的类,用于表示每一行的数据。RowData类中可以包含一些属性,代表每一行中的不同列。 首先,我们需要在Word模板中使用foreach指令,来循环输出列表行和列。可以使用标签${foreach items=listVar item=rowVar}和${end}将需要循环的部分包围起来。其中listVar是存储数据的List对象的名称,rowVar是循环过程中每一行数据的临时变量名。 然后,在foreach指令中,可以使用${rowVar.property}的方式获取每一行的属性值,来完成对列表行和列的输出。property代表RowData类中的某一个属性的名称。 最后,使用poi-tl提供的模板渲染引擎,将数据填充到Word模板中,生成目标Word文档。 综上所述,利用poi-tl可以很方便地循环输出列表行和列。首先需要准备好存储数据的List对象,并在Word模板中使用foreach指令进行循环遍历。然后,在循环过程中使用${rowVar.property}的方式获取每一行的属性值,完成对列表行和列的输出。最终,使用poi-tl提供的模板渲染引擎将数据填充到Word模板中,生成目标Word文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值