package me.zhengjie.modules.system.util;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class WordUtil {
/**
* 根据模板生成新word文档
* 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
*
* @param inputUrl 模板存放地址
* @param outputUrl 新文档存放地址
* @param textMap 需要替换的信息集合
* @return 成功返回true, 失败返回false
*/
public static boolean changWord(String inputUrl, String outputUrl,
Map<String, Object> textMap) {
//模板转换默认成功
boolean changeFlag = true;
try {
//获取docx解析对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//解析替换文本段落对象
changeText(document, textMap);
//解析替换表格对象
changeTable(document, textMap);
//生成新的word
File file = new File(outputUrl);
FileOutputStream stream = new FileOutputStream(file);
document.write(stream);
stream.close();
} catch (IOException | InvalidFormatException e) {
e.printStackTrace();
changeFlag = false;
}
return changeFlag;
}
/**
* 根据模板生成新word文档
* 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
*前端直接弹出下载
* @param inputUrl 模板存放地址
* @param textMap 需要替换的信息集合
*/
public static void changWord2(String inputUrl,
Map<String, Object> textMap, HttpServletResponse response) {
try {
//获取docx解析对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//解析替换文本段落对象
changeText(document, textMap);
//解析替换表格对象
changeTable(document, textMap);
ByteArrayOutputStream baos = new ByteArrayOutputStream();//二进制OutputStream
document.write(baos);//文档写入流
ByteArrayInputStream in = new ByteArrayInputStream(baos.toByteArray());//OutputStream写入InputStream二进制流
BufferedInputStream bis = new BufferedInputStream(in);
ServletOutputStream outputStream = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(outputStream);
byte[] buff = new byte[8192];
int bytesRead;
while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
bos.write(buff, 0, bytesRead);
}
bis.close();
bos.close();
outputStream.flush();
outputStream.close();
} catch (IOException | InvalidFormatException e) {
e.printStackTrace();
}
}
/**
* 替换段落文本
*
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
private static void changeText(XWPFDocument document, Map<String, Object> textMap) throws IOException, InvalidFormatException {
//获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//判断此段落时候需要进行替换
String text = paragraph.getText();
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
changeValue(run, textMap);
}
}
}
/**
* 替换表格对象方法
*
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
private static void changeTable(XWPFDocument document, Map<String, Object> textMap) throws IOException, InvalidFormatException {
//获取表格对象集合
List<XWPFTable> tables = document.getTables();
for (XWPFTable table : tables) {
//只处理行数大于等于2的表格,且不循环表头
if (table.getRows().size() > 1) {
//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
List<XWPFTableRow> rows = table.getRows();
//遍历表格,并替换模板
eachTable(rows, textMap);
}
}
}
/**
* 遍历表格
*
* @param rows 表格行对象
* @param textMap 需要替换的信息集合
*/
private static void eachTable(List<XWPFTableRow> rows, Map<String, Object> textMap) throws IOException, InvalidFormatException {
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
//判断单元格是否需要替换
List<XWPFParagraph> paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
changeValue(run, textMap);
}
}
}
}
}
/**
* 匹配传入信息集合与模板
*
* @param run 模板需要替换的区域
* @param textMap 传入信息集合
* @return 模板需要替换区域信息集合对应值
*/
private static String changeValue(XWPFRun run, Map<String, Object> textMap) throws IOException, InvalidFormatException {
Set<Map.Entry<String, Object>> textSets = textMap.entrySet();
String value=run.toString();
for (Map.Entry<String, Object> textSet : textSets) {
//匹配模板与替换值 格式${key}
String key = "${" + textSet.getKey() + "}";
if (null!=value&&value.contains(key)) {
if(textSet.getValue() instanceof String){
value = String.valueOf(textSet.getValue());
run.setText(value, 0);
}else if(textSet.getValue() instanceof List){
value = value.replace(key, "");
List<Map<String,Object>> pic = (List) textSet.getValue();
for(Map<String,Object> imageList : pic) {
int format;
if(null!=imageList.get("img")&&!"".equals(imageList.get("img"))){
String[] imgFile=imageList.get("img").toString().split(";");
run.setText(imageList.get("name").toString());
for (int i=0;i<imgFile.length;i++){
if(imgFile[i].endsWith(".emf")) format = XWPFDocument.PICTURE_TYPE_EMF;
else if(imgFile[i].endsWith(".wmf")) format = XWPFDocument.PICTURE_TYPE_WMF;
else if(imgFile[i].endsWith(".pict")) format = XWPFDocument.PICTURE_TYPE_PICT;
else if(imgFile[i].endsWith(".jpeg") || imgFile[i].endsWith(".jpg")) format = XWPFDocument.PICTURE_TYPE_JPEG;
else if(imgFile[i].endsWith(".png")) format = XWPFDocument.PICTURE_TYPE_PNG;
else if(imgFile[i].endsWith(".dib")) format = XWPFDocument.PICTURE_TYPE_DIB;
else if(imgFile[i].endsWith(".gif")) format = XWPFDocument.PICTURE_TYPE_GIF;
else if(imgFile[i].endsWith(".tiff")) format = XWPFDocument.PICTURE_TYPE_TIFF;
else if(imgFile[i].endsWith(".eps")) format = XWPFDocument.PICTURE_TYPE_EPS;
else if(imgFile[i].endsWith(".bmp")) format = XWPFDocument.PICTURE_TYPE_BMP;
else if(imgFile[i].endsWith(".wpg")) format = XWPFDocument.PICTURE_TYPE_WPG;
else {
System.err.println("Unsupported picture: " + imgFile +
". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg");
continue;
}
run.addBreak();
run.addPicture(new FileInputStream(imgFile[i]), format, imgFile[i], Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels
run.addBreak();
// run.addBreak(BreakType.PAGE);
}
}
}
run.setText(value, 0);
}
}
}
return value;
}
}
前端
const blob = new Blob([res])
const fileName = '文章.docx'
const link = document.createElement('a')
link.download = fileName
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
document.body.appendChild(link)
link.click()
URL.revokeObjectURL(link.href)
document.body.removeChild(link)
记得设置responseType: ‘blob’