当前位置:首页 » JAVA技术教程

poi实现合并word文档,兼容图片的合并

2018-06-13 16:01 本站整理 浏览(2)

问题

       这两天一直在找java合并wrod的实现方法,找到了一个不错的文章,地址如下:http://www.cnblogs.com/tianyublog/p/6957953.html,copy代码试验了一翻,的确是可以实现合并的word的效果的,但是有一个致命的缺陷,word里的图片没办法正确的合并到目标文件。

 

解决

       研究了大半天,终于找到了解决方案。上面的合并word原理是,将word文档的内容转换为xml字符串,然后把要合并文档的xml进行拼接,生成新的文档。之所以图片无法合并是因为xml里只保存了图片的基本信息及ID,但没有保存图片的具体二进制数据,所以解决思路就是如何将文档中的图片合并到目标word之中。于是我对原来合并的代码进行了改造,实现了我想要的效果

 

直接上代码,不能说很巧妙,但是至少解决了问题。

 

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
/**
 * @author: Max
 *  
 * @Date: 2018/6/8
 *  
 * @name: 多个word文件合并,采用poi实现,兼容图片的迁移
 *
 * @Description: 
 */
public class MergeDoc {


    public static void main (String[] args) throws Exception {
        InputStream in1 = null;
        InputStream in2 = null;
        InputStream in3 = null;
        OPCPackage src1Package = null;
        OPCPackage src2Package = null;
        OPCPackage src3Package = null;
        OutputStream dest = new FileOutputStream("d:\\merge.docx");
        try {
            in1 = new FileInputStream("my/word/图片表格测试模板.docx");
            in2 = new FileInputStream("my/word/图片.docx");
            in3 = new FileInputStream("my/word/图片.docx");
            src1Package = OPCPackage.open(in1);
            src2Package = OPCPackage.open(in2);
            src3Package = OPCPackage.open(in3);
        } catch (Exception e) {
            e.printStackTrace();
        }

        XWPFDocument src1Document = new XWPFDocument(src1Package);
        XWPFDocument src2Document = new XWPFDocument(src2Package);
        XWPFDocument src3Document = new XWPFDocument(src2Package);

        appendBody(src1Document, src2Document);
        appendBody(src1Document, src3Document);

        src1Document.write(dest);


    }

    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);
    }
}