@

一、准备模板

1、创建模板文件

创建一个word文件,输入如下图所示的内容:

二、代码实践

1、引入依赖

     <dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.0</version>
</dependency>

2、自定义XWPFDocument

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline; import java.io.IOException;
import java.io.InputStream; public class CustomXWPFDocument extends XWPFDocument {
public CustomXWPFDocument(InputStream in) throws IOException {
super(in);
} public CustomXWPFDocument() {
super();
} public CustomXWPFDocument(OPCPackage pkg) throws IOException {
super(pkg);
} /**
* @param id
* @param width 宽
* @param height 高
* @param paragraph 段落
*/
public void createPicture(int id, int width, int height,
XWPFParagraph paragraph) {
final int EMU = 9525;
width *= EMU;
height *= EMU;
String blipId = super.getRelationId(super.getAllPictures().get(id));
CTInline inline = paragraph.createRun().getCTR().addNewDrawing()
.addNewInline();
String picXml = ""
+ "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
+ " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:nvPicPr>" + " <pic:cNvPr id=\""
+ id
+ "\" name=\"Generated\"/>"
+ " <pic:cNvPicPr/>"
+ " </pic:nvPicPr>"
+ " <pic:blipFill>"
+ " <a:blip r:embed=\""
+ blipId
+ "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
+ " <a:stretch>"
+ " <a:fillRect/>"
+ " </a:stretch>"
+ " </pic:blipFill>"
+ " <pic:spPr>"
+ " <a:xfrm>"
+ " <a:off x=\"0\" y=\"0\"/>"
+ " <a:ext cx=\""
+ width
+ "\" cy=\""
+ height
+ "\"/>"
+ " </a:xfrm>"
+ " <a:prstGeom prst=\"rect\">"
+ " <a:avLst/>"
+ " </a:prstGeom>"
+ " </pic:spPr>"
+ " </pic:pic>"
+ " </a:graphicData>" + "</a:graphic>"; inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch (XmlException xe) {
xe.printStackTrace();
}
inline.set(xmlToken); inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0); CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height); CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(id);
docPr.setName("图片名称");
docPr.setDescr("描述信息");
}
}

2、公用的方法和变量

	private final String REGEX = "\\$\\{(.+?)\\}";

    private CustomXWPFDocument document;

    public PoICreateWordFactory(String templatePath) throws IOException {
loadTemplate(templatePath);
} /**
* 加载模板
*
* @param templatePath 模板路径
* @return 包含返回true, 不包含返回false
*/
private void loadTemplate(String templatePath) throws IOException {
try (InputStream in = Files.newInputStream(Paths.get(templatePath))) {
//转成word
this.document = new CustomXWPFDocument(in);
}
} /**
* 生成word
*
* @param targetFile word生成路径
* @return 包含返回true, 不包含返回false
*/
public void createWordFile(String targetFile) throws IOException {
try (FileOutputStream out = new FileOutputStream(targetFile)){
document.write(out);
}
} /**
* 判断文本中是否包含$
*
* @param text 文本
* @return 包含返回true, 不包含返回false
*/
public boolean checkText(String text) {
boolean check = false;
if (text.indexOf("$") != -1) {
check = true;
}
return check;
}

3、工具类引用的包名

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

4、段落文本替换

	/**
* 替换段落文本
*
* @param textMap(数据源)
*/
public void replaceText(Map<String, Object> textMap) {
//获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//获取到段落中的所有文本内容
String text = paragraph.getText();
//判断此段落中是否有需要进行替换的文本
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
Pattern pattern = Pattern.compile(REGEX);
Matcher matcher = pattern.matcher(run.toString());
if (matcher.find()) {
String key = matcher.group(1);
if(textMap.containsKey(key)){
run.setText(String.valueOf(textMap.get(key)), 0);
}
}
}
}
}
}

5、图片替换

	/**
* 替换图片
*
* @param imageMap(数据源)
*/
public void replaceImage(Map<String, byte[]> imageMap) throws org.apache.poi.openxml4j.exceptions.InvalidFormatException {
//段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
Set<Map.Entry<String, byte[]>> imageSets = imageMap.entrySet();
for (XWPFParagraph paragraph : paragraphs) {
//获取到段落中的所有文本内容
String text = paragraph.getText();
//判断此段落中是否有需要进行替换的文本
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
Pattern pattern = Pattern.compile(REGEX);
String runText = run.toString();
Matcher matcher = pattern.matcher(runText);
if (matcher.find()) {
String key = matcher.group(1);
if(imageMap.containsKey(key)){
//清空原有内容
run.setText("", 0);
//设置图片
document.addPictureData(imageMap.get(key), XWPFDocument.PICTURE_TYPE_PNG);
//创建一个word图片,并插入到文档中-->像素可改
document.createPicture(document.getAllPictures().size() - 1, 240, 240,paragraph);
break;
}
}
}
}
}
}

