根据模板动态生成word(二)使用poi生成word
@
一、准备模板
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的更多相关文章
- [Vue源码]一起来学Vue模板编译原理(二)-AST生成Render字符串
本文我们一起通过学习Vue模板编译原理(二)-AST生成Render字符串来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学V ...
- Python 实现二维码生成和识别
今天突然想给自己自己做个头像,然后还是二维码的形式,这样只要扫一扫就可以访问我的主页.然后就开始自己的苦逼之路... 其实实现二维码java,c#,C++等都可以实现:由于自己正在学python,所以 ...
- Java利用poi生成word(包含插入图片,动态表格,行合并)
转(小改): Java利用poi生成word(包含插入图片,动态表格,行合并) 2018年12月20日 09:06:51 wjw_11093010 阅读数:70 Java利用poi生成word(包含插 ...
- 使用java Apache poi 根据word模板生成word报表
项目开发过程中,客户提出一堆导出报表的需求,需要导出word格式,页眉还需要加上客户公司的logo,试了几种方案,最后选择了用 Apache poi 加上自定义标签的方式实现. 目前功能还比较简单,一 ...
- java使用poi操作word, 支持动态的行(一个占位符插入多条)和表格中动态行, 支持图片
依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifa ...
- POI生成word文档完整案例及讲解
一,网上的API讲解 其实POI的生成Word文档的规则就是先把获取到的数据转成xml格式的数据,然后通过xpath解析表单式的应用取值,判断等等,然后在把取到的值放到word文档中,最后在输出来. ...
- Freemaker基于word模板动态导出汇总整理
Freemaker基于word模板动态导出汇总整理 一.使用的jar包: 二.Word模板动态导出的基本思路: 1.首先通过自己在word中创建好需要导出的word文本+表格的模板,模板中需要填写内容 ...
- POI生成WORD文档
h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...
- Android根据word模板文档将表单数据生成word文档的方案整理
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 尝试的方案包括以下几种: freemarker 只能在java项目上运行,无法在Android项目上运行: 参考资料:<Fre ...
- Freemaker基于word模板动态导出压缩文件汇总整理
Freemaker基于word模板动态导出压缩文件汇总整理 Freemaker基于word模板动态导出单个文件思路和代码详情见连接: https://www.cnblogs.com/lsy-blogs ...
随机推荐
- SpringBoot @Target、@Retention、@Documented注解简介
jdk1.5起开始提供了4个元注解:@Target.@Retention.@Documented.@Inherited.何谓元注解?就是注解的注解. 在程序开发中,有时候我们需要自定义一个注解,这个自 ...
- 在void 中使用return的意思
在定义的void函数里如果想要提前终止函数 格式为 return; 如果 在有返回值的函数中 格式为: return+值(0 -1 ......) 但如果在void 函数中写return 0 ; 则会 ...
- 2022-08-30:给你一个字符串化学式 formula ,返回 每种原子的数量 。 原子总是以一个大写字母开始,接着跟随 0 个或任意个小写字母,表示原子的名字。 如果数量大于 1,原子后会跟着数
2022-08-30:给你一个字符串化学式 formula ,返回 每种原子的数量 . 原子总是以一个大写字母开始,接着跟随 0 个或任意个小写字母,表示原子的名字. 如果数量大于 1,原子后会跟着数 ...
- mac系统下,docker安装kibana报错,manifest for kibana:latest not found: manifest unknown: manifest unknown
1.问题描述:mac系统下,docker安装kibana报错,manifest for kibana:latest not found: manifest unknown: manifest unkn ...
- Linux 内存管理 pt.3
哈喽大家好,我是咸鱼 在<Linux 内存管理 pt.2>中我们学习了多级页表和大页,我们知道了由于历史遗留的问题,Linux 的页通常为 4KB 这样就会导致一个页表里面会有特别多页,为 ...
- 都说 C++ 没有 GC,RAII: 那么我算个啥?(赠书福利)
*以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「ENG八戒」https://mp.weixin.qq.com/s/7A9-tGZxf4w_7eZl3OUQ4A 学过 Java.C# ...
- Express实战个人订阅号实现网站登录
今天我们来实现一个使用个人订阅号实现网站的功能,后端使用的是 express .其它框架原理基本一致,只是定义路由或返回响应数据部分代码跟 express 有所出入.先来一波效果图: 1. 前言 20 ...
- 在开发过程中使用git rebase还是git merge,优缺点分别是什么?
前言 在开发过程中,git rebase 和 git merge 都是常见的代码版本管理工具.它们都能够将分支合并到主分支,并且都有各自的优缺点. git merge git merge 是一种将两个 ...
- JavaScript模块化 之( Commonjs、AMD、CMD、ES6 modules)演变史
经常在工作中使用define(['./modulename'],function(modulename){}),require(['modulename'],function(modulename){ ...
- hvv蓝初面试常见漏洞问题(上)
1.SQL注入 漏洞成因: 可控变量 变量会带入数据库查询 变量不存在过滤或者变量过滤不严格 注入流程 判断是否有注入点 order by 判断字段数量 union select 报错查看注入点 使用 ...