package org.jeecg.modules.utils;
import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.jeecg.common.api.dto.FileUploadVo;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.util.CommonUtils;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.springframework.core.io.ClassPathResource;
import org.w3c.dom.Node;
import java.io.*;
import java.util.List;
import java.util.Map;
/**
* Word文件处理工具类
*/
@Slf4j
public class WordUtils {
/**
* 处理Word文件 并 转换成pdf 保存
*
* @param dataMap 替换数据集
* @param uploadPath jeecg配置的文件路径
* @param wordPathName word模板文件路径
* @param uploadType 文件存储类型,local本地存储、oss等
* @return 业务保存的路径及文件名称
* @throws Exception
*/
public static Result<String> createDocAndParsePdf(Map<String, Object> dataMap, String uploadPath, String wordPathName, String uploadType, String bizPath, String pdfFileName) {
// 读取成文件流
InputStream inputStream;
try {
inputStream = CommonUtils.getInputStream(uploadType, uploadPath, wordPathName);
} catch (Exception e) {
return Result.error("文件未找到");
}
XWPFDocument doc = null;
// org.apache.poi.xwpf.usermodel.Document document = new XWPFDocument(fileInputStream); // TODO 后续做兼容
try {
//加载Word文档
doc = new XWPFDocument(inputStream);
// 替换word模板数据
replaceBookTag(doc, dataMap, uploadType, uploadPath);
//转换Word为pdf
String relativePath = wordParseToPdf(doc, uploadType, uploadPath, bizPath, pdfFileName);
//
return Result.OK("转换成功", relativePath);
} catch (Exception e) {
log.error("转换失败:{}", e.getMessage(), e);
return Result.error("转换失败", e.getMessage());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (doc != null) {
try {
doc.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
// 保存结果文件
// 是否能够直接使用流转换成pdf
/* File file = null;
try {
file = new File(saveFilePath);
if (file.exists()) {
file.delete();
} else {
//这说明目标文件的上级目录不存在,先新建所有的上级目录
file.getParentFile().mkdirs();
}
FileOutputStream fos = new FileOutputStream(file);
doc.write(fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} */
}
/**
* doc, uploadType, uploadPath, bizPath, pdfFileName
* word转换为pdf使用document 文档流
*/
public static String wordParseToPdf(XWPFDocument document, String uploadType, String uploadPath, String bizPath, String pdfFileName) throws Exception {
// 验证License 若不验证则转化出的pdf文档会有水印产生
if (!getLicense()) {
return null;
}
// String settings = FontSettings.getDefaultFontName();
ByteArrayOutputStream baos = null;
ByteArrayInputStream bais = null;
FileOutputStream os = null;
try {
// 直接把文档流转换成二进制的outputStream
baos = new ByteArrayOutputStream();
//文档写入流
document.write(baos);
//OutputStream写入InputStream二进制流 在Document 时使用
bais = new ByteArrayInputStream(baos.toByteArray());
if (CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)) {
String saveFilePath = uploadPath + SymbolConstant.SINGLE_SLASH + bizPath + SymbolConstant.SINGLE_SLASH + pdfFileName;
//文件夹不存在创建文件夹
File file = new File(saveFilePath);
if (!file.getParentFile().exists()) {
//这说明目标文件的上级目录不存在,先新建所有的上级目录
file.getParentFile().mkdirs();
}
// 创建保存pdf的文档流
os = new FileOutputStream(file);
// Address是将要被转化的word文档
Document doc = new Document(bais);
doc.save(os, SaveFormat.PDF);
return bizPath + SymbolConstant.SINGLE_SLASH + pdfFileName;
} else {
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
Document doc = new Document(bais);
doc.save(baos2, SaveFormat.PDF);
ByteArrayInputStream bais2 = new ByteArrayInputStream(baos2.toByteArray());
// 保存到oos 或则 mini云上去
// CommonUtils.upload(bais, bizPath, uploadType);
FileUploadVo fileUploadVo = CommonUtils.uploadByStream(uploadType, bais2, bizPath, pdfFileName, null, uploadPath);
bais2.close();
baos2.close();
return fileUploadVo.getRelativePath();
}
} catch (Exception e) {
// e.printStackTrace();
throw new RuntimeException(e);
} finally {
if (baos != null) {
baos.close();
}
if (bais != null) {
bais.close();
}
if (os != null) {
os.close();
}
}
}
/**
* 破解License
*
* @return
*/
public static boolean getLicense() throws Exception {
boolean result;
try {
// license.xml应放在..\WebRoot\WEB-INF\classes路径下
ClassPathResource classPathResource = new ClassPathResource("license.xml"); //模板文件
InputStream is = classPathResource.getInputStream();
License aposeLic = new License();
aposeLic.setLicense(is);
result = true;
} catch (Exception e) {
e.printStackTrace();
throw new Exception("Word转PDF失败,license获取失败");
}
return result;
}
/**
* 处理段落(根据书签的方式替换)
*/
public static void replaceBookTag(XWPFDocument document, Map<String, Object> bookTagMap, String uploadType, String uploadPath) throws Exception {
List<XWPFParagraph> paragraphList = document.getParagraphs();
List<XWPFTable> tables = document.getTables();
if (tables != null && tables.size() > 0) {
for (XWPFTable table : tables) {
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
bookParagraph(cell.getParagraphs(), bookTagMap, uploadType, uploadPath);
}
}
}
}
bookParagraph(paragraphList, bookTagMap, uploadType, uploadPath);
}
/**
* 处理书签段落
*
* @param paragraphList 段落集合
* @param bookTagMap 替换数据
* for (XWPFParagraph xwpfParagraph : paragraphList) {
* for (XWPFParagraph paragraph : paragraphList) {
* List<CTBookmark> bookmarks = paragraph.getCTP().getBookmarkStartList();
* for (CTBookmark bookmark : bookmarks) {
* String bookmarkName = bookmark.getName();
* if (bookmarkName.equals("your_bookmark_name")) {
* // 执行替换操作
* // 获取书签所在段落
* XWPFParagraph bookmarkParagraph = (XWPFParagraph) paragraph.getParent();
* // 获取书签所在单元格
* XWPFTableCell bookmarkCell = (XWPFTableCell) bookmarkParagraph.getParent();
* // 在单元格中插入新的内容
* bookmarkParagraph.removeRun(0);
* bookmarkParagraph.createRun().setText("Replacement Text");
* }
* }
* }
*/
public static void bookParagraph(List<XWPFParagraph> paragraphList, Map<String, Object> bookTagMap, String uploadType, String uploadPath) {
for (XWPFParagraph xwpfParagraph : paragraphList) {
CTP ctp = xwpfParagraph.getCTP();
for (int dwI = 0; dwI < ctp.sizeOfBookmarkStartArray(); dwI++) {
CTBookmark bookmark = ctp.getBookmarkStartArray(dwI);
if (bookTagMap.containsKey(bookmark.getName())) {
XWPFRun run = xwpfParagraph.createRun();
if (bookmark.getName().contains("img")) {
String fileName = bookTagMap.get(bookmark.getName())!=null?
bookTagMap.get(bookmark.getName()).toString() : null;
if (fileName!=null) {
// 读取文件并把文件写到word报告中
try (InputStream inputStream = CommonUtils.getInputStream(uploadType, uploadPath, fileName);) {
run.addPicture(inputStream, XWPFDocument.PICTURE_TYPE_PNG, fileName, Units.pixelToEMU(100), Units.pixelToEMU(50));
run.setText("");
} catch (IOException | InvalidFormatException e) {
throw new RuntimeException(e);
}
}
} else {
run.setText(bookTagMap.get(bookmark.getName()) != null ? bookTagMap.get(bookmark.getName()).toString() : "");
}
Node firstNode = bookmark.getDomNode();
Node nextNode = firstNode.getNextSibling();
while (nextNode != null) {
// 循环查找结束符
String nodeName = nextNode.getNodeName();
if (nodeName.equals("w:bookmarkEnd")) {
break;
}
// 删除中间的非结束节点,即删除原书签内容
Node delNode = nextNode;
nextNode = nextNode.getNextSibling();
ctp.getDomNode().removeChild(delNode);
}
if (nextNode == null) {
// 始终找不到结束标识的,就在书签前面添加
ctp.getDomNode().insertBefore(run.getCTR().getDomNode(), firstNode);
} else {
// 找到结束符,将新内容添加到结束符之前,即内容写入bookmark中间
ctp.getDomNode().insertBefore(run.getCTR().getDomNode(), nextNode);
}
}
}
}
}
/**
* word转pdf使用文件流 - 这方法需要先保存doc 再使用文件流转换
*
* @param wordFile
* @param saveFilePath
*/
public static void wordParseToPdf(File wordFile, String saveFilePath) throws Exception {
if (!getLicense()) { // 验证License 若不验证则转化出的pdf文档会有水印产生
return;
}
try {
// System.out.println(wordFile.getPath());
// long old = System.currentTimeMillis();
File file = new File(saveFilePath); // 新建一个空白pdf文档
if (!file.exists()) {
file.getParentFile().mkdirs();
}
FileOutputStream os = new FileOutputStream(file);
Document doc = new Document(wordFile.getPath()); // Address是将要被转化的word文档
doc.save(os, SaveFormat.PDF);// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF,
// EPUB, XPS, SWF 相互转换
// long now = System.currentTimeMillis();
// System.out.println("共耗时:" + ((now - old) / 1000.0) + "秒"); // 转化用时
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 处理段落 Runs 标签替换方式
*
* @param doc
* @param textMap
* @throws Exception
*/
public static void doParagraphs(XWPFDocument doc, Map<String, Object> textMap) throws Exception {
/**----------------------------暂时先不考虑动态生成表格、目前没需求;后续有需求后添加------------------------------------**/
List<XWPFParagraph> paragraphList = doc.getParagraphs();
List<XWPFTable> tables = doc.getTables();
if (tables != null && tables.size() > 0) {
for (XWPFTable table : tables) {
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
processParagraph(textMap, cell.getParagraphs());
}
}
}
}
processParagraph(textMap, paragraphList);
}
/**
* 处理段落
*
* @param textMap
* @param paragraphList
* @throws InvalidFormatException
* @throws IOException
*/
private static void processParagraph(Map<String, Object> textMap, List<XWPFParagraph> paragraphList) throws InvalidFormatException, IOException {
for (XWPFParagraph paragraph : paragraphList) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
//判断文本是否需要进行替换
if (checkText(text)) {
for (Map.Entry<String, Object> entry : textMap.entrySet()) {
// 匹配模板与替换值 格式{{key}} 可以优化只要键的形势 但是也可能出现分割的问题
String key = "{{" + entry.getKey() + "}}";
Object value = entry.getValue();
if (text.contains(key)) {
if (value instanceof String) { //文字替换
if (StringUtils.isNotEmpty((String) value)) {
run.setText((String) value, 0);
// text = text.replace(key, (String) value);
} else {
// text = null;
run.setText("", 0);
}
} else if (value instanceof InputStream) {
//图片替换 可能instanceof不能判断流
// Map picMap = (Map) value;
// InputStream fis = (InputStream) picMap.get(entry.getKey());
InputStream fis = (InputStream) value;
run.addPicture(fis, XWPFDocument.PICTURE_TYPE_PNG, entry.getKey(), Units.toEMU(100), Units.toEMU(80));
run.setText("", 0);
} else if (value == null) {
run.setText("", 0);
}
//优化,找到了就退出当前循环
break;
}
}
//替换模板原来位置
// run.setText(text, 0);
}
}
}
}
/**
* 检查是否是需要替换的数据
*
* @param text
* @return
*/
private static boolean checkText(String text) {
if (text == null || "".equals(text)) {
return false;
}
return text.contains("{{");
}
}
Java 使用word模板替换书签/标签
最新推荐文章于 2024-04-26 09:41:39 发布