使用POI合并.docx文件内容工具类(不支持Word2003的.doc)

使用POI合并.docx文件内容工具类(不支持Word2003的.doc)

前言

需求是要把多个Word文件根据顺序合并为一个,找到poi有相关的方法可以做,这里整合一个工具类备用,依赖了poi-ooxml 3.17

依赖

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.17</version>
</dependency>

工具类代码

package com.jsw.jinzhi.oa.common.utils.word;

import com.google.api.client.util.Lists;
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;

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

/**
 * @program: xxxxxxxxxx
 * @description: 合并.docx文件工具类,不支持.doc文件
 * @author: Husky
 * @create: 2021-03-16
 **/
public class AppendDocx {

	/**
	 * 用于多个合并.docx文件,不支持.doc文件
	 * @param outputStream 导出文件输出流
	 * @param sourceFilePathList 需合并的文件路径集合
	 */
	public static void appendDocx(OutputStream outputStream, List<String> sourceFilePathList) {
		try {
			ArrayList<XWPFDocument> documentList = new ArrayList<>();
			XWPFDocument doc = null;
			for (String path : sourceFilePathList) {
				FileInputStream in = new FileInputStream(path);
				OPCPackage open = OPCPackage.open(in);
				XWPFDocument document = new XWPFDocument(open);
				documentList.add(document);
			}
			for (int i = 0; i < documentList.size(); i++) {
				doc = documentList.get(0);
				if (i != 0) {
					appendBody(doc, documentList.get(i));
				}
			}
			doc.write(outputStream);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 用于合并两个XWPFDocument对象
	 * @param src
	 * @param append
	 * @throws Exception
	 */
	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("<"));
//下面这部分可以去掉,我加上的原因是合并的时候,有时候出现打不开的情况,对照document.xml将某些标签去掉就可以正常打开了
		addPart = addPart.replaceAll("w14:paraId=\"[A-Za-z0-9]{1,10}\"", "");
		addPart = addPart.replaceAll("w14:textId=\"[A-Za-z0-9]{1,10}\"", "");
		addPart = addPart.replaceAll("w:rsidP=\"[A-Za-z0-9]{1,10}\"", "");
		addPart = addPart.replaceAll("w:rsidRPr=\"[A-Za-z0-9]{1,10}\"", "");
		addPart = addPart.replace("<w:headerReference r:id=\"rId8\" w:type=\"default\"/>","");
		addPart = addPart.replace("<w:footerReference r:id=\"rId9\" w:type=\"default\"/>","");
		addPart = addPart.replace("xsi:nil=\"true\"","");

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值