背景介绍
在实际的项目当中,有很多这样的场景,管理后台上传word模板文件(如协议、合同、通知书等),需要通过代码实现,将业务数据写入到word文件的不同位置,然后生成pdf文件并上传到文件服务器,提供用户下载或者预览的功能。比如:用户在某平台借款,生成的借款协议。
插件下载与安装
本文主要使用 Aspose.Words 实现word转pdf,通过替换word中的占位符实现文件中数据的更新。更多功能可以参考Aspose官方网站。
- 插件下载
链接:https://pan.baidu.com/s/1TbkczJNSN9X8LjV5L49ssw
提取码:vspw
官网下载地址:https://www.aspose.com/
- 插件安装
下载的jar包,可以直接放到java项目当中,也可以上传到maven私服追加pom引用。
效果展示
- 原word文件,有year、month、day、user_name四个占位符
- 转换后的PDF文件,占位符信息已更新,并追加了水印
代码逻辑
import com.aspose.words.Shape;
import com.aspose.words.*;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author luandy
* @create 2021/02/28 12:43
*/
public class TestWordsToPdf {
/** isMatchCase 是否区分大小写 */
private static final boolean IS_MATCH_CASE_TRUE = true;
/** isMatchWholeWord 是否全词匹配 */
private static final boolean IS_MATCH_WHOLE_WORD_TRUE = false;
/** 字体目录:mac系统,根据系统字体目录调整 */
private static final String FONT_FOLDER = "/System/Library/Fonts";
/**
* 测试方法
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String wordPath = "/Users/luandy/Downloads/模板_V1.0.docx";
String pdfPath = "/Users/luandy/Downloads/模板_V1.0." + System.currentTimeMillis() + ".pdf";
ConcurrentHashMap<String, String> dataMap = new ConcurrentHashMap();
dataMap.put("year", "2021");
dataMap.put("month", "2");
dataMap.put("day", "28");
dataMap.put("user_name", "我是八零后琐话,欢迎您的关注");
// word转换pdf
docToPdf(wordPath, pdfPath, dataMap);
}
/**
* word转pdf主方法
*
* @param wordPath
* @param pdfPath
* @param dataMap
* @return
* @throws Exception
*/
public static boolean docToPdf(String wordPath, String pdfPath, ConcurrentHashMap<String, String> dataMap) throws Exception {
// 验证License 若不验证则转化出的pdf文档会有水印产生
if (!isWordLicense()) {
System.out.println("License验证不通过...");
return false;
}
File pdfFile = null;
FileOutputStream pdfFos = null;
try {
long old = System.currentTimeMillis();
// 新建一个pdf文档
pdfFile = new File(pdfPath);
pdfFos = new FileOutputStream(pdfFile);
// 将要被转化的word文档
Document doc = new Document(wordPath);
// 字体设置
FontSettings.setFontsFolder(FONT_FOLDER + File.separator, true);
// Aspose.Words 使用Replace()对模板进行替换字符操作
replaceWordsKey(doc, dataMap);
// 为PDF追加水印
insertWaterMarkText(doc, "八零后琐话");
// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
doc.save(pdfFos, SaveFormat.PDF);
long now = System.currentTimeMillis();
System.out.println("共耗时:" + ((now - old) / 1000.0) + "秒");
} catch (Exception e) {
System.out.println("Word 转 Pdf 失败..." + e);
// 为了不生成空文件,出现异常时,删除pdf文件,以便重新生成
if (pdfFile != null) {
pdfFile.delete();
}
return false;
} finally {
if (pdfFos != null) {
pdfFos.close();
}
}
// 文件转换成功
return true;
}
/**
* 替换Word中的占位符
*
* @param doc
* @param dataMap
* @throws Exception
*/
private static void replaceWordsKey(Document doc, ConcurrentHashMap<String, String> dataMap) throws Exception {
for (Map.Entry<String, String> entry : dataMap.entrySet()) {
// 替换Word中的变量,longfor_year为word模板中的占位符,2021为替换的数据,isMatchCase 是否区分大小写,isMatchWholeWord 是否全词匹配
doc.getRange().replace(entry.getKey(), entry.getValue(), IS_MATCH_CASE_TRUE, IS_MATCH_WHOLE_WORD_TRUE);
}
}
/**
* 验证aspose.word组件是否授权:无授权的文件有水印和试用标记
*
* @return
*/
private static boolean isWordLicense() {
try {
// 避免文件遗漏
String licensexml = "<License>\n" + "<Data>\n" + "<Products>\n"
+ "<Product>Aspose.Total for Java</Product>\n" + "<Product>Aspose.Words for Java</Product>\n"
+ "</Products>\n" + "<EditionType>Enterprise</EditionType>\n"
+ "<SubscriptionExpiry>20991231</SubscriptionExpiry>\n"
+ "<LicenseExpiry>20991231</LicenseExpiry>\n"
+ "<SerialNumber>23dcc79f-44ec-4a23-be3a-03c1632404e9</SerialNumber>\n" + "</Data>\n"
+ "<Signature>\n"
+ "sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=\n"
+ "</Signature>\n" + "</License>";
InputStream inputStream = new ByteArrayInputStream(licensexml.getBytes());
com.aspose.words.License license = new com.aspose.words.License();
license.setLicense(inputStream);
} catch (Exception e) {
System.out.println("License验证异常..." + e);
return false;
}
return true;
}
/**
* 为PDF添加水印
*
* @param doc
* @param waterMarkText
* @throws Exception
*/
private static void insertWaterMarkText(Document doc, String waterMarkText) throws Exception {
Shape watermark = new Shape(doc, ShapeType.TEXT_PLAIN_TEXT);
// 水印内容
watermark.getTextPath().setText(waterMarkText);
// 水印字体
watermark.getTextPath().setFontFamily("宋体");
// 水印宽度
watermark.setWidth(600);
// 水印高度
watermark.setHeight(150);
// 旋转水印
watermark.setRotation(-60);
// 水印颜色
watermark.getFill().setColor(Color.lightGray);
watermark.setStrokeColor(Color.lightGray);
watermark.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
watermark.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
watermark.setWrapType(WrapType.NONE);
watermark.setVerticalAlignment(VerticalAlignment.CENTER);
watermark.setHorizontalAlignment(HorizontalAlignment.CENTER);
Paragraph watermarkPara = new Paragraph(doc);
watermarkPara.appendChild(watermark);
for (Section sect : doc.getSections()) {
insertWaterMarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_PRIMARY);
insertWaterMarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_FIRST);
insertWaterMarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_EVEN);
}
}
private static void insertWaterMarkIntoHeader(Paragraph waterMarkPara, Section sect, int headerType) throws Exception {
HeaderFooter header = sect.getHeadersFooters().getByHeaderFooterType(headerType);
if (header == null) {
header = new HeaderFooter(sect.getDocument(), headerType);
sect.getHeadersFooters().add(header);
}
header.appendChild(waterMarkPara.deepClone(true));
}
}