6、表格替换

	/**
* 替换表格内容
*
* @param index(表格索引:第几个表格)
* @param tableList(数据源)
* @Return void
* @Exception
*/
public void replaceTable(int index, List<List<String>> tableList) {
XWPFTable table = document.getTables().get(index);
//创建行,根据需要插入的数据添加新行,不处理表头
for (int i = 1; i <= tableList.size(); i++) {
table.createRow();
}
//遍历表格插入数据
List<XWPFTableRow> rows = table.getRows();
for (int i = 1; i < tableList.size()+1; i++) {
XWPFTableRow newRow = table.getRow(i);
List<XWPFTableCell> cells = newRow.getTableCells();
List<String> rowData = tableList.get(i - 1);
for (int j = 0; j < rowData.size(); j++) {
XWPFTableCell cell = cells.get(j);
String text = rowData.get(j);
cell.setText(text);
//表格样式一致-->没有此段表格会默认左对齐
//有此段会使表格格式一致
CTTc cttc = cell.getCTTc();
CTTcPr ctPr = cttc.addNewTcPr();
ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
}
}
}

7、完整的工具类代码

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern; public class PoICreateWordFactory { /**
* 生成ord
*
*/
public void crateWord(Map<String, Object> dataMap, String templatePath, String targetFile) throws IOException, InvalidFormatException {
//加载模板文件
loadTemplate(templatePath); //将dataMap拆分成 textMap、imageMap、tableMap TODO 烂尾中 //段落替换变量
Map<String, Object> textMap = new HashMap<>();
//替换模板数据
replaceText(textMap); //图片替换变量
Map<String, byte[]> imageMap = new HashMap<>();
replaceImage(imageMap); //写入表格
List<List<String>> arrearsList = new ArrayList<>();
replaceTable(0, arrearsList); //生成新的word
createWordFile(targetFile);
} private final String REGEX = "\\$\\{(.+?)\\}"; private CustomXWPFDocument document; public PoICreateWordFactory() {} public PoICreateWordFactory(String templatePath) throws IOException {
loadTemplate(templatePath);
} /**
* 加载模板
*
* @param templatePath 模板路径
* @return 包含返回true, 不包含返回false
*/
public void loadTemplate(String templatePath) throws IOException {
try (InputStream in = Files.newInputStream(Paths.get(templatePath))) {
//转成word
this.document = new CustomXWPFDocument(in);
}
} /**
* 生成word
*
* @param targetFile word生成路径
* @return 包含返回true, 不包含返回false
*/
public void createWordFile(String targetFile) throws IOException {
try (FileOutputStream out = new FileOutputStream(targetFile)){
document.write(out);
}
} /**
* 判断文本中是否包含$
*
* @param text 文本
* @return 包含返回true, 不包含返回false
*/
public boolean checkText(String text) {
boolean check = false;
if (text.indexOf("$") != -1) {
check = true;
}
return check;
} /**
* 替换段落文本
*
* @param textMap(数据源)
*/
public void replaceText(Map<String, Object> textMap) {
//获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//获取到段落中的所有文本内容
String text = paragraph.getText();
//判断此段落中是否有需要进行替换的文本
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
Pattern pattern = Pattern.compile(REGEX);
Matcher matcher = pattern.matcher(run.toString());
if (matcher.find()) {
String key = matcher.group(1);
if(textMap.containsKey(key)){
run.setText(String.valueOf(textMap.get(key)), 0);
}
}
}
}
}
} /**
* 替换图片
*
* @param imageMap(数据源)
*/
public void replaceImage(Map<String, byte[]> imageMap) throws org.apache.poi.openxml4j.exceptions.InvalidFormatException {
//段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
Set<Map.Entry<String, byte[]>> imageSets = imageMap.entrySet();
for (XWPFParagraph paragraph : paragraphs) {
//获取到段落中的所有文本内容
String text = paragraph.getText();
//判断此段落中是否有需要进行替换的文本
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
Pattern pattern = Pattern.compile(REGEX);
String runText = run.toString();
Matcher matcher = pattern.matcher(runText);
if (matcher.find()) {
String key = matcher.group(1);
if(imageMap.containsKey(key)){
//清空原有内容
run.setText("", 0);
//设置图片
document.addPictureData(imageMap.get(key), XWPFDocument.PICTURE_TYPE_PNG);
//创建一个word图片,并插入到文档中-->像素可改
document.createPicture(document.getAllPictures().size() - 1, 240, 240,paragraph);
break;
}
}
}
}
}
} /**
* 替换表格内容
*
* @param index(表格索引:第几个表格)
* @param tableList(数据源)
* @Return void
* @Exception
*/
public void replaceTable(int index, List<List<String>> tableList) {
XWPFTable table = document.getTables().get(index);
//创建行,根据需要插入的数据添加新行,不处理表头
for (int i = 1; i <= tableList.size(); i++) {
table.createRow();
}
//遍历表格插入数据
List<XWPFTableRow> rows = table.getRows();
for (int i = 1; i < tableList.size()+1; i++) {
XWPFTableRow newRow = table.getRow(i);
List<XWPFTableCell> cells = newRow.getTableCells();
List<String> rowData = tableList.get(i - 1);
for (int j = 0; j < rowData.size(); j++) {
XWPFTableCell cell = cells.get(j);
String text = rowData.get(j);
cell.setText(text);
//表格样式一致-->没有此段表格会默认左对齐
//有此段会使表格格式一致
CTTc cttc = cell.getCTTc();
CTTcPr ctPr = cttc.addNewTcPr();
ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
}
}
}
}

