Java使用POI通过模板生成Word

news/2025/3/14 19:01:58/

Java使用POI通过模板生成Word

前言

最近工作需要用到,所以记录下来以便查找。

一、概述

POI读写word使用的核心类是XWPFDocument。一个XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档。

主要包含下面这几种对象:

  • XWPFParagraph:代表一个段落。
  • XWPFRun:代表具有相同属性的一段文本。
  • XWPFTable:代表一个表格。
  • XWPFTableRow:表格的一行。
  • XWPFTableCell:表格对应的一个单元格。

引用一段写的很好的结构说明:

原文:Poi之Word文档结构介绍

1、poi之word文档结构介绍之正文段落

一个文档包含多个段落,一个段落包含多个Runs,一个Runs包含多个Run,Run是文档的最小单元

获取所有段落:List<XWPFParagraph> paragraphs = word.getParagraphs();

获取一个段落中的所有Runs:List<XWPFRun> xwpfRuns = xwpfParagraph.getRuns();

获取一个Runs中的一个Run:XWPFRun run = xwpfRuns.get(index);

2、poi之word文档结构介绍之正文表格

一个文档包含多个表格,一个表格包含多行,一行包含多列(格),每一格的内容相当于一个完整的文档

获取所有表格:List<XWPFTable> xwpfTables = doc.getTables();

获取一个表格中的所有行:List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();

获取一行中的所有列:List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();

获取一格里的内容:List<XWPFParagraph> paragraphs = xwpfTableCell.getParagraphs();

之后和正文段落一样

注:

  1. 表格的一格相当于一个完整的docx文档,只是没有页眉和页脚。里面可以有表格,使用xwpfTableCell.getTables()获取。
  2. 在poi文档中段落和表格是完全分开的,如果在两个段落中有一个表格,在poi中是没办法确定表格在段落中间的。(当然除非你本来知道了,这句是废话)。只有文档的格式固定,才能正确的得到文档的结构

3、poi之word文档结构介绍之页眉:

一个文档可以有多个页眉(不知道怎么会有多个页眉。。。),页眉里面可以包含段落和表格

获取文档的页眉:List<XWPFHeader> headerList = doc.getHeaderList();

获取页眉里的所有段落:List<XWPFParagraph> paras = header.getParagraphs();

获取页眉里的所有表格:List<XWPFTable> tables = header.getTables();

之后就一样了

4、poi之word文档结构介绍之页脚:

页脚和页眉基本类似,可以获取表示页数的角标

二、用例测试

先使用代码去达到对word的读和写。

数据准备

编写一个word文档如下:

image-20210616172350172

源文件地址:

1- 读

/*** @Description 测试读取word文件* @Author hacah* @Date 2021/6/15 14:45*/
public static void testReadWord() throws IOException {// 填写输入流XWPFDocument xwpfDocument = new XWPFDocument(new FileInputStream("E:\\OneDrive\\文档\\自我介绍.docx"));// 获取文本数据List<XWPFParagraph> paragraphs = xwpfDocument.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {for (XWPFRun run : paragraph.getRuns()) {System.out.println(run.text());}}// 获取表格数据List<XWPFTable> tables = xwpfDocument.getTables();for (XWPFTable table : tables) {List<XWPFTableRow> rows = table.getRows();for (XWPFTableRow row : rows) {List<XWPFTableCell> tableCells = row.getTableCells();for (XWPFTableCell tableCell : tableCells) {List<XWPFParagraph> paragraphs1 = tableCell.getParagraphs();for (XWPFParagraph xwpfParagraph : paragraphs1) {List<XWPFRun> runs = xwpfParagraph.getRuns();for (XWPFRun run : runs) {System.out.println(run);}}}}}
}
public static void main(String[] args) throws IOException {testReadWord();
}

结果:

image-20210616173003505

2- 写

/*** @Description 测试使用模板写入数据,新建数据后的word* @author hacah* @Date 2021/6/15 15:09*/
public static void testWriteWord() throws IOException {XWPFDocument xwpfDocument = new XWPFDocument(new FileInputStream("E:\\OneDrive\\文档\\自我介绍.docx"));FileOutputStream fileOutputStream = new FileOutputStream("E:\\OneDrive\\文档\\通过模板创建的数据.docx");// 获取第一段文件的第一个runXWPFRun xwpfRun = xwpfDocument.getParagraphs().get(0).getRuns().get(0);xwpfRun.setText("修改的数据");xwpfDocument.write(fileOutputStream);fileOutputStream.close();
}
public static void main(String[] args) throws IOException {testWriteWord();
}

