注意:这里使用的word是docx格式的doc的不行
后端:
pom.xml
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
写的工具替换类
package com.xxx.common.utils.poi;
import com.xxx.common.utils.StringUtils;
import org.apache.poi.xwpf.usermodel.*;
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @author
* 替换word文字
*/
public class ReplaceWordUtil {
/**
* 替换表格内的文字
* @param data
* @param sourceFilePath
* @return
* @throws Exception
*/
public static XWPFDocument replaceInTable(Map<String, Object> data ,String sourceFilePath) throws Exception {
File file = new File(sourceFilePath);
if(!file.exists()){
throw new Exception("文件不存在!");
}
XWPFDocument document = new XWPFDocument(new FileInputStream(file));
replaceTableValue(document,data);
return document;
}
/**
* 替换表格内的文字
* @param document
* @param data
*/
public static void replaceTableValue(XWPFDocument document,Map<String, Object> data){
//重构map
buildMap(data);
Iterator<XWPFTable> tableList = document.getTablesIterator();
XWPFTable table;
List<XWPFTableRow> rows;
List<XWPFTableCell> cells;
while (tableList.hasNext()) {
table = tableList.next();
if (!checkText(table.getText())) {
continue;
}
rows = table.getRows();
for (XWPFTableRow row : rows) {
cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
if (!checkText(cell.getText())) {
continue;
}
List<XWPFParagraph> paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
replaceValue(paragraph, data);
}
}
}
}
}
/**
* 构造map,不再用外部替代了
* @param data
*/
public static void buildMap(Map<String, Object> data) {
Iterator<Map.Entry<String, Object>> iterator = data.entrySet().iterator();
Map<String, Object> newMap = new HashMap<>(data.size());
while (iterator.hasNext()) {
Map.Entry<String, Object> entry = iterator.next();
String newKey = "${" + entry.getKey() + "}";
newMap.put(newKey, entry.getValue());
iterator.remove();
}
data.putAll(newMap);
}
/**
* 检查文本中是否包含 ${
* @param text
* @return
*/
public static boolean checkText(String text) {
return text.indexOf("${") != -1;
}
/**
* 替换内容
* @param paragraph
* @param textMap
*/
public static void replaceValue(XWPFParagraph paragraph, Map<String, Object> textMap) {
XWPFRun run, nextRun;
String runsText;
List<XWPFRun> runs = paragraph.getRuns();
for (int i = 0; i < runs.size(); i++) {
run = runs.get(i);
runsText = run.getText(0);
if (StringUtils.isEmpty(runsText)) {
continue;
}
if (!checkText(runsText)) {
continue;
}
while (!runsText.contains("}")) {
nextRun = runs.get(i + 1);
runsText = runsText + nextRun.getText(0);
//删除该节点下的数据
paragraph.removeRun(i + 1);
}
if (textMap.containsKey(runsText)) {
run.setText(textMap.get(runsText).toString(), 0);
} else {
//如果匹配不到,则塞入空
run.setText("", 0);
}
}
}
}
word模板(注意一定要是docx的)
后端接口请求和处理:
@GetMapping("/getXXXXX")
public void getXXX(HttpServletResponse response){
try {
XXXX xxxx= sqService.getById(12013);
//这里转为map,去进行匹配
Map data = JSON.parseObject(JSON.toJSONString(xxxx), Map.class);
XWPFDocument xwpfDocument = ReplaceWordUtil.replaceInTable(data, 你模板的路径);
response.setContentType("application/msword");
response.setCharacterEncoding("utf-8");
xwpfDocument.write(response.getOutputStream());
}catch (Exception e){
System.out.println(e);
}
}
前端:
下载插件:
npm install docx-preview
npm install jszip
#需要打印的再下载这个
npm install vue-print-nb --save
接口请求:
这里主要就写几个页面用到的功能
// 页面
<template>
<div class="app-container">
//这个打印我就不多说了,需要打印的自行下载 v-print
<el-button v-print="'#printWord'"> 打 印 </el-button>
<div ref="word" id="printWord"></div>
</div>
</template>
引入axios
import axios from 'axios'
//从后台获取数据的方法
showWord(){
const docx = require("docx-preview");
axios.get(this.wordUrl, {responseType: "blob"}).then((res) => {
const blob = new Blob([res.data]);
docx.renderAsync(blob, this.$refs.word).then(this.print(this.$refs.word));
});
},
效果展示:
打印效果展示
--------------------------------------------------------------------------------------
因为前端展示的是转换为html后的数据,所以展示之前填充的数据位置都不准了,现修改为word转换为图片进行打印和展示
pom:
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc.free</artifactId>
<version>5.2.0</version>
</dependency>
代码:
@GetMapping("/getXXXX")
public String getXXX(XXX) {
try {
xxxxx byId = sqService.getById(12014);
Map data = JSON.parseObject(JSON.toJSONString(byId), Map.class);
XWPFDocument xwpfDocument = ReplaceWordUtil.replaceInTable(data, "模板路径");
//将word 写入流
ByteArrayOutputStream wordDocument = new ByteArrayOutputStream();
xwpfDocument.write(wordDocument);
//读取之前的流
InputStream inputStream = new ByteArrayInputStream(wordDocument.toByteArray());
Document document = new Document();
document.loadFromStream(inputStream,FileFormat.Docx);
//选择word的第一页进行转换为图片
BufferedImage bufferedImage = document.saveToImages(0, ImageType.Bitmap);
ByteArrayOutputStream imgOutStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "PNG", imgOutStream);
BASE64Encoder encoder = new sun.misc.BASE64Encoder();
String trim = encoder.encodeBuffer(imgOutStream.toByteArray()).trim();
String s = trim.replaceAll("\n", "").replaceAll("\r", "");
return "data:image/png;base64,"+s;
} catch (Exception e) {
System.out.println(e);
}
return null;
}
后端返回的是base64的图片,前端怎么展示就不用多说了吧
--------------------------------------------------------------------------------------------------
接下来看似完成了,但因为是word转成图片展示的,导致清晰度不够高,那怎么办?是使用图片清晰化?还是什么?
我的建议是将word转为pdf后文件存放在本地,通过配置negix映射使用浏览器访问打开并打印
@GetMapping("/getXXXX")
public String getXXX(XXX) {
try {
xxxxx byId = sqService.getById(12014);
Map data = JSON.parseObject(JSON.toJSONString(byId), Map.class);
XWPFDocument xwpfDocument = ReplaceWordUtil.replaceInTable(data, "模板路径");
String sendPdfName = UUID.randomUUID() +".pdf";
File file = new File(文件夹路径);
if(!file.isDirectory()){
file.mkdirs();
}
//直接将word转为pdf存储,并返回文件名
WordUtil.wordToPdf(xwpfDocument,xxxxConfig.getTempFilePath() + sendPdfName);
return sendPdfName;
} catch (Exception e) {
System.out.println(e);
}
return null;
}
package com.xxx.common.utils.poi;
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.documents.ImageType;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Base64;
/**
* word工具类
*/
public class WordUtil {
/**
* 将word 转为pdf 并返回pdf 的名字
* @param xwpfDocument
* @param path
* @return
* @throws Exception
*/
public static void wordToPdf(XWPFDocument xwpfDocument,String path) throws Exception{
ByteArrayOutputStream wordDocument = new ByteArrayOutputStream();
xwpfDocument.write(wordDocument);
InputStream inputStream = new ByteArrayInputStream(wordDocument.toByteArray());
com.spire.doc.Document document = new Document();
document.loadFromStream(inputStream, FileFormat.Docx);
document.saveToFile(path,FileFormat.PDF);
}
}
接着就是在negix内配置 你 xxxxConfig.getTempFilePath() 这个在服务器的路径了
location /tempFilePath/
{
alias D:/xxx/temp/xx/;
}
接着只需要在你前端代码里接收返回时,用浏览器打印就完事了,记得用google浏览器啊
xxxx(query).then(rep =>{
if (rep) {
window.open("/tempFilePath/" + rep, "_blank");
} else {
this.$message.error("打印出错!");
}
})
/--------------------------再补充一个word转pdf的方法----------------------------------------------------------------
下载maven
<dependency>
<groupId>com.luhuiguo</groupId>
<artifactId>aspose-words</artifactId>
<version>22.10</version>
</dependency>
新建license.xml 放在resources下
<License>
<Data>
<Products>
<Product>Aspose.Total for Java</Product>
<Product>Aspose.Words for Java</Product>
</Products>
<EditionType>Enterprise</EditionType>
<SubscriptionExpiry>20991231</SubscriptionExpiry>
<LicenseExpiry>20991231</LicenseExpiry>
<SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
</Data>
<Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>
</License>
import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
public class WordToPdf {
public static boolean getLicense() {
boolean result = false;
try {
InputStream is = WordToPdf.class.getClassLoader().getResourceAsStream("license.xml");
License aposeLic = new License();
aposeLic.setLicense(is);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* word转pdf
* @param inPath word路径
* @param outPath 输出路径
* @return
* @throws Exception
*/
public static boolean docToPdf(String inPath, String outPath) throws Exception {
// 验证License 若不验证则转化出的pdf文档会有水印产生
if (!getLicense()) {
return false;
}
try {
// 新建一个空白pdf文档
File file = new File(outPath);
FileOutputStream os = new FileOutputStream(file);
// Address是将要被转化的word文档
Document doc = new Document(inPath);
// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
doc.save(os, SaveFormat.PDF);
os.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}