1 packagecom.htsoft.oa.action.sjrh.tool;2
3 importjava.io.File;4 importjava.io.FileInputStream;5 importjava.io.FileOutputStream;6 importjava.io.IOException;7 importjava.io.InputStream;8 importjava.io.OutputStream;9 importjava.io.RandomAccessFile;10 importjava.nio.MappedByteBuffer;11 importjava.nio.channels.FileChannel;12 importjava.nio.channels.FileChannel.MapMode;13 importjava.text.SimpleDateFormat;14 importjava.util.ArrayList;15 importjava.util.Date;16 importjava.util.Iterator;17 importjava.util.List;18
19 importorg.apache.commons.io.IOUtils;20 importorg.docx4j.dml.wordprocessingDrawing.Inline;21 importorg.docx4j.jaxb.Context;22 importorg.docx4j.openpackaging.exceptions.Docx4JException;23 importorg.docx4j.openpackaging.packages.WordprocessingMLPackage;24 importorg.docx4j.openpackaging.parts.PartName;25 importorg.docx4j.openpackaging.parts.WordprocessingML.AlternativeFormatInputPart;26 importorg.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;27 importorg.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;28 importorg.docx4j.relationships.Relationship;29 importorg.docx4j.wml.Br;30 importorg.docx4j.wml.CTAltChunk;31 importorg.docx4j.wml.Drawing;32 importorg.docx4j.wml.ObjectFactory;33 importorg.docx4j.wml.P;34 importorg.docx4j.wml.R;35 importorg.docx4j.wml.STBrType;36
37 importcom.alibaba.fastjson.JSONObject;38 importcom.htsoft.oa.action.sjrh.pojo.MergeResult;39
40 public classWordMergeUtils {41 private static ObjectFactory factory = newObjectFactory();42
43 /**
44 * 合并docx45 *46 *@paramstreams47 * 要合并的word文件的输入流48 *@parampath49 * 合并后的文件的路径50 *@return
51 *@throwsDocx4JException52 *@throwsIOException53 */
54 public static File mergeDocx(final List streams, String path) throwsDocx4JException, IOException {55
56 WordprocessingMLPackage target = null;57 final File generated = newFile(path);58
59 int chunkId = 0;60 Iterator 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 = newFileOutputStream(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 returngenerated;91 } else{92 return null;93 }94 }95
96 //插入文档
97 private static void insertDocx(MainDocumentPart main, byte[] bytes, intchunkId) {98 try{99 AlternativeFormatInputPart afiPart = newAlternativeFormatInputPart(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 *@paramfile118 *@return
119 *@throwsDocx4JException120 *@throwsIOException121 */
122 public static File wordMLToWord(File file) throwsDocx4JException, IOException {123 WordprocessingMLPackage target =WordprocessingMLPackage.load(file);124 File temp = File.createTempFile(file.getName(), ".doc");125 target.save(temp);126 returntemp;127 }128
129 /**
130 * xml转docx,原文件不变,返回转换完成的word文件对象。131 *132 *@paramfile133 *@return
134 *@throwsDocx4JException135 *@throwsIOException136 */
137 public static File xmlToWord(File file) throwsDocx4JException, IOException {138 WordprocessingMLPackage target =WordprocessingMLPackage.load(file);139 File temp = File.createTempFile(file.getName(), ".doc");140 target.save(temp);141 returntemp;142 }143
144 /**
145 * 合并wordML文档146 *147 *@paramlist148 *@parampath149 *@throwsDocx4JException150 *@throwsIOException151 */
152 public static File mergeWordML(List list, String path) throwsDocx4JException, IOException {153 final List streams = new ArrayList();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(newFileInputStream(file));158 }159 returnWordMergeUtils.mergeDocx(streams, path);160 }161
162 /**
163 * 把文件转换成Byte[] Mapped File way MappedByteBuffer 可以在处理大文件时,提升性能164 *165 *@paramfilename166 *@return
167 *@throwsIOException168 */
169 public static byte[] fileToByteArray(String filename) throwsIOException {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 returnresult;183 } catch(IOException e) {184 e.printStackTrace();185 throwe;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 *@paramword202 * 需要编辑的文件203 *@paramimageList204 * 图片对象集合( 图片对象属性: url 图片文件路径 keyword 文档中的图片占位符 name 图片文件名 )205 *@throwsException206 * 不幸的createImageInline方法抛出一个异常(没有更多具体的异常类型)207 */
208 public static void addImageToPackage(File word, List imageList) throwsException {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 *@paramwordFilePath238 * 文件路径239 *@paramimageList240 * 图片对象集合( 图片对象属性: url 图片文件路径 keyword 文档中的图片占位符 name 图片文件名 )241 *@throwsException242 * 不幸的createImageInline方法抛出一个异常(没有更多具体的异常类型)243 */
244 public static void addImageToPackage(String wordFilePath, List imageList) throwsException {245 addImageToPackage(newFile(wordFilePath), imageList);246 }247
248 /**
249 * 创建一个对象工厂并用它创建一个段落和一个可运行块R. 然后将可运行块添加到段落中. 接下来创建一个图画并将其添加到可运行块R中. 最后我们将内联250 * 对象添加到图画中并返回段落对象.251 *252 *@paraminline253 * 包含图片的内联对象.254 *@return包含图片的段落255 */
256 private staticP 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 returnparagraph;265 }266
267 /**
268 * 文档结尾添加一个空白页269 *270 *@throwsDocx4JException271 */
272 public static void addPageBreak(File word) throwsDocx4JException {273
274 WordprocessingMLPackage wordMLPackage =WordprocessingMLPackage.load(word);275
276 MainDocumentPart documentPart =wordMLPackage.getMainDocumentPart();277
278 Br breakObj = newBr();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 *@throwsDocx4JException291 */
292 public static voidaddPageBreak(MainDocumentPart documentPart) {293 Br breakObj = newBr();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 *@throwsDocx4JException305 */
306 public static void addPageBreak(String wordFilePath) throwsDocx4JException {307 addPageBreak(newFile(wordFilePath));308 }309
310 /**
311 * 合并word文档 接口方法312 *313 *@paramsourceFiles待合并文件314 *@parammergedFileName合并后的文件名称315 *@throwsException316 */
317 public static MergeResult merge(String djxh, ListsourceFiles, 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 files = new ArrayList();327 for(String filePath : sourceFiles) {328 File file = newFile(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 = newFile(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 }