博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POI解析word文件,并为特定规则的key替换值
阅读量:4358 次
发布时间:2019-06-07

本文共 5707 字,大约阅读时间需要 19 分钟。

转载: 

模板替换内容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毫秒.

转载于:https://www.cnblogs.com/yxgmagic/p/9851367.html

你可能感兴趣的文章
《Docker入门实战》笔记(一)
查看>>
hdu 3635 Dragon Balls (并查集)
查看>>
文件操作
查看>>
7.java集合,泛型简单总结,IO流
查看>>
杭电2007 平方和与立方和
查看>>
JS邮箱验证-正则验证
查看>>
关于SQL查询效率,100w数据,查询只要1秒
查看>>
Quartz 2D绘图
查看>>
JS Fetch
查看>>
EJB 笔记
查看>>
【delete】Android自定义控件(四) 自定义ImageView动态设置ImageView的高度
查看>>
HDUOJ------(1230)火星A+B
查看>>
Servlet
查看>>
基于jquery地图特效全国网点查看代码
查看>>
【leetcode】867 - Transpose Matrix
查看>>
Python的平凡之路(17)
查看>>
Git for Windows之使用SSH协议开通公钥免密登陆功能
查看>>
Identity Server4学习系列一
查看>>
计算机硬件-基础
查看>>
完成登录功能,用session记住用户名
查看>>