前言

目前poi-tl只提供了word表格的单行模板渲染能力,但是在实际的开发中,业务需求涉及多行,这里就需要自己编写一个渲染策略。

正文

因为poi-tl使用指定策略的方式为通过ConfigureBuilder的bind方式指定处理某个参数的变量,比如这样:

ConfigureBuilder builder = Configure.builder();
builder.bind("reports", new MultipleRowTableRenderPolicy());

所以第一步需要获取reports所在的行位置。

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

由于是多行渲染,因此需要知道定义的模板行数。

    protected int getMultipleRowNum(XWPFTemplate template) throws CloneNotSupportedException {TemplateResolver resolver = new TemplateResolver(template.getConfig().copy(multiplePrefix, multipleSuffix));List<MetaTemplate> metaTemplates = resolver.resolveDocument(template.getXWPFDocument());if (!metaTemplates.isEmpty()) {RunTemplate run = cast2runTemplate(metaTemplates.get(0));String tagName = run.getTagName();int num = Integer.parseInt(tagName);run.getRun().setText("", 0);return num < 1 ? DEFAULT_MULTIPLE_ROW_NUM : num;}return DEFAULT_MULTIPLE_ROW_NUM;
}

拿到基本信息后就可以遍历数据,进而遍历渲染表格了。

