package combineDoc;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
public class MergeDocPoi {
/**
* 合并两个docx文档方法,对文档包含的图片无效
* @author boxinliuyue
* @date 2018年11月9日
*/
public static void main(String[] args) throws Exception {
String file1="D:\\data\\WordTest\\Combine\\1.docx";
String file2="D:\\data\\WordTest\\Combine\\2.docx";
String file3="D:\\data\\WordTest\\Combine\\3.docx";
List<String> fileList=new ArrayList();
fileList.add(file1);
fileList.add(file2);
fileList.add(file3);
String destDocx = "D:\\data\\WordTest\\Combine\\合成文件.docx";
mergeDoc(fileList, destDocx);
}
/**
* 合并docx文件
* @param srcDocxs 需要合并的目标docx文件
* @param destDocx 合并后的docx输出文件
*/
public static void mergeDoc(List<String> srcDocxs,String destDocx){
OutputStream dest = null;
List<OPCPackage> opcpList = new ArrayList();
int length = null == srcDocxs ? 0 : srcDocxs.size();
/**
* 循环获取每个docx文件的OPCPackage对象
*/
for (int i = 0; i < length; i++) {
String doc = srcDocxs.get(i);
OPCPackage srcPackage = null;
try {
srcPackage = OPCPackage.open(doc);
} catch (Exception e) {
e.printStackTrace();
}
if(null != srcPackage){
opcpList.add(srcPackage);
}
}
int opcpSize = opcpList.size();
//获取的OPCPackage对象大于0时,执行合并操作
if(opcpSize > 0){
try {
dest = new FileOutputStream(destDocx);
XWPFDocument src1Document = new XWPFDocument(opcpList.get(0));
//XWPFParagraph p=src1Document.createParagraph();
//p.setFirstLineIndent(0);
//p.setPageBreak(false);
XWPFRun run1=src1Document.getLastParagraph().createRun();
run1.addBreak(BreakType.PAGE);
//CTBody src1Body = src1Document.getDocument().getBody();
//OPCPackage大于1的部分执行合并操作
if(opcpSize > 1){
for (int i = 1; i < opcpSize; i++) {
OPCPackage src2Package = opcpList.get(i);
XWPFDocument src2Document = new XWPFDocument(src2Package);
if(i!=opcpSize-1){//加上这一句,否则最后一页将多加一页空白页
//每部分换页
XWPFRun run2=src2Document.getLastParagraph().createRun();
run2.addBreak(BreakType.PAGE);
}
//CTBody src2Body = src2Document.getDocument().getBody();
appendBody(src1Document, src2Document);
}
}
//将合并的文档写入目标文件中
simpleNumberFooter(src1Document);
src1Document.write(dest);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally{
IOUtils.closeQuietly(dest);
}
}
}
/**
* 合并文档内容
* @param src 目标文档
* @param append 要合并的文档
* @throws Exception
*/
// private static void appendBody(CTBody src, CTBody append) throws Exception {
// XmlOptions optionsOuter = new XmlOptions();
// optionsOuter.setSaveOuter();
// String appendString = append.xmlText(optionsOuter);
// String srcString = src.xmlText();
// String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
// String mainPart = srcString.substring(srcString.indexOf(">") + 1,
// srcString.lastIndexOf("<"));
// String sufix = srcString.substring(srcString.lastIndexOf("<"));
// String addPart = appendString.substring(appendString.indexOf(">") + 1,
// appendString.lastIndexOf("<"));
// CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart
// + sufix);
// src.set(makeBody);
// }
public static void appendBody(XWPFDocument src, XWPFDocument append) throws Exception {
CTBody src1Body = src.getDocument().getBody();
CTBody src2Body = append.getDocument().getBody();
List<XWPFPictureData> allPictures = append.getAllPictures();
// 记录图片合并前及合并后的ID
Map<String, String> map = new HashMap();
for (XWPFPictureData picture : allPictures) {
String before = append.getRelationId(picture);
//将原文档中的图片加入到目标文档中
String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
map.put(before, after);
}
appendBody(src1Body, src2Body, map);
}
private static void appendBody(CTBody src, CTBody append, Map<String, String> map) throws Exception {
XmlOptions optionsOuter = new XmlOptions();
optionsOuter.setSaveOuter();
String appendString = append.xmlText(optionsOuter);
String srcString = src.xmlText();
String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
String sufix = srcString.substring(srcString.lastIndexOf("<"));
String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));
if (map != null && !map.isEmpty()) {
//对xml字符串中图片ID进行替换
for (Map.Entry<String, String> set : map.entrySet()) {
addPart = addPart.replace(set.getKey(), set.getValue());
}
}
//将两个文档的xml内容进行拼接
CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);
src.set(makeBody);
}
//页脚:显示页码信息
public static void simpleNumberFooter(XWPFDocument document) throws Exception {
CTP ctp = CTP.Factory.newInstance();
XWPFParagraph codePara = new XWPFParagraph(ctp, document);
XWPFRun r1 = codePara.createRun();
r1.setText("第");
r1.setFontSize(11);
CTRPr rpr = r1.getCTR().isSetRPr() ? r1.getCTR().getRPr() : r1.getCTR().addNewRPr();
CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts();
fonts.setAscii("宋体");
fonts.setEastAsia("宋体");
fonts.setHAnsi("宋体");
r1 = codePara.createRun();
CTFldChar fldChar = r1.getCTR().addNewFldChar();
fldChar.setFldCharType(STFldCharType.Enum.forString("begin"));
r1 = codePara.createRun();
CTText ctText = r1.getCTR().addNewInstrText();
ctText.setStringValue("PAGE \\* MERGEFORMAT");
ctText.setSpace(SpaceAttribute.Space.Enum.forString("preser