模板替换内容key是: ${enforcername1}

package com.jsy.test.pdf;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.apache.poi.POIXMLDocument;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;public class WordReplace {
 /*
	 * 在Word文档中段落的最小的操作单位是XWPFRun,正常的一个段落,会被分割成多个小的XWPFRun,这些XWPFRun组合在一起就是一个完整的段落。
	 * 
	 * 
	 * 通常我们在Word文档中做的标记${mark_1},在文档中会被分割成多个XWPFRun,所以我们没法使用一个XWPFRun来进行标记文本替换。在这里,
	 * 我们想到一个方法,就是使用类似于找到字符串中子串下标的方法,找到段落XWPFRun中子Run下标,记录起始和终止下标,在终止下标后insertNewRun
	 * (int pos),然后再从终止下标往前xwpfParagraph.removeRun(i);到起始下标。
	 * 
	 * 
	 * 这个方法可以以整个段落位单位进行标记文本替换。然后遍历文档中所有的段落进行替换。 全部代码如下:
	 */ /**
	 * 替换所有段落中的标记
	 * 
	 * @param xwpfParagraphList
	 * @param params
	 */
	public static void replaceInAllParagraphs(List<XWPFParagraph> xwpfParagraphList, Map<String, String> params) {
		for (XWPFParagraph paragraph : xwpfParagraphList) {
			if (paragraph.getText() == null || paragraph.getText().equals(""))
				continue;
			for (String key : params.keySet()) {
				if (paragraph.getText().contains(key)) {
					System.err.println("旧值: "+key);
					replaceInParagraph(paragraph, key, params.get(key));
				}
			}
		}
	} /**
	 * 替换段落中的字符串
	 * 
	 * @param xwpfParagraph
	 * @param oldString
	 * @param newString
	 */
	public static void replaceInParagraph(XWPFParagraph xwpfParagraph, String oldString, String newString) {
		Map<String, Integer> pos_map = findSubRunPosInParagraph(xwpfParagraph, oldString);
		System.err.println(pos_map.toString());
		if (pos_map != null) {
			System.out.println("start_pos:" + pos_map.get("start_pos"));
			System.out.println("end_pos:" + pos_map.get("end_pos"));
			List<XWPFRun> runs = xwpfParagraph.getRuns();
			XWPFRun modelRun = runs.get(pos_map.get("end_pos"));
			XWPFRun xwpfRun = xwpfParagraph.insertNewRun(pos_map.get("end_pos") + 1);
			System.err.println(newString);
			xwpfRun.setText(newString);

			System.out.println("字体大小:" + modelRun.getFontSize());
			if (modelRun.getFontSize() != -1)
				xwpfRun.setFontSize(modelRun.getFontSize());// 默认值是五号字体,但五号字体getFontSize()时,返回-1
			xwpfRun.setFontFamily(modelRun.getFontFamily());
			for (int i = pos_map.get("end_pos"); i >= pos_map.get("start_pos"); i--) {
				System.out.println("remove run pos in :" + i);
				xwpfParagraph.removeRun(i);
			}
		}
	} /**
	 * 找到段落中子串的起始XWPFRun下标和终止XWPFRun的下标
	 * 
	 * @param xwpfParagraph
	 * @param substring
	 * @return
	 */
	public static Map<String, Integer> findSubRunPosInParagraph(XWPFParagraph xwpfParagraph, String substring) {
		List<XWPFRun> runs = xwpfParagraph.getRuns();
		int start_pos = 0;
		int end_pos = 0;
		String subtemp = "";
		for (int i = 0; i < runs.size(); i++) {
			subtemp = "";
			start_pos = i;
			for (int j = i; j < runs.size(); j++) {
				if (runs.get(j).getText(runs.get(j).getTextPosition()) == null)
					continue;
				subtemp += runs.get(j).getText(runs.get(j).getTextPosition());
				if (subtemp.equals(substring)) {
					end_pos = j;
					Map<String, Integer> map = new HashMap<>();
					map.put("start_pos", start_pos);
					map.put("end_pos", end_pos);
					return map;
				}
			}
		}
		return null;
	} // 对表格中标记文本的替换
	// 有些标记做在表格单元格中,每个单元格中的内容都是一个普通的段落,所以,我们只需遍历出所有的单元格,然后遍历出每个单元格中的所有段落,再调用以上方法进行标记文本替换即可。代码如下 /**
	 * 替换所有的表格
	 * 
	 * @param xwpfTableList
	 * @param params
	 */
	public static void replaceInTables(List<XWPFTable> xwpfTableList, Map<String, String> params) {
		for (XWPFTable table : xwpfTableList) {
			replaceInTable(table, params);
		}
	} /**
	 * 替换一个表格中的所有行
	 * 
	 * @param xwpfTable
	 * @param params
	 */
	public static void replaceInTable(XWPFTable xwpfTable, Map<String, String> params) {
		List<XWPFTableRow> rows = xwpfTable.getRows();
		replaceInRows(rows, params);
	} /**
	 * 替换表格中的一行
	 * 
	 * @param rows
	 * @param params
	 */
	public static void replaceInRows(List<XWPFTableRow> rows, Map<String, String> params) {
		for (int i = 0; i < rows.size(); i++) {
			XWPFTableRow row = rows.get(i);
			replaceInCells(row.getTableCells(), params);
		}
	} /**
	 * 替换一行中所有的单元格
	 * 
	 * @param xwpfTableCellList
	 * @param params
	 */
	public static void replaceInCells(List<XWPFTableCell> xwpfTableCellList, Map<String, String> params) {
		for (XWPFTableCell cell : xwpfTableCellList) {
			replaceInCell(cell, params);
		}
	} /**
	 * 替换表格中每一行中的每一个单元格中的所有段落
	 * 
	 * @param cell
	 * @param params
	 */
	public static void replaceInCell(XWPFTableCell cell, Map<String, String> params) {
		List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
		replaceInAllParagraphs(cellParagraphs, params);
	} // 调用方法测试
	public static void main(String[] args) throws IOException, Exception {
		// TODO Auto-generated method stub
		String filepathString = "C:\\Users\\Administrator\\Desktop\\现场笔录.docx";
		String destpathString = "C:\\Users\\Administrator\\Desktop\\现场笔录_new.docx";
		Map<String, String> map = new HashMap<String, String>();
		map.put("${enforcername1}", "小白鼠");
		map.put("${enforcername2}", "喵喵喵");
		map.put("${drivername}", "卡特琳娜");
		map.put("${driverphone}", "15112345678"); OPCPackage pack = POIXMLDocument.openPackage(filepathString);
		XWPFDocument document = new XWPFDocument(pack);
		/**
		 * 对段落中的标记进行替换
		 */
		List<XWPFParagraph> parasList = document.getParagraphs();
		replaceInAllParagraphs(parasList, map);
		/**
		 * 对表格中的标记进行替换
		 */
		List<XWPFTable> tables = document.getTables();
		replaceInTables(tables, map);
		FileOutputStream outStream = null;
		try {
			outStream = new FileOutputStream(destpathString);
			document.write(outStream);
			outStream.flush();
			outStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}}

 个人感觉有点慢,15KB的文件需要750ms,希望如果有大佬有好的方案可以评论区告诉我!因为我这个还要转PDF然后立即预览的,所以尽量缩减时间.

我现在的方法网页预览需要5164毫秒.