功能:根据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
下载字体库:pan.baidu.com/s/1vobIy1gt…
创建测试word模板: word模板.docx
工具类使用:
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: