Java使用POI通过模板生成Word

本文介绍了如何使用Java的POI库通过模板生成Word文档,详细讲解了POI操作Word的基本元素,如段落、表格、页眉页脚,并提供了读写Word的测试用例及实际案例。

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");

    // 获取第一段文件的第一个run
    XWPFRun 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");
        // 生成word
        generateWord(fileInputStream, fileOutputStream, insertTextMap, addList);

    }
}

结果:

image-20210617100524291

参考或相关文章

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

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

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值