java POI合并两个Word 包含图片,格式

找了好几个,都有瑕疵,要不图片问题,要不合并后打不开

总结两个问题:

1.图片问题,会重复替换,参考帖子:https://blog.csdn.net/c_940404/article/details/83996718

2.合并后打不开,参考帖子:https://www.cnblogs.com/himonkey/p/11110726.html

3.pot-ti 可以替换模板内容,进行word 追加

4.主要代码:(别人踩的坑,已标红,后面解释)

/**************合并 word start******************/
    public static int mergeDoc (String[] srcDocxs,String destDocx){  
        if(srcDocxs == null || srcDocxs.length<2){
            //请传入多个word路径
            return 1;
        }
        OutputStream dest = null;
            InputStream in1 = null;
            try {
                in1 = new FileInputStream(srcDocxs[0]);  
                dest = new FileOutputStream(destDocx);  
                OPCPackage src1Package = OPCPackage.open(in1);  
                XWPFDocument src1Document = new XWPFDocument(src1Package);  
                for (int i=1;i< srcDocxs.length;i++) {
                    InputStream item = new FileInputStream(srcDocxs[i]);   
                    OPCPackage src2Package = OPCPackage.open(item);  
                    XWPFDocument src2Document = new XWPFDocument(src2Package);  
                    appendBody(src1Document, src2Document);
                }
                src1Document.createNumbering();//操作_1
                src1Document.write(dest);
                return 0;
            } catch (Exception e) {
                logger.error("合并word失败:"+e.getMessage());
            }
            return 1;
    }
    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<String,String>();  
        for (XWPFPictureData picture : allPictures) {  
            String before = append.getRelationId(picture);  
            //将原文档中的图片加入到目标文档中  
            String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);  
            map.put(before, after.replace("rId", "myKey"));  //操作_2
        }  
  
        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 rgex = "<[\\s]*?w:sectPr[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?w:sectPr[\\s]*?>";
        appendString = appendString.replaceAll(rgex, "");
        String srcString = src.xmlText();
        String regex = regex(srcString,"w:sectPr"); //操作_4

        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());  
            } 
            addPart = addPart.replace("myKey", "rId");//操作_3
        }  
        //将两个文档的xml内容进行拼接  
        CTBody makeBody = CTBody.Factory.parse(prefix+mainPart+addPart+sufix);  
  
        src.set(makeBody);  
    }  
    
    /*************合并word end*****************/

/** 获取指定标签中的内容
      * @param xml
     * @param label
     * @return
     */
    public static String regex(String xml, String label) {
        String context = "";
        // 正则表达式
        String rgex = "<" + label + "[^>]*>((?:(?!<\\/" + label + ">)[\\s\\S])*)<\\/" + label + ">";
        Pattern pattern = Pattern.compile(rgex);// 匹配的模式
        Matcher m = pattern.matcher(xml);
        // 匹配的有多个
        List<String> list = new ArrayList<String>();
        while (m.find()) {
            int i = 1;
            list.add(m.group(i));
            i++;
        }
        if (list.size() > 0) {
            // 输出内容自己定义
            context = String.valueOf(list.size());
        }
        return context;
    }


 

4.调用:

public static void main(String[] args) {
        String[] srcDocxs = {"E:\\log\\test.docx","E:\\log\\testphoto.docx"};
        String destDocx = "E:\\log\\test_new.docx";
        mergeDoc(srcDocxs, destDocx);
    }

6.解释:操作_1 的意思是:给合成的word自动编号(应该是分页的意思),主要是因为 我在做 poi 的word转pdf功能时 报错--说的就是合成的word中没有numbering值;

操作_2和操作_3 是对应关系:此问题出现在 两个word 文档中都有多张图片时,方法会将 后面的文档中的图片 添加到 第1个文档的缓存中,会生成对应的 rId 值, 然后再对 字符串中的图片ID进行替换时,会出现 覆盖现象,

如: map中的值为:{rId4:rId8,rId5:rId9,rId6:rId10,rId7:rId11,rId8:rId12,rId9:rId13,}   然后 进行替换 的时候,会先将 rId4替换为rId8,然后依次执行, 但到 替换rId8时,就出现了问题,因为头一个 rId8是 替换后的,但在代码中replace 不会管你,会将两个rId8都替换为 rid12,这样就出现了问题,我的解决方法是先不用rId,用其他不易重复的值代替,在所有图片id替换完成后,再改回来,也可以在 替换那步 判断是不是替换最后一个,我没考虑这个,因为 字符串中有个replaceFirst,没有replaceLast 

7,解释: 操作_4意思:是 <w:sectPr> 标签的问题,然后在 POI 合并的时候检查一下 POI 将 Word 转为 xml 后 w:sectPr 标签情况(用正则表达式方法),合并三个 word 文档,结果输出 2 也就是说前两个文档合并后 w:sectPr 标签有两个。因为我输出的是目标模板合并前的 w:sectPr 标签情况。

解决:去掉追加word内容中的 w:sectPr 标签,确保合成的word中只有一个 w:sectPr 标签对

String rgex = "<[\\s]*?w:sectPr[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?w:sectPr[\\s]*?>"; appendString = appendString.replaceAll(rgex, "");

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值