三、验证模板生成

1、测试代码

public static void main(String[] args) throws IOException, InvalidFormatException {
String templatePath = "D:\\文章\\word生成\\poi\\qiantiao.docx";
String targetFile = "D:\\test\\qiantiao.docx";
//初始化,并加载模板文件
PoICreateWordFactory poICreateWordFactory = new PoICreateWordFactory(templatePath); //段落替换变量
LocalDate currentDate = LocalDate.now();
LocalDate endDate = currentDate.plusYears(1L);
Map<String, Object> textMap = new HashMap<>();
textMap.put("debtor", "陈有楚");
textMap.put("nowYear", String.valueOf(currentDate.getYear()));
textMap.put("nowMonth", String.valueOf(currentDate.getMonthValue()));
textMap.put("nowDay", String.valueOf(currentDate.getDayOfMonth()));
textMap.put("arrears", "一顿老魏、贵州大黄牛、v我50");
textMap.put("endYear", String.valueOf(endDate.getYear()));
textMap.put("endMonth", String.valueOf(endDate.getMonthValue()));
textMap.put("endDay", String.valueOf(endDate.getDayOfMonth()));
textMap.put("creditor", "知北游");
//替换模板数据
poICreateWordFactory.replaceText(textMap); //图片替换变量
FileInputStream imageInput = new FileInputStream("D:\\picture\\其他\\24-05-23-142418.png");
byte[] bytes = new byte[imageInput.available()];
imageInput.read(bytes);
imageInput.close();
Map<String, byte[]> imageMap = new HashMap<>();
imageMap.put("image1", bytes);
poICreateWordFactory.replaceImage(imageMap); //写入表格
List<List<String>> arrearsList = new ArrayList<>();
arrearsList.add(Arrays.asList("一顿老魏", "1", "三月内"));
arrearsList.add(Arrays.asList("贵州大黄牛", "1", "一年内"));
arrearsList.add(Arrays.asList("v我50", "1", "一月内"));
//获取表格位置 0代表第一个表格,写死第一个,模板里也只有一个模板
poICreateWordFactory.replaceTable(0, arrearsList); //生成新的word
poICreateWordFactory.createWordFile(targetFile); }

2、生成效果

四、总结

其实从测试代码里就可以发现这其实只是一个半成品代码,文本替换、图片替换、表格替换甚至需要分别传递不同的数据map。本来是打算合并成一个dataMap,然后根据参数类来区分是文本、图片、表格的。然后拆分成多个数据map。但是在写这些代码时发现了也是基于poi开发的开源项目poi-tl。功能很全,我想实现的功能他都有,顿时我写的上面这些代码就失去了意义,然后就烂尾了。。。后面有时间介绍一下poi-tl这个开源项目使用方式吧,经过试验这个确实功能完善,非常推荐。