run.setText("", 0);
TemplateResolver resolver = new TemplateResolver(template.getConfig().copy(prefix, suffix));
// 获取模板所在的起始行
int position = getRowIndex(tagCell.getTableRow());
List<XWPFTableRow> tempRows = getAllTemplateRow(table, template, position);
// 保存第行模板,以便在后续操作中获取光标
final XWPFTableRow firstTempRow = tempRows.get(0);
Iterator<?> dataIt = ((Iterable<?>) data).iterator();
boolean hasNextData = dataIt.hasNext();
int index = 0;while (hasNextData) {Object dt = dataIt.next();hasNextData = dataIt.hasNext();Iterator<XWPFTableRow> rowTempIt = tempRows.iterator();boolean hasNextTempRow = rowTempIt.hasNext();while (hasNextTempRow) {XWPFTableRow tempRow = rowTempIt.next();hasNextTempRow = rowTempIt.hasNext();if (!table.addRow(tempRow, position)) {throw new RenderException("创建新的表格行失败");}// 光标操作,移动光标到目标行,以便后续的模板渲染XmlCursor newCursor = firstTempRow.getCtRow().newCursor();newCursor.toPrevSibling();XmlObject object = newCursor.getObject();XWPFTableRow newRow = new XWPFTableRow((CTRow) object, table);newRow.getCtRow().set(object);setTableRow(table, newRow, position);List<XWPFTableCell> cells = newRow.getTableCells();RenderDataCompute dataCompute = template.getConfig().getRenderDataComputeFactory().newCompute(EnvModel.of(dt, EnvIterator.makeEnv(index++, hasNextData || hasNextTempRow)));cells.forEach(tableCell -> {List<MetaTemplate> metaTemplates = resolver.resolveBodyElements(tableCell.getBodyElements());new DocumentProcessor(template, resolver, dataCompute).process(metaTemplates);});++position;}
}removeTableRow(table, position, tempRows.size());

值得一提就是光标的移动操作,相当于操作所有行的确定。取模板的第一行作为基位置,然后每次插入的渲染的行后,就把光标向上移一行,进而指向刚插入的行,最后渲染即可。

EnvIterator.makeEnv只是为了生成一些遍历现在时参数,可以用在渲染参数的表达式中,具体可以参数poi-tl的文档。

附上removeTableRow函数的实现,注意:使用下标移出行时,下标千万不要作自增操作。

protected void removeTableRow(XWPFTable table, int startIndex, int size) {for (int i = 0; i < size; ++i) {table.removeRow(startIndex);}
}

测试

模板

代码

public class MultipleRowTableRenderPolicyTest {public static void main(String[] args) throws IOException {Map<String, Object> params = new HashMap<>();params.put("title", "某某某会议");params.put("date", new Date());params.put("address", "某某会议室");List<Report> reports = new ArrayList<>();reports.add(new Report("王五", new Date(), "汇报内容1"));reports.add(new Report("张三", new Date(), "汇报内容2"));reports.add(new Report("李四", new Date(), "汇报内容3"));params.put("reports", reports);ConfigureBuilder builder = Configure.builder();builder.bind("reports", new MultipleRowTableRenderPolicy());XWPFTemplate xt = XWPFTemplate.compile("src/test/resources/template/render-multiple-row.docx", builder.build()).render(params);xt.writeToFile("render-multiple-row.docx");}static class Report {private String author;private Date time;private String content;public Report(String author, Date time, String content) {this.author = author;this.time = time;this.content = content;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public Date getTime() {return time;}public void setTime(Date time) {this.time = time;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}}
}

结语

相关代码已经上传至github,地址:https://github.com/llzero54/poi-tl-ext

poi-tl-ext扩展,实现多行表格模板替换相关推荐

  1. POI渲染Excel表格模板替换其中指定表格参数,以及Microsoft联机文档查看器遇到的坑

    POI渲染表格替换指定address参数 pom.xml Util工具类 划重点excel文件渲染数据核心方法 POJO 下边介绍下小编这里对线上office展示采用的方式 坑! 缺点 pom.xml ...

  2. 扩展jquery实现客户端表格的分页、排序

    下面链接中是我用jQuery的扩展来实现的表格分页和排序,使用这个扩展必须加上表头<thead>和<tbody>标签,因为我是 通过<tbody>来进行分页的,要是 ...

  3. java使用poi操作excel删除一整行

    java使用poi操作excel删除一整行 需求1:删除excel表格第4行 代码示例: sheet.shiftRows(4, sheet.getLastRowNum(),-1); 第一个参数为行数( ...

  4. Java使用Poi填充Word表格模板(图片和文字)

    Java使用Poi填充Word表格模板(图片和文字) **** 由于个人需求需要对表格模板进行操作,所以本文章只对表格进行替换数据操作,没有段落,没有循环遍历,没有延伸!!!!!(后续补充!!!) * ...

  5. java poi 模板填数据库,java使用POI读取excel模版并向固定表格里填写数据详解

    java使用POI读取excel模版并向固定表格里填写数据详解:public class ExportExcelDemo { private HSSFWorkbook workbook = null; ...

  6. java excel 删除行_使用Apache POI在Excel中删除多行

    我有一张包含75行表格的Excel表格 . 在第76行我有各列的总功能 =SUM(A1:A75) 和 =SUM(B1:B75) 在第77到第92位的行我有一个Excel图表这需要A1:A75和B1:为 ...

  7. SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)

    本编文章继SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格)文章之后 介绍Poi-tl导出word的延伸功能: 所需依赖以及word模板所属位置 见 SpringBoo ...

  8. 使用jquery进行多行表格数据验证

    使用jquery进行多行表格数据验证 <!DOCTYPE html> <html lang="en"> <head><meta chars ...

  9. JeecgBoot轻松解决ERP项目复杂布局需求,JVXETable高性能行表格效果和项目案例

    ERP项目表格布局一般都很复杂,要求大数据.高操作.高性能 ,这个用JeecgBoot如何解决呢? 行编辑无痕刷新,实现鼠标移开即时保存,其他用户数据实时更新并有日历翻牌效果和无痕刷新效果: 行编辑实 ...

最新文章

  1. 和qc哪个发展更好_一图一表让你秒懂什么叫QC/QA/QM
  2. modelandview跳转页面404_Thinkphp制作404跳转页
  3. javamail command not implemented
  4. WSUS使用网络共享存储补丁
  5. 快速安装第三方库的指令——解决第三方库安装超时问题
  6. java 带参数的构造函数_java – mockito模拟一个带参数的构造函数
  7. JavaScript 函数循环、延时、节流、防抖
  8. mysql 移植ucos_基于STM32F767的UCOSIII移植学习
  9. numpy求逆矩阵_线性代数精华2——逆矩阵的推导过程
  10. php 合并 js css,PHP实现合并多个JS和CSS文件示例
  11. linux修改mdc时钟,Linux下用xsupplicant或mdc拨号上网
  12. InVEST实践及在生态系统服务供需、固碳、城市热岛、论文写作等实际项目中的具体应用
  13. 前端面试常问的问题(必须掌握)
  14. 全栈式python工程师培训课程
  15. 各公司用户画像技术案例分享
  16. 裂变海报设计的落地干货,为什么海报在裂变活动中这么重要?
  17. “Win7内部版本7600此Windows副本不是正版”解决方法
  18. Ad Mucher最新有效注册,升级方式
  19. 初识Android 制作一个简单的记账本
  20. 2021年最新ABAQUS复合材料建模仿真与应用专题培训

热门文章

  1. NUXT 运行generate报错 is not in cwd
  2. em4305reader_EM4305和4205中文数据手册
  3. java+bizx文件_14.Teambiz后台开发规范
  4. 100以内两个整数的(随机产生)的加法运算练习程序
  5. Dubbo是什么?Dubbo干什么?Dubbo怎么用?
  6. ArcGIS | ArcGIS 安装及学习资源
  7. No module named win32api
  8. Go redis连接池
  9. 如何使用YYCache存储自定义对象
  10. 在jango中添加富文本