java合并多个word 2007 文档 基于docx4j

参考文章:http://dh.swzhinan.com/post/185.html

引入的jar包

 1 <dependency>
 2             <groupId>org.docx4j</groupId>
 3             <artifactId>docx4j</artifactId>
 4             <version>6.0.1</version>
 5         </dependency>
 6         <dependency>
 7             <groupId>org.apache.commons</groupId>
 8             <artifactId>commons-compress</artifactId>
 9             <version>1.8.1</version>
10         </dependency>
11         <dependency>
12             <groupId>com.alibaba</groupId>
13             <artifactId>fastjson</artifactId>
14             <version>1.2.58</version>
15         </dependency>
16 
17         <dependency>
18             <groupId>org.apache.poi</groupId>
19             <artifactId>poi</artifactId>
20             <version>3.10-FINAL</version>
21         </dependency>
22         <dependency>
23             <groupId>org.apache.poi</groupId>
24             <artifactId>poi-ooxml</artifactId>
25             <version>3.10-FINAL</version>
26         </dependency>
27         <dependency>
28             <groupId>org.apache.xmlbeans</groupId>
29             <artifactId>xmlbeans</artifactId>
30             <version>2.5.0</version>
31         </dependency>
32         <dependency>
33             <groupId>org.apache.xmlgraphics</groupId>
34             <artifactId>xmlgraphics-commons</artifactId>
35             <version>1.3.1</version>
36         </dependency>

