package com.fzzy.igds.utils; import com.aspose.words.Document; import com.aspose.words.License; import com.aspose.words.SaveFormat; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.config.ConfigureBuilder; import com.deepoove.poi.policy.HackLoopTableRenderPolicy; import com.fzzy.igds.data.ExportWordParam; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.file.FileUtils; import org.apache.commons.collections.CollectionUtils; import org.apache.poi.openxml4j.opc.OPCPackage; 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 org.springframework.http.MediaType; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Description 文档工具类,将数据源填充到模板并另存文件 * @Author CZT * @Date 2025/4/21 16:14 */ public class WordUtil { /** * 许可证字符串(可以放到resource下的xml文件中也可) */ private static final String LICENSE = "" + "" + "Aspose.Total for JavaAspose.Words for Java" + "Enterprise" + "20991231" + "20991231" + "8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7" + "" + "sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=" + ""; /** * 将数据源填充到模板中并另存:主表+子表(可只有列表) * * @param param 数据源 * @throws IOException */ public static void exportWord(ExportWordParam param) throws Exception { //渲染模板 HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy(); Configure config = null; ConfigureBuilder configureBuilder = Configure.newBuilder(); if(StringUtils.isNotEmpty(param.getListName1())){ configureBuilder.bind(param.getListName1(), policy); } if(StringUtils.isNotEmpty(param.getListName2())){ configureBuilder.bind(param.getListName2(), policy); } if(StringUtils.isNotEmpty(param.getListName3())){ configureBuilder.bind(param.getListName3(), policy); } if(StringUtils.isNotEmpty(param.getListName4())){ configureBuilder.bind(param.getListName4(), policy); } if(StringUtils.isNotEmpty(param.getListName5())){ configureBuilder.bind(param.getListName5(), policy); } config = configureBuilder.build(); XWPFTemplate template = XWPFTemplate.compile(param.getTemplatePath() + param.getTemplateName(), config).render(param.getDataMap()); //模板文件保存 FileOutputStream fos = new FileOutputStream(param.getSavePath() + param.getTemplateName()); template.write(fos); } /** * 将数据源填充到模板中并另存:主表+子表(可只有列表) * * @param param 数据源 * @throws IOException */ public static void exportMoreWord(ExportWordParam param) throws Exception { Integer index = 900; List wordList = new ArrayList<>(); for (Map dataMap : param.getDataList()) { //渲染模板 HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy(); Configure config = null; ConfigureBuilder configureBuilder = Configure.newBuilder(); if(StringUtils.isNotEmpty(param.getListName1())){ configureBuilder.bind(param.getListName1(), policy); } if(StringUtils.isNotEmpty(param.getListName2())){ configureBuilder.bind(param.getListName2(), policy); } if(StringUtils.isNotEmpty(param.getListName3())){ configureBuilder.bind(param.getListName3(), policy); } if(StringUtils.isNotEmpty(param.getListName4())){ configureBuilder.bind(param.getListName4(), policy); } if(StringUtils.isNotEmpty(param.getListName5())){ configureBuilder.bind(param.getListName5(), policy); } config = configureBuilder.build(); XWPFTemplate template = XWPFTemplate.compile(param.getTemplatePath() + param.getTemplateName(), config).render(dataMap); wordList.add(param.getSavePath() + index + "-" + param.getTemplateName()); //模板文件保存 FileOutputStream fos = new FileOutputStream(param.getSavePath() + index + "-" + param.getTemplateName()); template.write(fos); index ++; } //多个word合并 mergeWord(wordList, param.getSavePath(), param.getTemplateName()); } /** * 下载文档 * * @param filePath 文档路径 * @param fileName 文档名称 * @param response * @throws Exception */ public static void download(String filePath, String fileName, HttpServletResponse response) throws Exception { //下载 if (!FileUtils.checkAllowDownload(fileName)) { throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); } response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); FileUtils.setAttachmentResponseHeader(response, fileName); FileUtils.writeBytes(filePath + fileName, response.getOutputStream()); } /** * 设置 license 去除水印 */ private static void setLicense() { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(LICENSE.getBytes()); License license = new License(); try { license.setLicense(byteArrayInputStream); } catch (Exception e) { e.printStackTrace(); } } /** * word 转 pdf 生成至指定路径,pdf为空则上传至word同级目录 * * @param wordPath word文件路径 * @param pdfPath pdf文件路径 */ public static void wordConvertPdfFile(String wordPath, String pdfPath) { FileOutputStream fileOutputStream = null; try { setLicense(); File file = new File(pdfPath); fileOutputStream = new FileOutputStream(file); Document doc = new Document(wordPath); doc.save(fileOutputStream, SaveFormat.PDF); } catch (Exception e) { e.printStackTrace(); } finally { try { assert fileOutputStream != null; fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 获取 生成的 pdf 文件路径,默认与源文件同一目录 * * @param inputFilePath word文件 * @return 生成的 pdf 文件 */ public static String getPdfName(String inputFilePath) { return inputFilePath.replaceAll("."+ getPostfix(inputFilePath), ".pdf"); } public static String getPostfix(String inputFilePath) { return inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1); } /*-------------多个word合并到成1个word文档----------*/ public static void mergeWord(List wordList, String mergeWordPath, String mergeWordName) { List srcfile = new ArrayList<>(); File file = null; for (String word : wordList) { file = new File(word); srcfile.add(file); } try { ArrayList documentList = new ArrayList<>(); for (int i = 0; i < srcfile.size(); i++) { FileInputStream in = new FileInputStream(srcfile.get(i).getPath()); OPCPackage open = OPCPackage.open(in); XWPFDocument document = new XWPFDocument(open); documentList.add(document); } XWPFDocument doc = documentList.get(0); if (CollectionUtils.isEmpty(documentList)) { throw new RuntimeException("待合并的word文档list为空"); } int size = documentList.size(); if (size > 1) { for (int i = 1; i < size; i++) { // 从第二个word开始合并 XWPFDocument nextPageDoc = documentList.get(i); // 最后一页不需要设置分页符,设置分页符后容易换页,可以去掉 if (i != (size-1)) { nextPageDoc.createParagraph().setPageBreak(true); } appendBody(doc, nextPageDoc); } } new File(mergeWordPath + mergeWordName).delete(); OutputStream dest = new FileOutputStream(mergeWordPath + mergeWordName); doc.write(dest); } catch (Exception e) { e.printStackTrace(); } } public void aqscMergeDoc(String outPutPath, String mergeWord) { List srcfile = new ArrayList<>(); File file1 = new File(outPutPath); File file2 = new File(mergeWord); srcfile.add(file1); srcfile.add(file2); try { ArrayList documentList = new ArrayList<>(); for (int i = 0; i < srcfile.size(); i++) { FileInputStream in = new FileInputStream(srcfile.get(i).getPath()); OPCPackage open = OPCPackage.open(in); XWPFDocument document = new XWPFDocument(open); documentList.add(document); } XWPFDocument doc = documentList.get(0); if (CollectionUtils.isEmpty(documentList)) { throw new RuntimeException("待合并的word文档list为空"); } int size = documentList.size(); if (size > 1) { doc.createParagraph().setPageBreak(true); for (int i = 1; i < size; i++) { // 从第二个word开始合并 XWPFDocument nextPageDoc = documentList.get(i); // 最后一页不需要设置分页符 if (i != (size-1)) { nextPageDoc.createParagraph().setPageBreak(true); } appendBody(doc, nextPageDoc); } } new File(outPutPath).delete(); OutputStream dest = new FileOutputStream(outPutPath); doc.write(dest); } catch (Exception e) { e.printStackTrace(); } } public static void appendBody(XWPFDocument src, XWPFDocument append) throws Exception { CTBody src1Body = src.getDocument().getBody(); CTBody src2Body = append.getDocument().getBody(); List allPictures = append.getAllPictures(); // 记录图片合并前及合并后的ID Map map = new HashMap<>(); for (XWPFPictureData picture : allPictures) { String before = append.getRelationId(picture); // 将原文档中的图片加入到目标文档中 String after = src.addPictureData(picture.getData(), org.apache.poi.xwpf.usermodel.Document.PICTURE_TYPE_PNG); map.put(before, after); } appendBody(src1Body, src2Body, map); } private static void appendBody(CTBody src, CTBody append, Map 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 srcString = src.xmlText().replaceAll( "", "" ).replaceAll( "", "" ); String prefix = srcString.substring(0, srcString.indexOf(">")); String mainPart = srcString.substring(srcString.indexOf(">"), srcString.lastIndexOf("<")); String sufix = srcString.substring(srcString.lastIndexOf("<")); String addPart = appendString.substring(appendString.indexOf(">"), appendString.lastIndexOf("<")); if (map != null && !map.isEmpty()) { // 对xml字符串中图片ID进行替换 for (Map.Entry set : map.entrySet()) { addPart = addPart.replace(set.getKey(), set.getValue()); } } // 将两个文档的xml内容进行拼接 CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix); src.set(makeBody); } }