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