在写代码中,肯定会有生成pdf的需求,试了很多方法都事倍功半,通常我们的做法不外乎以下几种:
1、先生成html,再通过相关类库把html转化为pdf,转化出来的pdf其实跟html的表现还有很大差距的,并且无法分页,比如首页一般是独立的一个封面,但是通过html生成,很难控制首页独立,大多数情况下第二页的内容会生成在首页,这样大大降低了体验。
2、使用pdf生成类库的api生成,当pdf页面简单的时候,我们还能处理过来,当很复杂的时候呢,比如 生成一个复杂的报告,这个报告可能有多达几十页,结构条目都很多的时候,用api生成真的就成了不可完成的任务了。
新思路
那么我们可以提供另外一种思路,我们通过word来生成pdf,有很多成熟的类库可以把word转化为pdf,并且基本上能在很大程度上保证生成的pdf和word表现一致。那么关键点就是如何生成word文档了。
生成word
生成word也有很多种方法,通常我们也是通过word相关类库的api来生成,比如 node下面的 officegen,java的POI,JXL,iText等都可以生成,那么同pdf一样,使用api来生成word文件一样会很复杂,也是一个不可完成的任务。
剑走偏锋、出奇制胜
面对这样的问题,我们能不能找到一个更为简便的方法进行生成呢?下面我们来看看如何利剑出鞘、直斩敌人要害,以彼之道还施彼身。
通过修改word文档的源码文件(document.xml)生成word文档
我们先写一个word模版文档,然后我们再通过代码去修改word文档中必要的地方,另存为一个新的word文档,那么这样我们就不用关注word文档生成时候的排版问题了,那岂不是事半功倍,思路来了,我们来看看怎么做。
word文档其实是一个zip压缩包,比如我们把report.docx的后缀改为report.zip,就可以通过解压工具把word文档解压出来,解压出来的文件内容如下:
进入到word目录,文件内容如下:
箭头所指的document.xml文件就是我们需要修改的文件,这个是word内容的描述文件,通过修改document.xml文件我们就可以根据word文件的格式来生成新的word文件
以nodejs的代码为例,其他语言代码同理,使用ejs模版类库,同理的你也可以选择其他的模版类库,比如java的freemarker。把document.xml转化为ejs模版。
它的部分document.xml内容如下:
红色箭头所指的是我们需要动态写入昵称的地方,我们把它替换为模版语言:
使用ejs模版类库,同理的你也可以选择其他的模版类库,比如java的freemarker。把document.xml转化为ejs模版。
其他地方修改同理,需要循环输出的地方也是一样。
我们的document.xml已经转化为ejs的模版了,那么我们就可以通过ejs来控制document.xml的生成,把生成后的document.xml覆盖掉word文档解压目录report下的word/document.xml文件,zip打包report文件夹为report.docx,这样word文档就生成了。
这样生成的word文档,用word打开后会显示错误,但是点击修复一般就可以进去了,也能看到修改多的内容。出现错误是因为打包zip可能丢失了一些非必要的信息,但是没关系,我们可以使用zip类库的api,通过流写入的方式去覆盖掉原document.xml就不会出现word打开后的错误,小伙伴们可以自行研究zip流写入
至此我们word文档已经生成完成,我们再调用word转pdf的类库,就能把word转化为pdf,效果能够趋近于完美展现。
这种方案页有一些需要注意的地方:
1、word文档中少用定位的形状框进行绝对定位,这样pdf生成的时候容易错乱。
2、word文档需要少定义个性化的样式,这样导致document.xml文档过大。
此处给小伙伴推荐一个客户端加密的密码管理的工具 https://ispass.cn
不怕密码丢失,不怕密码忘记,成百上千的密码随心管理
ok,已经大功告成了,那么下面来附上代码,nodejs的样例代码