根据模板动态生成word(二)使用poi生成word的更多相关文章

  1. [Vue源码]一起来学Vue模板编译原理(二)-AST生成Render字符串

    本文我们一起通过学习Vue模板编译原理(二)-AST生成Render字符串来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学V ...

  2. Python 实现二维码生成和识别

    今天突然想给自己自己做个头像,然后还是二维码的形式,这样只要扫一扫就可以访问我的主页.然后就开始自己的苦逼之路... 其实实现二维码java,c#,C++等都可以实现:由于自己正在学python,所以 ...

  3. Java利用poi生成word(包含插入图片,动态表格,行合并)

    转(小改): Java利用poi生成word(包含插入图片,动态表格,行合并) 2018年12月20日 09:06:51 wjw_11093010 阅读数:70 Java利用poi生成word(包含插 ...

  4. 使用java Apache poi 根据word模板生成word报表

    项目开发过程中,客户提出一堆导出报表的需求,需要导出word格式,页眉还需要加上客户公司的logo,试了几种方案,最后选择了用 Apache poi 加上自定义标签的方式实现. 目前功能还比较简单,一 ...

  5. java使用poi操作word, 支持动态的行(一个占位符插入多条)和表格中动态行, 支持图片

    依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifa ...

  6. POI生成word文档完整案例及讲解

    一,网上的API讲解 其实POI的生成Word文档的规则就是先把获取到的数据转成xml格式的数据,然后通过xpath解析表单式的应用取值,判断等等,然后在把取到的值放到word文档中,最后在输出来. ...

  7. Freemaker基于word模板动态导出汇总整理

    Freemaker基于word模板动态导出汇总整理 一.使用的jar包: 二.Word模板动态导出的基本思路: 1.首先通过自己在word中创建好需要导出的word文本+表格的模板,模板中需要填写内容 ...

  8. POI生成WORD文档

    h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...

  9. Android根据word模板文档将表单数据生成word文档的方案整理

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 尝试的方案包括以下几种: freemarker 只能在java项目上运行,无法在Android项目上运行: 参考资料:<Fre ...

  10. Freemaker基于word模板动态导出压缩文件汇总整理

    Freemaker基于word模板动态导出压缩文件汇总整理 Freemaker基于word模板动态导出单个文件思路和代码详情见连接: https://www.cnblogs.com/lsy-blogs ...

随机推荐

  1. Abp框架Web站点的安全性提升

    本文将从GB/T 28448-2019<信息安全技术 网络安全等级保护测评要求>规定的安全计算环境中解读.摘要若干安全要求,结合Abp框架,对站点进行安全升级. [身份鉴别]应对登录的用户 ...

  2. 如何使用Webpack工具构建项目

    起步 webpack 用于编译 JavaScript 模块.一旦完成 安装,你就可以通过 webpack CLI 或 API 与其配合交互.如果你还不熟悉 webpack,请阅读 核心概念 和 对比, ...

  3. Caused by: java.net.BindException: Address already in use: JVM_Bind(ActiveMq已经启动)

    1.本地启动项目开启两个启动类出错. Error creating bean with name 'brokerService' defined in class path resource [com ...

  4. [Pytorch框架] 5.3 Fashion MNIST进行分类

    文章目录 5.3 Fashion MNIST进行分类 Fashion MNIST 介绍 数据集介绍 分类 格式 数据提交 数据加载 创建网络 损失函数 优化器 开始训练 训练后操作 可视化损失函数 保 ...

  5. Win Airtest + 夜神模拟器 实现APP自动化

    前言: Airtest 是一个跨平台的UI自动化测试框架,适用于游戏和App.目前支持Windows.Android平台和 iOS 平台. 一.下载Airtest 下载地址:https://airte ...

  6. Prism Sample 29-InvokeCommandAction

    一下子跳到29,不是我的错,应该是新版本中去掉了一些过重的功能,案例就也去掉了,所以不是我的错. 本例是演示行为转命令的,事实上前面已经用到了. xmlns:i="http://schema ...

  7. Django笔记三十六之单元测试汇总介绍

    本文首发于公众号:Hunter后端 原文链接:Django笔记三十六之单元测试汇总介绍 Django 的单元测试使用了 Python 的标准库:unittest. 在我们创建的每一个 applicat ...

  8. 2023-04-14:n对情侣坐在连续排列的 2n 个座位上,想要牵到对方的手, 人和座位由一个整数数组 row 表示,其中 row[i] 是坐在第 i 个座位上的人的ID, 情侣们按顺序编号,第一对

    2023-04-14:n对情侣坐在连续排列的 2n 个座位上,想要牵到对方的手, 人和座位由一个整数数组 row 表示,其中 row[i] 是坐在第 i 个座位上的人的ID, 情侣们按顺序编号,第一对 ...

  9. 2022-12-23:portainer是docker的web可视化工具。如果根据docker部署去写yaml,默认local是k8s,而不是docker,这不符合需求,需要修改yaml。请问部署在

    2022-12-23:portainer是docker的web可视化工具.如果根据docker部署去写yaml,默认local是k8s,而不是docker,这不符合需求,需要修改yaml.请问部署在 ...

  10. 2022-04-01:有n个人,m个任务,任务之间有依赖记录在int[][] depends里。 比如: depends[i] = [a, b],表示a任务依赖b任务的完成, 其中 0 <= a <

    2022-04-01:有n个人,m个任务,任务之间有依赖记录在int[][] depends里. 比如: depends[i] = [a, b],表示a任务依赖b任务的完成, 其中 0 <= a ...