文章目录

  • 前言
  • 一、需求
  • 二、方案
  • 三、实现
  • 总结

前言

  • word生成是较为常见的功能,通常解决方案有freemarker、poi-tl等。
  • 一般常规的word模板替换可采用第三方封装好的工具实现。
  • 本文涉及动态复杂表格的插入,最好还是采用poi-tl。
  • poi-tl版本差异性较大,如果被版本束缚,较难找到对应版本的copy代码,这时候可以参考其他版本再对照自己版本的jar包文件来对应实现。
    poi 与 poi-tl 版本对应关系 http://deepoove.com/poi-tl

一、需求

根据模板生成对应的word文件。

  1. 包含文本替换
  2. 动态表格,涉及动态合并单元格
  3. word中包含分割线的图片
    前期难点在于动态表格的绘制和锚点替换,后期难点在于poi-tl版本约束(由于某些原因,必须用1.9.1版本)。

二、方案

  1. poi 从头到尾画(即时这个word并不大,code硬编码起来也较为复杂,主要是比较难受,还要考虑各种样式,图片插入等)
  2. 拼html写入word(同上的硬编码较为麻烦,但样式结构可以word另存html后直接用,代码和word打开后的模式不友好,默认为web模式)
  3. 死磕poi-tl

三、实现

1.生成word 关键代码

//构建模板替换的map对象
Map<String, Object> dataMap = wordMaps(findDTO);
//获取模板信息等
String fileName = UUIDUtil.uuid() + ".docx";
String midPath = "uploadFile" + File.separator + "duty" + File.separator;
String filePath = fileUploadRoot + midPath;
String templatePath = this.getFullPathName("evaluate.docx");
//主要执行代码 指定替换内容形式为${xxxx},指定${table}标签的渲染规则为DetailTablePolicy
Configure builder = Configure.newBuilder().buildGramer("${", "}").bind("table", new DetailTablePolicy()).build();
XWPFTemplate template = XWPFTemplate.compile(templatePath, builder).render(dataMap);
try {template.writeToFile(filePath + fileName);template.close();
} catch (IOException e) {e.printStackTrace();
}

2.自定义规则类

package com.gsafety.gemp.evaluate.manage.rule.impl;import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.MergeCellRule;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.TableRenderData;
import com.deepoove.poi.data.Tables;
import com.deepoove.poi.data.style.TableStyle;
import com.deepoove.poi.policy.RenderPolicy;
import com.deepoove.poi.policy.TableRenderPolicy;
import com.deepoove.poi.policy.TextRenderPolicy;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.xwpf.NiceXWPFDocument;
import lombok.SneakyThrows;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;/*** @author Mr.wanter* @time 2022-9-7 0007* @description*/
public class DetailTablePolicy implements RenderPolicy {@SneakyThrows@Overridepublic void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {NiceXWPFDocument doc = template.getXWPFDocument();RunTemplate runTemplate = (RunTemplate) eleTemplate;XWPFRun run = runTemplate.getRun();if (null == data) {return;}List<RowRenderData> rows = (List<RowRenderData>) data;TableStyle.BorderStyle borderStyle = new TableStyle.BorderStyle();borderStyle.setColor("A6A6A6");borderStyle.setSize(4);borderStyle.setType(XWPFTable.XWPFBorderType.SINGLE);TableRenderData tableRenderData = Tables.ofA4MediumWidth().border(borderStyle).center().create();rows.forEach(r -> {tableRenderData.addRow(r);});MergeCellRule.MergeCellRuleBuilder mergeCellRuleBuilder = MergeCellRule.builder();/*** 设置表格合并规则* 1.起始行 MergeCellRule.Grid.of(i, j) i: 行 j: 列* 2.结束行 MergeCellRule.Grid.of(i, j) i: 行 j: 列*///评估对象合并mergeCellRuleBuilder.map(MergeCellRule.Grid.of(1, 0), MergeCellRule.Grid.of(rows.size() - 1, 0));List<String> subTargetContent = new ArrayList<>();rows.forEach(r -> {subTargetContent.add(r.getCells().get(1).getParagraphs().get(0).getContents().get(0).toString());});Set<String> set = subTargetContent.stream().collect(Collectors.toSet());set.forEach(s -> {//只有重复的合并,获取到需要合并项的列的行起始索引后进行合并if (subTargetContent.stream().filter(st -> s.equals(st)).count() > 1) {mergeCellRuleBuilder.map(MergeCellRule.Grid.of(subTargetContent.indexOf(s), 1), MergeCellRule.Grid.of(subTargetContent.lastIndexOf(s), 1));//评估项合并mergeCellRuleBuilder.map(MergeCellRule.Grid.of(subTargetContent.indexOf(s), 4), MergeCellRule.Grid.of(subTargetContent.lastIndexOf(s), 4));//权重合并}});/*** MergeCellRule支持多合并规则,会以Map的形式存入可以看一下源码* !!! 一定要设置完规则后再调用 MergeCellRule的build方法进行构建*/tableRenderData.setMergeRule(mergeCellRuleBuilder.build());TableRenderPolicy.Helper.renderTable(run, tableRenderData);//todo 如果不加入下面代码生成的word会保留模板中的${table}TextRenderPolicy.Helper.renderTextRun(run, "");}
}

3.效果展示

总结

poi版本差异较大,很难拿来即用。
参考:https://blog.csdn.net/weixin_45051216/article/details/112471339解决了:

  1. table样式
  2. RowRenderData的构建方式。
  3. 合并单元格

表格渲染失败(不知道是不是版本问题),最终还是要仔细看jar包中都有哪些类和方法,根据文件名一点一点研究出来。渲染table的关键:TableRenderPolicy.Helper.renderTable(run, tableRenderData)

【java】poi-tl 1.9.1 word模板插入文本及动态复杂表格相关推荐

  1. java poi实现word导出(包括word模板的使用、复制表格、复制行、插入图片的使用)

    java poi实现数据的word导出(包括word模板的使用.复制表格.复制行.插入图片的使用) 1.实现的效果 实现病人基本信息.多条病历数据.多项检查项图片的动态插入(网络图片) 2.模板 把w ...

  2. java 解析word模板为xml, 动态填充数据到xml,最后输出word文档

    java 解析word模板为xml, 动态填充数据到xml,最后输出word文档 在项目中, 一开始是使用java Apache poi 根据word模板生成word报表, 后面发现框架有个低版本的p ...

  3. 图片复制word java_java poi实现word导出(包括word模板的使用、复制表格、复制行、插入图片的使用)...

    java poi实现数据的word导出(包括word模板的使用.复制表格.复制行.插入图片的使用) 1.实现的效果 实现病人基本信息.多条病历数据.多项检查项图片的动态插入(网络图片) 2.模板 把w ...

  4. Java读取word模板,并动态生成word

    Java读取word模板,并动态生成word ​ 最近有个需求是将数据库里存入的用户个人信息生成一个word然后供用户下载,第一时间就就想到了poi来做,所以记录一下免得自己忘了,忘了也可以回来看看

  5. Java将对象信息写到word模板中(全网最简单版)

    Java将对象信息写到word模板中 一.首先进行依赖的导入 <!-- 证书模板写入信息 --><dependency><groupId>com.deepoove& ...

  6. JAVA POI 导出EXCEL时,EXCEL模板中的公式无效问题

    JAVA POI 出力EXCEL时,EXCEL模板中的公式无效问题 工作中遇到一个问题. EXCEL模板有两个sheet,画面内容要导出到第二个sheet中,第一个sheet设置公式,读取第二个she ...

  7. PHPWord替换word模板内容时,存在表格,且不确定表格行数的处理方式

    PHPWord替换word模板内容时,存在表格,且不确定表格行数的处理方式 想得到的目标表格 表格可能存在若干行,需要循环生成,插入到word模板中 word模板 实现过程 1.Composer安装 ...

  8. 关于JAVA POI解析WPS docx文档中的table(复杂表格包含单元格横向,纵向的合并)

    关于JAVA POI解析WPS docx文档中的table(复杂表格包含单元格横向,纵向的合并) 首先,关于poi解析表格先阅读一篇他人的博客 使用poi读取word2007(.docx)中的复杂表格 ...

  9. java poi 上传与下载word文件

    java编程要实现对word的操作没有vb那种编程语言来得容易,得借助一些开源组件,其中就包括jacob.poi等, 而poi应用得最为广泛,对word2003和2007的读和写word操作都十分方便 ...

最新文章

  1. OpenCV 4.5.4 刚刚发布!新增SoftNMS、DNN模型8位量化等功能
  2. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)
  3. hdu2155 小黑的镇魂曲(dp)
  4. 新建linux组、用户命令
  5. STM32、Cortex-M3和ARMv8-M之间的关联
  6. 彻底解决zend studio 下 assignment in condition警告
  7. java面向对象编程基础实验报告_20155313 实验三《Java面向对象程序设计》实验报告...
  8. 读《scikiit-learn机器学习》支持向量机
  9. 如何学会阅读源码,看这篇就够了!
  10. Springboot集成通用Mapper与Pagehelper,实现mybatis+Druid的多数据源配置
  11. Practise 5.2测试与封装(黑白盒
  12. 浏览器背后的运行机制
  13. ps6人脸识别液化工具在哪_ps液化工具在哪?(Photoshop基础教程:液化工具)
  14. vscode调整代码大小
  15. 吴伯凡-认知方法论-效率高并不一定是好事
  16. 下一关口令:别犹“豫”,看“浙”里,一起“皖”
  17. OpenCV+YOLO+IP摄像头实现目标检测
  18. 一梦江湖获取服务器信息后没有登录,一梦江湖登录不上怎么办 登录不上解决方案...
  19. 信息系统项目管理师(2022年)—— 重点内容:项目合同管理(13)
  20. Mysql密码修改方式

热门文章

  1. Javascript+Ajax+Node JS +socket .io +mysql 实现在线私人聊天
  2. Esper学习之三:进程模型 .
  3. pycharm配置IdeaVim
  4. EASYEXCEL 根据模板导出
  5. 云创大数据亮相第四届中国-亚欧安博会,智慧路灯伴侣、单向光闸引关注热潮...
  6. charles、Fiddler抓取https原理
  7. 【学习笔记】《Writing Science》14-21
  8. 美国诚实签经验——医院预约单和医院资料,医生预约收据和报价表,赴美预算,赴美行程,保险是加分项,工作证明(勾出职位和薪酬),附上名片或者工卡,全家福照片...
  9. 数据挖掘习题之决策树算法
  10. 手机游戏引擎 Cocos2d-x