java word模板内容替换并转pdf

488 阅读2分钟

功能:根据word模板替换模板中占位符生成新的word文件、将word文件转换成pdf文件。

maven依赖:

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>4.1.2</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>

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

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

<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>fr.opensagres.poi.xwpf.converter.pdf-gae</artifactId>
    <version>2.0.2</version>
</dependency>

工具类:CreatePdfUtils.java

import com.hundsun.otp.base.constant.ErrorConsts;
import com.hundsun.otp.base.exception.BusinessException;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.pdf.BaseFont;
import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter;
import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions;
import fr.opensagres.xdocreport.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import net.netca.exception.NetcaPDFBoxException;
import net.netca.pdfSign.ISignatureVerifier;
import net.netca.pdfSign.impl.SignatureVerifierImpl;
import net.netca.pki.PkiException;
import net.netca.pki.SignedData;
import org.apache.poi.xwpf.usermodel.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;

/**
 * ClassName CreatePdfUtils
 * Description :
 * >>>>>>>>>>>>>1:替换word内容
 * >>>>>>>>>>>>>2:word转pdf文件
 */
@Slf4j
public class CreatePdfUtils {

    /**
     * MethodName replaceWords
     * Description 替换文档内容
     *
     */
    public static void replaceWords(String filePath, String outputFilePath, Map<String, String> replacements) throws IOException {
        try (FileInputStream fis = new FileInputStream(filePath);
             XWPFDocument document = new XWPFDocument(fis)) {
            // 替换后为空的行 需要删除
            List<Integer> paragraphsToRemove = new ArrayList<>();
            // 替换段落中的占位符
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            for (int i = 0; i < paragraphs.size(); i++) {
                XWPFParagraph next = paragraphs.get(i);
                String oldText = next.getText();
                replaceInParagraph(next, replacements);
                String newText = next.getText();
                if(StringUtils.isNotEmpty(oldText.trim()) && StringUtils.isEmpty(newText.trim())){
                    paragraphsToRemove.add(i);
                }
            }

            // 替换表格中的占位符
            document.getTables().forEach(table -> {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        for (XWPFParagraph paragraph : cell.getParagraphs()) {
                            replaceInParagraph(paragraph, replacements);
                        }
                    }
                }
            });
            // 从后往前删除段落
            for (int i = paragraphsToRemove.size() - 1; i >= 0; i--) {
                document.removeBodyElement(paragraphsToRemove.get(i));
            }
            // 输出新文档
            try (FileOutputStream fos = new FileOutputStream(outputFilePath)) {
                document.write(fos);
            }
        }
    }

    private static void replaceInParagraph(XWPFParagraph paragraph, Map<String, String> replacements) {
        StringBuilder paragraphText = new StringBuilder();
        List<XWPFRun> runs = paragraph.getRuns();
        if(runs.isEmpty()){
            return;
        }
        XWPFRun xwpfRun = runs.get(0);
        String color = xwpfRun.getColor();
        String fontFamily = xwpfRun.getFontFamily();
        int fontSize = xwpfRun.getFontSize();
        for (XWPFRun run : runs) {
            if (run.getText(0) != null) {
                paragraphText.append(run.getText(0));
            }
        }

        String originalText = paragraphText.toString();
        String finalText = originalText;

        // 执行所有替换
        for (Map.Entry<String, String> entry : replacements.entrySet()) {
            finalText = finalText.replace(entry.getKey(), entry.getValue());
        }

        // 如果文本有变化,更新run
        if (!originalText.equals(finalText)) {
            // 清除现有内容
            for (int i = runs.size() - 1; i >= 0; i--) {
                paragraph.removeRun(i);
            }

            // 添加新的run
            if (!finalText.isEmpty()) {
                XWPFRun newRun = paragraph.createRun();
                newRun.setText(finalText);
                newRun.setColor(color);
                newRun.setFontFamily(fontFamily);
                newRun.setFontSize(fontSize);
            }
        }
    }

    /**
     * MethodName wordToPdf
     * Description word转pdf
     *
     */
    public static String wordToPdf(String toPdf) {
        try {
            FileInputStream fis = new FileInputStream(toPdf);
            // 转换后pdf路径
            String tarPdf = toPdf.substring(0, toPdf.lastIndexOf(".")) + ".pdf";
            File file = new File(tarPdf);
            if (file.exists()) {
                return tarPdf;
            }
            FileOutputStream fos = new FileOutputStream(tarPdf);
            XWPFDocument xwpfDocument = new XWPFDocument(fis);
            PdfOptions pdfOptions = PdfOptions.create();
            pdfOptions.fontProvider((familyName, s1, size, style, color) -> {
                BaseFont bfChinese = null;
                try {
                    bfChinese = BaseFont.createFont(getFontPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
                } catch (DocumentException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                Font fontChinese = new Font(bfChinese, size, style, color);
                if (familyName != null) {
                    fontChinese.setFamily(familyName);
                }
                return fontChinese;
            });
            PdfConverter.getInstance().convert(xwpfDocument, fos, pdfOptions);
            return tarPdf;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * MethodName getFontPath
     * Description 获取中文宋体字体库资源路径
     *
     */
    private static String getFontPath() {
        try {
            return CreatePdfUtils.class.getClassLoader().getResource("font/simsun.ttf").toURI().toString();
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }
}

字体库(宋体):simsun.ttf

P_2025-07-16_10-07-23.png

下载字体库:pan.baidu.com/s/1vobIy1gt…

创建测试word模板: word模板.docx

P_2025-07-16_10-27-41.png

工具类使用:

public static void main(String[] args) {
    Map<String, String> replace = new HashMap<>();
    replace.put("name","李四");
    replace.put("age", "31");
    try {
        // word内容替换
        CreatePdfUtils.replaceWords("C:\Users\lisi\Desktop\word模板.docx",
                "C:\Users\lisi\Desktop\word版文档.docx", replace);
        // word转pdf
        CreatePdfUtils.wordToPdf("C:\Users\lisi\Desktop\word版文档.docx"); 
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

最终生成的word文档和转换后的pdf:

1.png

2.png