Hi,大家好,我是麦洛,最近项目中遇到了将html
页面导出为pdf
文件,现在将相关内容分享出来,希望帮到有需要的伙伴
需求场景
在招投标软件中,每个标段结束评标之后,都会生成评标报告
评标报告主要包含项目信息,标段信息,投标人信息,投标人报价,评标专家打分等情况,相对来说信息量还是比较大,假如我们要导出评标报告该如何做?
html
页面直接导出为pdf
- 后端组装页面,导出pdf
对比两种方式,很明显第一种方式优越性更好。即方便实现,又避免了由于页面的变动而需要改动导出功能代码的尴尬
方案调研
查阅了一些资料,目前市面上流行的解决方案主要有以下几种
-
wkhtmltopdf
-
iText
-
html2canvas+jsPDF
其中前面两种为后端实现方式,第三种为纯前端实现方式;
首先让我们来看一下wkhtmltopdf
从github上可以看出,wkhtmltopdf
的Star数量总共有11.1K,由此可见他的火爆程度。经过测验以后,我发现他的效果也是最好的。但是由于我们的项目采用了vue
,貌似它不支持vue
语法。所以我这边最后只能退而求其次,使用了其他技术来实现。
接着我们来看一下html2canvas
+jsPDF
的方式
这种方式是采用以上两个开源项目来实现。网上把它称作是一种曲线救国的方式。首先我们利用html2canvas
将HTML
网页保存成canvas
图片,然后我们在利用jsPDF
将canvas
图片生成PDF
文件。所以最终我们拿到的PDF
文件并不是真正意义上的PDF
文件,而是一张图片。这也导致我们无法编辑PDF
文件。而且质量也一般。
最后我们来看一看iText
itext7
好像是最新版本,这种方式适合于维护PDF
模板然后动态添加内容,有需要的小伙伴可以了解一下。
由于我们的项目前端是采用vue,经过测试以后,我发现wkhtmltopdf
好像并不支持Vue语法。也可能是我的使用方式不当。欢迎小伙伴指正。而且itext7更多用于需要去维护PDF模板的场景,并不适合我本次的需求。所以我最终使用html2canvas
+jsPDF
的方式来实现。
实战案例
html2canvas+jsPDF
现在,我们来看看html2canvas
+jsPDF
的实现方式
首先需要引入html2canvas
和jsPDF
的依赖文件。大家可以从官网下载。我也会在文末的资源包中放一份,方便大家使用。
//导出pdf文件[html2canvas&&jspdf结合方式]
getPdf: function () {
var that = this;
//影藏不需要的按钮
that.buttonShow = !that.buttonShow;
//不写会报错
window.jsPDF = window.jspdf.jsPDF;
//将body的内容保存为一个图片
var html2canvas1 = html2canvas(document.body, {
//图片跨域加载
useCORS: true,
onrendered: function (canvas) {
var contentWidth = canvas.width
var contentHeight = canvas.height
//一页pdf显示html页面生成的canvas高度
var pageHeight = contentWidth / 592.28 * 841.89
//未生成pdf的html页面高度
var leftHeight = contentHeight
//页面偏移
var position = 0
//a4纸的尺寸[595.28,841.89] html页面生成的canvas在pdf的宽高
var imgWidth = 595.28
var imgHeight = 592.28 / contentWidth * contentHeight
//获取图片的base64数据
var pageData = canvas.toDataURL('image/jpeg', 1.0)
//document.body.appendChild(canvas);
var PDF = new jsPDF('', 'pt', 'a4');
if (leftHeight < pageHeight) {
PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
} else {
//分页
while (leftHeight > 0) {
PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
if (leftHeight > 0) {
PDF.addPage()
}
}
}
//下载pdf
var save = PDF.save(that.sectionInfo.sectionName+"评标报告" + '.pdf');
//将pdf文件转为blob对象
var blob = save.output("blob");
//保存pdf文件到服务器
that.savePdf(blob)
},
});
},
由于这种方式是纯前端实现。如果我们想要把PDF保存一份到服务器,需要自己手动实现将文件上传到服务器。
wkhtmltopdf
接下来我们来看看wkhtmltopdf
这种方式如何实现?
如果我们要使用wkhtmltopdf
,需要安装官方提供的软件,大家可以在他的官网进行下载。
https://wkhtmltopdf.org/downloads.html
安装完成以后我们需要将安装路径配置的我们的工具类中。
public class WKHtmlToPdfUtil {
private static final String WINDOWS_URL = "D:/wkhtmltopdf/bin/wkhtmltopdf.exe";
private static final String LINUX_URL = "/opt/wkhtmltox/bin/wkhtmltopdf";
下面我们看一看如何使用,我们需要将我们导出的页面的路径拼接后作为参数传递进来。
String serverUrl = request.getScheme() + "://" + request.getServerName()+":"+request.getServerPort();
//组装需要导出页面的地址
serverUrl += request.getContextPath()+"/";
serverUrl += "evaluate/report/evaluateSectionReport?projectId="+projectId+"§ionId="+sectionId;
logger.info(serverUrl);
// 工具类调用
exportPdf(serverUrl,response);
/**
* @Title: 导出pdf到服务器
* @param
* @return
*/
public static void exportPdf(String serverUrl, HttpServletResponse response){
try {
ArrayList<String> urlList = new ArrayList<>();
urlList.add(serverUrl);
String folder = Global.getProfile() + "resultReports/";
// 判断此路径所有目录是否存在,不存在则创建
File file = new File(folder);
if(!file.exists() && !file.isDirectory()){
// mkdir()创建此抽象路径名指定的目录。如果父目录不存在则创建不成功
// mkdirs()创建此抽象路径名指定的目录,包括所有必需但不存在的父目录
file.mkdirs();
}
// 生成随机的附件路径(时间戳+4位随机数)
Random random = new Random();
String fileName = "milolee"+random.nextInt(10);
//资源包中,自己下载
WKHtmlToPdfUtil.htmlToPdf(urlList, folder+fileName+".pdf");
//资源包中,自己下载
// 生成成交通知书pdf文件到服务器之后下载到客户端
FileUtils.downLoadFile(folder,fileName+".pdf",response);
} catch (Exception e){
e.printStackTrace();
}
}
工具类WKHtmlToPdfUtil
和FileUtils
我放到资源包中,大家自行下载,太多了就不一一粘贴了
接下来我们看一看导出我的CSDN
首页的效果,还是很棒的
小结
本文主要介绍了如何将html页面导出为pdf文件,希望给遇到类似需求的小伙伴一点思路,没遇到的也可以收藏一下,以后说不定用得到。