word按照版本为两种:doc和docx,POI针对这两种操作需要不同的API:
doc操作使用HWPFDocument,替换思想就是找到书签的起止位置,对范围内的文本进行替换:
public static void docOperate(InputStream inputStream,OutputStream outputStream,
Map<String,String> dataMap) throws IOException {
HWPFDocument document = new HWPFDocument(inputStream);
Bookmarks bookmarks = document.getBookmarks();
for(int dwI = 0;dwI < bookmarks.getBookmarksCount();dwI++){
Bookmark bookmark = bookmarks.getBookmark(dwI);
if(dataMap.containsKey(bookmark.getName())){
Range range = new Range(bookmark.getStart(),bookmark.getEnd(),document);
range.replaceText(dataMap.get(bookmark.getName()),false);
}
}
document.write(outputStream);
}
docx 操作使用 XWPFDocument,替换思想是根据段落找到书签,然后取书签起止范围内的节点进行操作,目的就是将书签起止范围内的多个文字节点删除,然后添加新的文本内容;此时可将文本插入或替换在书签的前、中、后等位置,因书签原内容已删,效果其实是一样的:
/** docx中定义的部分常量引用 **/
public static final String RUN_NODE_NAME = "w:r";
public static final String TEXT_NODE_NAME = "w:t";
public static final String BOOKMARK_START_TAG = "w:bookmarkStart";
public static final String BOOKMARK_END_TAG = "w:bookmarkEnd";
public static final String BOOKMARK_ID_ATTR_NAME = "w:id";
public static final String STYLE_NODE_NAME = "w:rPr";
public static void docxOperate(InputStream inputStream,OutputStream outputStream,Map<String,String> dataMap) throws IOException {
XWPFDocument document = new XWPFDocument(inputStream).getXWPFDocument();
List<XWPFParagraph> paragraphList = document.getParagraphs();
for(XWPFParagraph xwpfParagraph:paragraphList){
CTP ctp = xwpfParagraph.getCTP();
for(int dwI = 0;dwI < ctp.sizeOfBookmarkStartArray();dwI++){
CTBookmark bookmark = ctp.getBookmarkStartArray(dwI);
if(dataMap.containsKey(bookmark.getName())){
XWPFRun run = xwpfParagraph.createRun();
run.setText(dataMap.get(bookmark.getName()));
Node firstNode = bookmark.getDomNode();
Node nextNode = firstNode.getNextSibling();
while(nextNode != null){
// 循环查找结束符
String nodeName = nextNode.getNodeName();
if(nodeName.equals(BOOKMARK_END_TAG)){
break;
}
// 删除中间的非结束节点,即删除原书签内容
Node delNode = nextNode;
nextNode = nextNode.getNextSibling();
ctp.getDomNode().removeChild(delNode);
}
if(nextNode == null){
// 始终找不到结束标识的,就在书签前面添加
ctp.getDomNode().insertBefore(run.getCTR().getDomNode(),firstNode);
}else{
// 找到结束符,将新内容添加到结束符之前,即内容写入bookmark中间
ctp.getDomNode().insertBefore(run.getCTR().getDomNode(),nextNode);
}
}
}
}
document.write(outputStream);
document.close();
}
pom需要引入的maven包:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.13</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.13</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.13</version>
</dependency>
按照这个方法,普通的文本替换没有问题,但是图片和table等内容无法替换,poi对doc的操作据了解是没有table相关的,docx的table等操作需要自行找到拷贝、替换方案。