结果:

image-20210616173147153

三、案例

使用未修改过的上文的原word的文件。对${}的数据进行替换,对空表格插入数据。

代码如下:

package com.hacah.word;import org.apache.commons.codec.binary.StringUtils;
import org.apache.poi.util.StringUtil;
import org.apache.poi.xwpf.usermodel.*;import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author Hacah* @className: templateToWord* @description: TODO 类描述* @date 2021/6/15 15:17*/
public class templateToWord {/*** @param wordValue ${...} 带${}的变量* @param map       存储需要替换的数据* @return java.lang.String* @Description 有${}的值匹配出替换的数据,没有${}就返回原来的数据* @author hacah* @Date 2021/6/15 16:02*/public static String matchesValue(String wordValue, Map<String, String> map) {for (String s : map.keySet()) {String s1 = new StringBuilder("${").append(s).append("}").toString();if (s1.equals(wordValue)) {wordValue = map.get(s);}}return wordValue;}/*** @return boolean* @Description 测试是否包含需要替换的数据* @author hacah* @Date 2021/6/15 15:30*/public static boolean isReplacement(String text) {boolean check = false;if (text.contains("$")) {check = true;}return check;}/*** @Description 处理所有文段数据,除了表格* @param xwpfDocument* @param insertTextMap* @author hacah* @Date 2021/6/17 10:04*/public static void handleParagraphs(XWPFDocument xwpfDocument, Map<String, String> insertTextMap) {for (XWPFParagraph paragraph : xwpfDocument.getParagraphs()) {String text = paragraph.getText();if (isReplacement(text)) {for (XWPFRun run : paragraph.getRuns()) {// 判断带有${}的run// System.out.println(run);run.setText(matchesValue(run.text(), insertTextMap), 0);}}}}/*** @Description 通过word模板生成word的主方法* @param inputStream* @param outputStream* @param insertTextMap* @param addList* @author hacah* @Date 2021/6/17 10:03*/public static void generateWord(InputStream inputStream, OutputStream outputStream, Map<String, String> insertTextMap, List<String[]> addList) throws IOException {//获取docx解析对象XWPFDocument xwpfDocument = new XWPFDocument(inputStream);// 处理所有文段数据,除了表格handleParagraphs(xwpfDocument, insertTextMap);// 处理表格数据handleTable(xwpfDocument, insertTextMap, addList);// 写出数据xwpfDocument.write(outputStream);outputStream.close();}/*** @Description 处理表格数据方法* @param xwpfDocument* @param insertTextMap* @param addList* @author hacah* @Date 2021/6/17 10:04*/public static void handleTable(XWPFDocument xwpfDocument, Map<String, String> insertTextMap, List<String[]> addList) {List<XWPFTable> tables = xwpfDocument.getTables();for (XWPFTable table : tables) {List<XWPFTableRow> rows = table.getRows();if (rows.size() > 1) {if (isReplacement(table.getText())) {// 替换数据for (XWPFTableRow row : rows) {List<XWPFTableCell> tableCells = row.getTableCells();for (XWPFTableCell tableCell : tableCells) {if (isReplacement(tableCell.getText())) {// 替换数据List<XWPFParagraph> paragraphs = tableCell.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {run.setText(matchesValue(tableCell.getText(), insertTextMap), 0);}}}}}} else {// 插入数据for (int i = 1; i < addList.size(); i++) {XWPFTableRow row = table.createRow();}List<XWPFTableRow> rowList = table.getRows();for (int i = 1; i < rowList.size(); i++) {XWPFTableRow xwpfTableRow = rowList.get(i);List<XWPFTableCell> tableCells = xwpfTableRow.getTableCells();for (int j = 0; j < tableCells.size(); j++) {XWPFTableCell xwpfTableCell = tableCells.get(j);xwpfTableCell.setText(addList.get(i - 1)[j]);}}}}}}public static void main(String[] args) throws IOException {// 替换文本数据构建HashMap<String, String> insertTextMap = new HashMap<>(16);insertTextMap.put("like", "[爱好test]");insertTextMap.put("birthday", "[生日test]");insertTextMap.put("sex", "[性别test]");insertTextMap.put("name", "[姓名test]");insertTextMap.put("age", "[年龄test]");// 插入数据构建ArrayList<String[]> addList = new ArrayList<>();addList.add(new String[]{"【1插入电话】", "【2插入地址】", "【3插入邮箱】"});addList.add(new String[]{"【test插入电话2】", "【test插入地址2】", "【test插入邮箱2】"});// 设置模板输入和结果输出FileInputStream fileInputStream = new FileInputStream("E:\\OneDrive\\文档\\自我介绍.docx");FileOutputStream fileOutputStream = new FileOutputStream("E:\\OneDrive\\文档\\通过模板创建的数据.docx");// 生成wordgenerateWord(fileInputStream, fileOutputStream, insertTextMap, addList);}
}

结果:

image-20210617100524291

参考或相关文章

https://www.iteye.com/blog/elim-2049110

https://www.jianshu.com/p/6603b1ea3ad1


http://www.ppmy.cn/news/899777.html

相关文章

如何在word中安装grammarly

步骤如下 1.打开网址 传递门https://www.grammarly.com/office-addin 会看到这个界面 之后你就点击红色框 2.注册、登录 你如果没有注册过的话是需要注册一个账号的我这里使用163邮箱注册&#xff0c;qq邮箱收不到验证码&#xff08;亲测&#xff09; 3.下载 4.安装 注意…

Word邮件合并功能详解:合并后生成多个word文档,删除空白页

Word邮件合并功能详解&#xff1a;合并后生成多个word文档&#xff0c;删除空白页 最近在实习&#xff0c;干了很多打杂得工作&#xff0c;所以office软件用的很多很多&#xff0c;瞬间觉得自己可以去裸考计算机二级了哈哈哈哈哈哈。今天因为工作用到了邮件合并这个功能&#…

分享一个MySQL数据库表结构导出word文档最方便的方法

1、使用的是MySQL-Front工具&#xff0c;这个工具使用非常方便&#xff0c;尤其是导出数据的时候&#xff0c;几百万的数据一两分钟就导完了&#xff0c;推荐使用。 MySQL-Front下载&#xff08;只有3.93M&#xff09;&#xff1a;https://mysql-front.en.softonic.com/ 注&a…

《C++程序设计原理与实践》笔记 第20章 容器和迭代器

本章和下一章将介绍STL&#xff0c;即C标准库的容器和算法部分。关键概念序列和迭代器用于将容器&#xff08;数据&#xff09;和算法&#xff08;处理&#xff09;联系在一起。 20.1 存储和处理数据 首先考虑一个简单的例子&#xff1a;Jack和Jill各自在测量车速&#xff0c…

基于Open3D的点云处理11-三维点云表面重建

点云表面重建 &#xff08;1&#xff09;显式建模方法&#xff1a; Explicit reconstruction 例如&#xff1a;Delaunay 三角网、Alpha shapes &#xff08;2&#xff09;隐式建模方法&#xff1a; Implicit reconstruction 例如&#xff1a;径向基函数法、移动最小二乘法、泊…

Latex学习

Latex学习 文章目录 Latex学习一、TeX,LaTeX,MikTex,CTeX,TeX Live到底是什么及其区别二、TexLive安装与环境配置1、VSCodeTexliveSumatraPDF搭建Latex环境 &#xff08;★★★&#xff09;2、Texlive安装宏包 三、MikTex安装1、MikTex安装2、winEdt的使用&#xff08;★★★★…

element中icon字体图标的使用

效果图 官方提供的图标 icon字体图标 安装 安装依赖 cnpm install element-plus/icons-vue 编写src/plugins/icons.js import * as components from "element-plus/icons-vue";export default {install: (app) > {for (const key in components) {const comp…

ShowDoc任意文件上传绕过手法分享

因为你仍能痛苦&#xff0c;所以说明你对生活还抱有希望&#xff01; 漏洞描述 ShowDoc 存在任意文件上传漏洞&#xff0c;攻击者通过构造特殊的数据包可以上传恶意文件控制服务器 漏洞复现 访问漏洞url 构造如下数据包上传php文件&#xff0c;进行绕过 POST /index.php?…