教你两招,轻松搞定html页面导出为pdf文件

Hi,大家好,我是麦洛,最近项目中遇到了将html页面导出为pdf文件,现在将相关内容分享出来,希望帮到有需要的伙伴

需求场景

在招投标软件中,每个标段结束评标之后,都会生成评标报告

评标报告主要包含项目信息,标段信息,投标人信息,投标人报价,评标专家打分等情况,相对来说信息量还是比较大,假如我们要导出评标报告该如何做?

  • html页面直接导出为pdf
  • 后端组装页面,导出pdf

对比两种方式,很明显第一种方式优越性更好。即方便实现,又避免了由于页面的变动而需要改动导出功能代码的尴尬

方案调研

查阅了一些资料,目前市面上流行的解决方案主要有以下几种

首先让我们来看一下wkhtmltopdf

从github上可以看出,wkhtmltopdf的Star数量总共有11.1K,由此可见他的火爆程度。经过测验以后,我发现他的效果也是最好的。但是由于我们的项目采用了vue,貌似它不支持vue语法。所以我这边最后只能退而求其次,使用了其他技术来实现。

接着我们来看一下html2canvas+jsPDF的方式

这种方式是采用以上两个开源项目来实现。网上把它称作是一种曲线救国的方式。首先我们利用html2canvasHTML网页保存成canvas图片,然后我们在利用jsPDFcanvas图片生成PDF文件。所以最终我们拿到的PDF文件并不是真正意义上的PDF文件,而是一张图片。这也导致我们无法编辑PDF文件。而且质量也一般。

最后我们来看一看iText

itext7好像是最新版本,这种方式适合于维护PDF模板然后动态添加内容,有需要的小伙伴可以了解一下。

由于我们的项目前端是采用vue,经过测试以后,我发现wkhtmltopdf好像并不支持Vue语法。也可能是我的使用方式不当。欢迎小伙伴指正。而且itext7更多用于需要去维护PDF模板的场景,并不适合我本次的需求。所以我最终使用html2canvas+jsPDF的方式来实现。微信搜一搜"爱写Bug的麦洛",关注我,不定期会搞一些送书活动,和粉丝互动

实战案例

html2canvas+jsPDF

现在,我们来看看html2canvas+jsPDF的实现方式

首先需要引入html2canvasjsPDF的依赖文件。大家可以从官网下载。我也会在文末的资源包中放一份,方便大家使用。

1 //导出pdf文件[html2canvas&&jspdf结合方式] 2 getPdf: function () { 3 var that = this; 4 //影藏不需要的按钮 5 that.buttonShow = !that.buttonShow; 6 //不写会报错 7 window.jsPDF = window.jspdf.jsPDF; 8 //将body的内容保存为一个图片 9 var html2canvas1 = html2canvas(document.body, { 10 //图片跨域加载 11 useCORS: true, 12 onrendered: function (canvas) { 13 var contentWidth = canvas.width 14 var contentHeight = canvas.height 15 //一页pdf显示html页面生成的canvas高度 16 var pageHeight = contentWidth / 592.28 * 841.89 17 //未生成pdf的html页面高度 18 var leftHeight = contentHeight 19 //页面偏移 20 var position = 0 21 //a4纸的尺寸[595.28,841.89] html页面生成的canvas在pdf的宽高 22 var imgWidth = 595.28 23 var imgHeight = 592.28 / contentWidth * contentHeight 24 //获取图片的base64数据 25 var pageData = canvas.toDataURL('image/jpeg', 1.0) 26 //document.body.appendChild(canvas); 27 var PDF = new jsPDF('', 'pt', 'a4'); 28 if (leftHeight < pageHeight) { 29 PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight) 30 } else { 31 //分页 32 while (leftHeight > 0) { 33 PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight) 34 leftHeight -= pageHeight 35 position -= 841.89 36 if (leftHeight > 0) { 37 PDF.addPage() 38 } 39 } 40 } 41 //下载pdf 42 var save = PDF.save(that.sectionInfo.sectionName+"评标报告" + '.pdf'); 43 //将pdf文件转为blob对象 44 var blob = save.output("blob"); 45 //保存pdf文件到服务器 46 that.savePdf(blob) 47 }, 48 }); 49 },

由于这种方式是纯前端实现。如果我们想要把PDF保存一份到服务器,需要自己手动实现将文件上传到服务器。

wkhtmltopdf

接下来我们来看看wkhtmltopdf这种方式如何实现?

如果我们要使用wkhtmltopdf,需要安装官方提供的软件,大家可以在他的官网进行下载。

https://wkhtmltopdf.org/downloads.html

安装完成以后我们需要将安装路径配置的我们的工具类中。

1public class WKHtmlToPdfUtil { 2 private static final String WINDOWS_URL = "D:/wkhtmltopdf/bin/wkhtmltopdf.exe"; 3 private static final String LINUX_URL = "/opt/wkhtmltox/bin/wkhtmltopdf";

下面我们看一看如何使用,我们需要将我们导出的页面的路径拼接后作为参数传递进来。

1 String serverUrl = request.getScheme() + "://" + request.getServerName()+":"+request.getServerPort(); 2 //组装需要导出页面的地址 3 serverUrl += request.getContextPath()+"/"; 4 serverUrl += "evaluate/report/evaluateSectionReport?projectId="+projectId+"&sectionId="+sectionId; 5 logger.info(serverUrl); 6 // 工具类调用 7 exportPdf(serverUrl,response);
1 /** 2 * @Title: 导出pdf到服务器 3 * @param 4 * @return 5 */ 6 public static void exportPdf(String serverUrl, HttpServletResponse response){ 7 try { 8 ArrayList<String> urlList = new ArrayList<>(); 9 urlList.add(serverUrl); 10 String folder = Global.getProfile() + "resultReports/"; 11 // 判断此路径所有目录是否存在,不存在则创建 12 File file = new File(folder); 13 if(!file.exists() && !file.isDirectory()){ 14 // mkdir()创建此抽象路径名指定的目录。如果父目录不存在则创建不成功 15 // mkdirs()创建此抽象路径名指定的目录,包括所有必需但不存在的父目录 16 file.mkdirs(); 17 } 18 // 生成随机的附件路径(时间戳+4位随机数) 19 Random random = new Random(); 20 String fileName = "milolee"+random.nextInt(10); 21 //资源包中,自己下载 22 WKHtmlToPdfUtil.htmlToPdf(urlList, folder+fileName+".pdf"); 23 //资源包中,自己下载 24 // 生成成交通知书pdf文件到服务器之后下载到客户端 25 FileUtils.downLoadFile(folder,fileName+".pdf",response); 26 27 } catch (Exception e){ 28 e.printStackTrace(); 29 } 30 }

工具类WKHtmlToPdfUtilFileUtils我放到资源包中,大家自行下载,太多了就不一一粘贴了

接下来我们看一看导出我的CSDN首页的效果,还是很棒的

小结

本文主要介绍了如何将html页面导出为pdf文件,希望给遇到类似需求的小伙伴一点思路,没遇到的也可以收藏一下,以后说不定用得到。

由于本文设计到的代码比较多,我会打包上传到csdn,大家可以自行下载

下载地址 : https://download.csdn.net/download/Milogenius/18562697

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Twitter的分布式自增ID算法snowflake (Java版)

概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移