Explorar el Código

method to merge docx

dengjia hace 1 mes
padre
commit
109f282b74

+ 101 - 0
easier-report-biz/src/main/java/com/yaoyicloud/tools/DocxUtil.java

@@ -0,0 +1,101 @@
+package com.yaoyicloud.tools;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.xwpf.usermodel.IBodyElement;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFPicture;
+import org.apache.poi.xwpf.usermodel.XWPFPictureData;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
+import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture;
+
+import com.deepoove.poi.xwpf.XWPFStructuredDocumentTag;
+
+public final class DocxUtil {
+
+    public static void mergeDocx(XWPFDocument target, List<XWPFDocument> sources, String outputPath)
+        throws InvalidFormatException, FileNotFoundException, IOException {
+        mergeDocx(target, sources, outputPath, true);
+    }
+
+    /*
+     * 只更新target的内容,全局设定(fonts, styles, custom items)都使用target docx
+     */
+    public static void mergeDocx(XWPFDocument target, List<XWPFDocument> sources, String outputPath,
+        boolean clearTargetBody) throws InvalidFormatException, FileNotFoundException, IOException {
+        if (clearTargetBody) {
+            target.getDocument().unsetBody();
+            target.getDocument().addNewBody();
+        }
+        for (XWPFDocument source : sources) {
+            appendSourceContent(target, source);
+        }
+
+        try (FileOutputStream out = new FileOutputStream(outputPath)) {
+            target.write(out);
+            target.close();
+        }
+    }
+
+    private static void appendSourceContent(XWPFDocument target, XWPFDocument source) throws InvalidFormatException {
+        for (IBodyElement element : source.getBodyElements()) {
+            if (element instanceof XWPFParagraph) {
+                appendParagraph(target, (XWPFParagraph) element);
+            } else if (element instanceof XWPFTable) {
+                appendTable(target, (XWPFTable) element);
+            } else if (element instanceof XWPFStructuredDocumentTag) {
+                // todo: 目录,自定义标签等
+                continue;
+            }
+        }
+    }
+
+    private static void appendTable(XWPFDocument target, XWPFTable oldTable) {
+        XWPFTable newTable = target.createTable();
+        newTable.getCTTbl().set(oldTable.getCTTbl().copy());
+    }
+
+    private static void appendParagraph(XWPFDocument target, XWPFParagraph oldParagraph) throws InvalidFormatException {
+        // Remove additional blank page
+        // if (i == doc1.getBodyElements().size() - 1
+        // && oldParagraph.isPageBreak()
+        // && StrUtil.isBlank(oldParagraph.getText())) {
+        // continue;
+        // }
+
+        // Copy Picture
+        for (int i = 0; i < oldParagraph.getRuns().size(); i++) {
+            XWPFRun oldRun = oldParagraph.getRuns().get(i);
+
+            // Check if the run has embedded images
+            List<XWPFPicture> pictures = oldRun.getEmbeddedPictures();
+            for (int j = 0; j < pictures.size(); j++) {
+                XWPFPictureData picData = pictures.get(j).getPictureData();
+
+                // copy picture
+                // String fileName = picData.getFileName();
+                String newRelationId = target.addPictureData(picData.getData(), picData.getPictureType());
+
+                // update image rId to the new run
+                // 注意这里用新文件的rId更新了旧文件的Run,然后复制旧文件的XML到新文件
+                // 如果直接编辑新文件需要在复制XML后重新生成XWPFParagraph对象,才能正确反映更新的XML数据
+                CTPicture ctPic = pictures.get(j).getCTPicture();
+                CTBlipFillProperties bill = ctPic.getBlipFill();
+                CTBlip blip = bill.getBlip();
+                blip.setEmbed(newRelationId);
+            }
+        }
+        // Copy Xml content
+        XWPFParagraph newParagraph = target.createParagraph();
+        newParagraph.getCTP().set(oldParagraph.getCTP().copy());
+    }
+
+}

+ 33 - 0
easier-report-biz/src/test/java/com/yaoyicloud/render/test/TestDocxOperations.java

@@ -0,0 +1,33 @@
+package com.yaoyicloud.render.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.junit.Test;
+import com.yaoyicloud.tools.DocxUtil;
+
+public class TestDocxOperations {
+
+    @Test
+    public void testMergeDocx() throws IOException, InvalidFormatException {
+
+        FileInputStream streamMerge =
+            new FileInputStream(getClass().getClassLoader().getResource("docx/check_overview.docx").getFile());
+        FileInputStream stream1 =
+            new FileInputStream(getClass().getClassLoader().getResource("docx/service_provider_info.docx").getFile());
+        FileInputStream stream2 =
+            new FileInputStream(getClass().getClassLoader().getResource("docx/check_overview.docx").getFile());
+
+        DocxUtil.mergeDocx(new XWPFDocument(streamMerge),
+            List.of(new XWPFDocument(stream1), new XWPFDocument(stream2)),
+            "../temp/merged.docx");
+
+        assertTrue(true);
+    }
+
+}

BIN
easier-report-biz/src/test/resources/docx/check_overview.docx


BIN
easier-report-biz/src/test/resources/docx/service_provider_info.docx