问题背景描述
我们在做项目的时候,可能会遇到这样的一个需求,根据业务数据,生成一份pdf文件,然后提供给用户下载查看。
生成pdf文件,可能会有很多种方式实现:
- 1.根据html模板,把数据填充到html模板,生成一份pdf文件
- 2.根据pdf模板,把数据填充到pdf模板,生成一份pdf文件
- 3.根据word模板,把数据填充到word模板,生成一份pdf文件
对比了这3种实现方式:
第1种实现方式,html的代码,会导致有些样式丢失,效果不好。(不太建议)
第2种实现方式,操作起来,很麻烦,需要编写大量的代码,最终的效果也不是很友好。(难度比较大,不太建议)
第3种实现方式,这种实现,是个人目前觉得比较好的一种方式,样式,实现也可以接受啦!!!
以上,仅代表个人观点,可能有不对的地方,别喷,或轻点喷!!!
那今天咋们着重的讨论一下第3种实现方式!!!^_^
word转pdf说明
目前,word转pdf,我们可以借助openoffice帮我们实现这个功能。
但凡,有个但是啦,毕竟你要借助openoffice,这毕竟是一个工具,那咋们就不得不部署运行这个程序,那这样得话,不得加重咋们后期服务器的部署和运维了嘛?
所以这里,咋们还是得想想看,有无其他简单的实现方式?
哈哈,那肯定是有的啦,我们可以通过纯代码的方式,实现word转pdf的功能!!!
下面看哥们操作喽!!!^_^
word转pdf实现
- word模板数据填充工具类
public class WordTemplateUtils {
private static Logger logger = LoggerFactory.getLogger(WordTemplateUtils.class);
/*
* 根据Word模板生成word文档
* @param uploadPath 文件夹路径
* @param writePath 生成word文件路径
* @param templatePath word模板路径
* @param contentMap 填充数据
*/
public static boolean writeWordByTemplate(String uploadPath, String writePath, String templatePath, Map<String, Object> contentMap) throws Exception {
//如果文件夹不存在,新建文件夹
File file = new File(uploadPath);
//如果路径不存在,新建
if (!file.exists() && !file.isDirectory()) {
file.mkdirs();
}
boolean result = false;
logger.info("---根据模板生成word文档");
XWPFDocument document = new XWPFDocument(new FileInputStream(templatePath));
if (document == null) {
logger.error("---模板文件不存在,tempPath:{}", templatePath);
return result;
}
InputStream is = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(writePath);
WordTemplateUtils.changeText(document, contentMap);
//生成新的word文档
document.write(fos);
result = true;
} catch (IOException e) {
logger.error("---输出word文档失败,原因:{}", e.getMessage());
result = false;
} finally {
if (is != null) {
is.close();
}
if (fos != null) {
fos.close();
}
}
return result;
}
/**
* 替换段落文本
*
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
private static void changeText(XWPFDocument document, Map<String, Object> textMap) {
//获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//判断此段落时候需要进行替换
String text = paragraph.getText();
System.out.println(text);
if (!text.equals("")) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String textR = run.getText(0);//读取的模板段落
if (StringUtils.isEmpty(textR)) {
continue;
}
String newTxetR = "";
//判断文本是否需要进行替换
// System.out.print(textR + ",");
for (Map.Entry<String, Object> entry : textMap.entrySet()) {
//匹配模板与替换值 格式${key}
String key = entry.getKey();
Object value = entry.getValue();
if (textR.contains(key)) {//
if (value instanceof String) { //文字替换
String inputText = value.toString();
if (inputText.contains("\n")) {//包含换行符
String[] lines = inputText.split("\n");
//newTxetR = textR.replace(key, lines[0]);
run.setText(lines[0].trim(), 0); // set first line into XWPFRun
for (int i = 1; i < lines.length; i++) {
// add break and insert new text
run.addBreak();//换行
run.addTab();//缩进
run.setText(lines[i].trim());
}
} else {
newTxetR = textR.replace(key, (String) value);
//替换模板原来位置
if (!newTxetR.equals("")) {
run.setText(newTxetR, 0);
}
}
} else if (value instanceof Map) { //图片替换
newTxetR = textR.replace(key, "");
//替换模板原来位置
if (!newTxetR.equals("")) {
run.setText(newTxetR, 0);
}
Map picMap = (Map) value;
int width = Integer.parseInt(picMap.get("width").toString());
int height = Integer.parseInt(picMap.get("height").toString());
int picType = getPictureType(picMap.get("type").toString());
FileInputStream fis = (FileInputStream) picMap.get("content");
try {
String blipId = document.addPictureData(fis, picType);
int id = document.getNextPicNameNumber(picType);
createPicture(id, blipId, width, height, run);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
/**
* @param id
* @param blipId
* @param width 宽
* @param height 高
* //* @param paragraph 段落
*/
private static void createPicture(int id, String blipId, int width, int height, XWPFRun xwpfRun) {
final int EMU = 9525;
width *= EMU;
height *= EMU;
CTInline inline = xwpfRun.getCTR().addNewDrawing().addNewInline();
//CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline(); //在遍历run列表的时候,创建新的run有可能会导致报错
String picXml = ""
+ "<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">"
+ " <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">"
+ " <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">"
+ " <pic:nvPicPr>" + " <pic:cNvPr id=""
+ id
+ "" name="Generated"/>"
+ " <pic:cNvPicPr/>"
+ " </pic:nvPicPr>"
+ " <pic:blipFill>"
+ " <a:blip r:embed=""
+ blipId
+ "" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>"
+ " <a:stretch>"
+ " <a:fillRect/>"
+ " </a:stretch>"
+ " </pic:blipFill>"
+ " <pic:spPr>"
+ " <a:xfrm>"
+ " <a:off x="0" y="0"/>"
+ " <a:ext cx=""
+ width
+ "" cy=""
+ height
+ ""/>"
+ " </a:xfrm>"
+ " <a:prstGeom prst="rect">"
+ " <a:avLst/>"
+ " </a:prstGeom>"
+ " </pic:spPr>"
+ " </pic:pic>"
+ " </a:graphicData>" + "</a:graphic>";
inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch (XmlException xe) {
xe.printStackTrace();
}
inline.set(xmlToken);
inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0);
CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height);
CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(id);
docPr.setName("docx_img_ " + id);
docPr.setDescr("docx Picture");
}
/**
* 根据图片类型,取得对应的图片类型代码
*
* @param picType
* @return int
*/
private static int getPictureType(String picType) {
int res = XWPFDocument.PICTURE_TYPE_PICT;
if (picType != null) {
if (picType.equalsIgnoreCase("png")) {
res = XWPFDocument.PICTURE_TYPE_PNG;
} else if (picType.equalsIgnoreCase("dib")) {
res = XWPFDocument.PICTURE_TYPE_DIB;
} else if (picType.equalsIgnoreCase("emf")) {
res = XWPFDocument.PICTURE_TYPE_EMF;
} else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
res = XWPFDocument.PICTURE_TYPE_JPEG;
} else if (picType.equalsIgnoreCase("wmf")) {
res = XWPFDocument.PICTURE_TYPE_WMF;
}
}
return res;
}
public static void main(String[] args) throws Exception {
Map<String, Object> contentMap = new HashMap<String, Object>();
//组装文本参数
contentMap.put("demo1", "示例1");
contentMap.put("demo2", "示例2");
String fileName = "demo.docx";
WordTemplateUtils.writeWordByTemplate("D:\word\file", ""D:\word\file\" + fileName,
"D:\word\template\template.docx", contentMap);
}
}
复制代码
word模板,可以是这样:
最终生成的效果如下:
- word转pdf工具类
/**
* Word或Excel 转Pdf 工具类
*
* 备注:需要引入 aspose-words-15.8.0-jdk16.jar / aspose-cells-8.5.2.jar
*/
public class PdfUtil {
private static boolean getLicense() {
boolean result = false;
try {
// license.xml应放在..\WebRoot\WEB-INF\classes路径下
InputStream is = PdfUtil.class.getClassLoader().getResourceAsStream("License.xml");
License aposeLic = new License();
aposeLic.setLicense(is);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* @param wordPath 需要被转换的word文件名
* @param pdfPath 转换之后pdf的文件
*/
public static void doc2pdf(String wordPath, String pdfPath) {
if (!getLicense()) { // 验证License 若不验证则转化出的pdf文档会有水印产生
return;
}
try {
long old = System.currentTimeMillis();
File file = new File(pdfPath); //新建一个pdf文档
FileOutputStream os = new FileOutputStream(file);
Document doc = new Document(wordPath); //Address是将要被转化的word文档
doc.save(os, com.aspose.words.SaveFormat.PDF);//全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
long now = System.currentTimeMillis();
os.close();
System.out.println("共耗时:" + ((now - old) / 1000.0) + "秒"); //转化用时
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param excelPath 需要被转换的excel全路径带文件名
* @param pdfPath 转换之后pdf的全路径带文件名
*/
public static void excel2pdf(String excelPath, String pdfPath) {
if (!getLicense()) { // 验证License 若不验证则转化出的pdf文档会有水印产生
return;
}
try {
long old = System.currentTimeMillis();
Workbook wb = new Workbook(excelPath);// 原始excel路径
FileOutputStream fileOS = new FileOutputStream(new File(pdfPath));
wb.save(fileOS, com.aspose.cells.SaveFormat.PDF);
fileOS.close();
long now = System.currentTimeMillis();
System.out.println("共耗时:" + ((now - old) / 1000.0) + "秒"); //转化用时
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//word 和excel 转为pdf
String fileName = "D:\word\file\demo.docx";
String pdfPath = "D:\word\pdf\demo..pdf";
doc2pdf(filePaths, pdfPath);
}
}
复制代码
这里提供一下:License.xml文件
<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>
好了,这个就是word转pdf的示例,也是比较简单啦!!!
好了,word转pdf,大概的实现,就是这样了!!!^_^
那我们就可以愉快的编写代码了!!!^_^
作者:llsydn
链接:https://juejin.cn/post/7087036463035973640
本文暂时没有评论,来添加一个吧(●'◡'●)