代码

  1 package com.htsoft.oa.action.sjrh.tool;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.FileOutputStream;
  6 import java.io.IOException;
  7 import java.io.InputStream;
  8 import java.io.OutputStream;
  9 import java.io.RandomAccessFile;
 10 import java.nio.MappedByteBuffer;
 11 import java.nio.channels.FileChannel;
 12 import java.nio.channels.FileChannel.MapMode;
 13 import java.text.SimpleDateFormat;
 14 import java.util.ArrayList;
 15 import java.util.Date;
 16 import java.util.Iterator;
 17 import java.util.List;
 18 
 19 import org.apache.commons.io.IOUtils;
 20 import org.docx4j.dml.wordprocessingDrawing.Inline;
 21 import org.docx4j.jaxb.Context;
 22 import org.docx4j.openpackaging.exceptions.Docx4JException;
 23 import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
 24 import org.docx4j.openpackaging.parts.PartName;
 25 import org.docx4j.openpackaging.parts.WordprocessingML.AlternativeFormatInputPart;
 26 import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
 27 import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
 28 import org.docx4j.relationships.Relationship;
 29 import org.docx4j.wml.Br;
 30 import org.docx4j.wml.CTAltChunk;
 31 import org.docx4j.wml.Drawing;
 32 import org.docx4j.wml.ObjectFactory;
 33 import org.docx4j.wml.P;
 34 import org.docx4j.wml.R;
 35 import org.docx4j.wml.STBrType;
 36 
 37 import com.alibaba.fastjson.JSONObject;
 38 import com.htsoft.oa.action.sjrh.pojo.MergeResult;
 39 
 40 public class WordMergeUtils {
 41     private static ObjectFactory factory = new ObjectFactory();
 42 
 43     /**
 44      * 合并docx
 45      * 
 46      * @param streams
 47      *            要合并的word文件的输入流
 48      * @param path
 49      *            合并后的文件的路径
 50      * @return
 51      * @throws Docx4JException
 52      * @throws IOException
 53      */
 54     public static File mergeDocx(final List<InputStream> streams, String path) throws Docx4JException, IOException {
 55 
 56         WordprocessingMLPackage target = null;
 57         final File generated = new File(path);
 58 
 59         int chunkId = 0;
 60         Iterator<InputStream> it = streams.iterator();
 61         while (it.hasNext()) {
 62             InputStream is = it.next();
 63             if (is != null) {
 64                 try {
 65                     if (target == null) {
 66                         // Copy first (master) document
 67                         OutputStream os = new FileOutputStream(generated);
 68                         os.write(IOUtils.toByteArray(is));
 69                         os.close();
 70 
 71                         target = WordprocessingMLPackage.load(generated);
 72                     } else {
 73                         MainDocumentPart documentPart = target.getMainDocumentPart();
 74 
 75 //                        addPageBreak(documentPart); // 另起一页,换页
 76 
 77                         insertDocx(documentPart, IOUtils.toByteArray(is), chunkId++);
 78                     }
 79                 } catch (Exception e) {
 80                     e.printStackTrace();
 81                 } finally {
 82                     is.close();
 83                 }
 84             }
 85         }
 86 
 87         if (target != null) {
 88             target.save(generated);
 89             // Docx4J.save(target, generated, Docx4J.FLAG_NONE);
 90             return generated;
 91         } else {
 92             return null;
 93         }
 94     }
 95 
 96     // 插入文档
 97     private static void insertDocx(MainDocumentPart main, byte[] bytes, int chunkId) {
 98         try {
 99             AlternativeFormatInputPart afiPart = new AlternativeFormatInputPart(
100                     new PartName("/part" + chunkId + ".docx"));
101             // afiPart.setContentType(new ContentType(CONTENT_TYPE));
102             afiPart.setBinaryData(bytes);
103             Relationship altChunkRel = main.addTargetPart(afiPart);
104 
105             CTAltChunk chunk = Context.getWmlObjectFactory().createCTAltChunk();
106             chunk.setId(altChunkRel.getId());
107 
108             main.addObject(chunk);
109         } catch (Exception e) {
110             e.printStackTrace();
111         }
112     }
113 
114     /**
115      * wordML转word,原文件不变,返回转换完成的word文件对象。
116      * 
117      * @param file
118      * @return
119      * @throws Docx4JException
120      * @throws IOException
121      */
122     public static File wordMLToWord(File file) throws Docx4JException, IOException {
123         WordprocessingMLPackage target = WordprocessingMLPackage.load(file);
124         File temp = File.createTempFile(file.getName(), ".doc");
125         target.save(temp);
126         return temp;
127     }
128 
129     /**
130      * xml转docx,原文件不变,返回转换完成的word文件对象。
131      * 
132      * @param file
133      * @return
134      * @throws Docx4JException
135      * @throws IOException
136      */
137     public static File xmlToWord(File file) throws Docx4JException, IOException {
138         WordprocessingMLPackage target = WordprocessingMLPackage.load(file);
139         File temp = File.createTempFile(file.getName(), ".doc");
140         target.save(temp);
141         return temp;
142     }
143 
144     /**
145      * 合并wordML文档
146      * 
147      * @param list
148      * @param path
149      * @throws Docx4JException
150      * @throws IOException
151      */
152     public static File mergeWordML(List<File> list, String path) throws Docx4JException, IOException {
153         final List<InputStream> streams = new ArrayList<InputStream>();
154         for (int i = 0; i < list.size(); i++) {
155             File file = list.get(i);
156             // file = WordMLUtil.wordMLToWord(file); // wordML转word
157             streams.add(new FileInputStream(file));
158         }
159         return WordMergeUtils.mergeDocx(streams, path);
160     }
161 
162     /**
163      * 把文件转换成Byte[] Mapped File way MappedByteBuffer 可以在处理大文件时,提升性能
164      * 
165      * @param filename
166      * @return
167      * @throws IOException
168      */
169     public static byte[] fileToByteArray(String filename) throws IOException {
170 
171         RandomAccessFile raf = null;
172         FileChannel fc = null;
173         try {
174             raf = new RandomAccessFile(filename, "r");
175             fc = raf.getChannel();
176             MappedByteBuffer byteBuffer = fc.map(MapMode.READ_ONLY, 0, fc.size()).load();
177             System.out.println(byteBuffer.isLoaded());
178             byte[] result = new byte[(int) fc.size()];
179             if (byteBuffer.remaining() > 0) {
180                 byteBuffer.get(result, 0, byteBuffer.remaining());
181             }
182             return result;
183         } catch (IOException e) {
184             e.printStackTrace();
185             throw e;
186         } finally {
187             try {
188                 fc.close();
189                 raf.close();
190             } catch (IOException e) {
191                 e.printStackTrace();
192             }
193         }
194     }
195 
196     /**
197      * Docx4j拥有一个由字节数组创建图片部件的工具方法, 随后将其添加到给定的包中. 为了能将图片添加 到一个段落中,
198      * 我们需要将图片转换成内联对象. 这也有一个方法, 方法需要文件名提示, 替换文本, 两个id标识符和一个是嵌入还是链接到的指示作为参数.
199      * 一个id用于文档中绘图对象不可见的属性, 另一个id用于图片本身不可见的绘制属性. 最后我们将内联 对象添加到段落中并将段落添加到包的主文档部件.
200      * 
201      * @param word
202      *            需要编辑的文件
203      * @param imageList
204      *            图片对象集合( 图片对象属性: url 图片文件路径 keyword 文档中的图片占位符 name 图片文件名 )
205      * @throws Exception
206      *             不幸的createImageInline方法抛出一个异常(没有更多具体的异常类型)
207      */
208     public static void addImageToPackage(File word, List<JSONObject> imageList) throws Exception {
209 
210         WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(word);
211 
212         for (int i = 0; i < imageList.size(); i++) {
213             JSONObject image = imageList.get(i);
214 
215             byte[] bytes = fileToByteArray(image.getString("url"));
216 
217             BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
218 
219             int docPrId = 1;
220             int cNvPrId = 2;
221             Inline inline = imagePart.createImageInline(image.getString("name"), image.getString("keyword"), docPrId,
222                     cNvPrId, false);
223 
224             P paragraph = addInlineImageToParagraph(inline);
225 
226             wordMLPackage.getMainDocumentPart().addObject(paragraph);
227         }
228 
229         wordMLPackage.save(word);
230     }
231 
232     /**
233      * Docx4j拥有一个由字节数组创建图片部件的工具方法, 随后将其添加到给定的包中. 为了能将图片添加 到一个段落中,
234      * 我们需要将图片转换成内联对象. 这也有一个方法, 方法需要文件名提示, 替换文本, 两个id标识符和一个是嵌入还是链接到的指示作为参数.
235      * 一个id用于文档中绘图对象不可见的属性, 另一个id用于图片本身不可见的绘制属性. 最后我们将内联 对象添加到段落中并将段落添加到包的主文档部件.
236      * 
237      * @param wordFilePath
238      *            文件路径
239      * @param imageList
240      *            图片对象集合( 图片对象属性: url 图片文件路径 keyword 文档中的图片占位符 name 图片文件名 )
241      * @throws Exception
242      *             不幸的createImageInline方法抛出一个异常(没有更多具体的异常类型)
243      */
244     public static void addImageToPackage(String wordFilePath, List<JSONObject> imageList) throws Exception {
245         addImageToPackage(new File(wordFilePath), imageList);
246     }
247 
248     /**
249      * 创建一个对象工厂并用它创建一个段落和一个可运行块R. 然后将可运行块添加到段落中. 接下来创建一个图画并将其添加到可运行块R中. 最后我们将内联
250      * 对象添加到图画中并返回段落对象.
251      * 
252      * @param inline
253      *            包含图片的内联对象.
254      * @return 包含图片的段落
255      */
256     private static P addInlineImageToParagraph(Inline inline) {
257         // 添加内联对象到一个段落中
258         P paragraph = factory.createP();
259         R run = factory.createR();
260         paragraph.getContent().add(run);
261         Drawing drawing = factory.createDrawing();
262         run.getContent().add(drawing);
263         drawing.getAnchorOrInline().add(inline);
264         return paragraph;
265     }
266 
267     /**
268      * 文档结尾添加一个空白页
269      * 
270      * @throws Docx4JException
271      */
272     public static void addPageBreak(File word) throws Docx4JException {
273 
274         WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(word);
275 
276         MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
277 
278         Br breakObj = new Br();
279         breakObj.setType(STBrType.PAGE);
280 
281         P paragraph = factory.createP();
282         paragraph.getContent().add(breakObj);
283         documentPart.getJaxbElement().getBody().getContent().add(paragraph);
284         wordMLPackage.save(word);
285     }
286 
287     /**
288      * 文档结尾添加一个空白页
289      * 
290      * @throws Docx4JException
291      */
292     public static void addPageBreak(MainDocumentPart documentPart) {
293         Br breakObj = new Br();
294         breakObj.setType(STBrType.PAGE);
295 
296         P paragraph = factory.createP();
297         paragraph.getContent().add(breakObj);
298         documentPart.getJaxbElement().getBody().getContent().add(paragraph);
299     }
300 
301     /**
302      * 文档结尾添加一个空白页
303      * 
304      * @throws Docx4JException
305      */
306     public static void addPageBreak(String wordFilePath) throws Docx4JException {
307         addPageBreak(new File(wordFilePath));
308     }
309 
310     /**
311      * 合并word文档 接口方法
312      * 
313      * @param sourceFiles待合并文件
314      * @param mergedFileName合并后的文件名称
315      * @throws Exception
316      */
317     public static MergeResult merge(String djxh, List<String> sourceFiles, String mergedFileName) {
318 
319         if (djxh == null || djxh.isEmpty()) {
320             return new MergeResult(-1, null, "登记序号为空!", null);
321         } else if (sourceFiles == null || sourceFiles.size() <= 0) {
322             return new MergeResult(-1, null, "待合并文件路径为空!", null);
323         }
324 
325         try {
326             List<File> files = new ArrayList<File>();
327             for (String filePath : sourceFiles) {
328                 File file = new File(filePath);
329                 files.add(file);
330             }
331 
332             // 保存基础路径
333             String path = "";
334             if ("1".equals(WordStaticFileds.open_Fixed_path)) {
335                 // 创建固定路径
336                 path = WordStaticFileds.create_word_path + "word/fixed/" + djxh;
337             } else {
338                 // 创建不固定路径
339                 path = WordStaticFileds.create_word_path + "word/notFixed/"
340                         + new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/" + djxh;
341             }
342 
343             if (mergedFileName == null || mergedFileName.isEmpty()) {
344                 if (files.size() > 0) {
345                     String oldName = files.get(0).getName();
346                     int lastIndexOf = oldName.lastIndexOf(".");
347                     if (lastIndexOf > 0) {
348                         mergedFileName = oldName.substring(0, lastIndexOf) + "-合并后.docx";
349                     }
350                 }
351             }
352 
353             File mergedfile = new File(path);
354 
355             if (!mergedfile.exists()) {
356                 mergedfile.mkdirs();
357             }
358 
359             String mergedFullPath = path + "/" + mergedFileName;
360             File mergeWordML = WordMergeUtils.mergeWordML(files, mergedFullPath);
361             
362             
363             return new MergeResult(0, mergeWordML, "合并word文件成功!", mergeWordML.getAbsolutePath());
364         } catch (Exception e) {
365             return new MergeResult(-1, null, "合并word文件出错!错误信息:" + e.getMessage(), null);
366         }
367 
368     }
369 }

 

posted @ 2019-11-28 14:13  dirgo  阅读(1966)  评论(0编辑  收藏  举报