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();
之后和正文段落一样
注:
- 表格的一格相当于一个完整的docx文档,只是没有页眉和页脚。里面可以有表格,使用
xwpfTableCell.getTables()
获取。- 在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文档如下:
源文件地址:
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();
}
结果:
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();
}
结果:
三、案例
使用未修改过的上文的原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);}
}
结果:
参考或相关文章
https://www.iteye.com/blog/elim-2049110
https://www.jianshu.com/p/6603b1ea3ad1