0%

PDF导出功能设计

背景

在公司从事CRM系统设计的时候,产品设计之初有个功能需求就是需要导出合同文件(PDF)以及提供预览功能。其中合同包括单次广告合同,DSP合同,框架合同以及认刊书等等,每种合同的内容和格式都不相同。

思考

无论什么合同,从主题内容上来看,都包括静态部分和动态部分;(所谓静态即内容针对与所有的合同都是一样的,而动态内容则需要不同的数据来渲染成不同的格式 )。为此,想到了dubbo官网中关于api与spi的分离的设计

技术上,选用的itext7的技术实现。 如果编码去写合同的cell肯定不现实,而且后期的可维护性和可拓展性太差。比如实时变更合同上的条款内容, 需要重新发版,代价高。所以选择html+freemarker+itext的实现方案。

其中渲染成pdf这个功能本身而言是和业务无关的。其中包含的实现方式

  • str -> pdf
  • html -> pdf
  • freemarker + model -> pdf

为了实现实时性的需求,需要让运营的同事维护合同模板然后从远程文件系统(fastdfs, ali-oss, tencent等)读取文件内容信息然后渲染成 pdf文件。
而一个pdf文件其实由多种渲染方式共同组成, 自然而然的想到了组合模式。为此,关于 PDF的API可以设计如下

api-render

实现

有了上述的思考作为铺垫之后, 真正到落地需要配合数据库,应用层的代码和第三方存储系统共同参与方能完成一个完整的pdf导出模块。

design

可以看出 SPI对应的是 Render的设计, API对应的是Builder的设计。而中间的CombinePolicy则是交付给运营人员配置和管理的。

总结

在一个简单的PDF导出功能设计和实现中,设计模式包含了策略模式,桥接模式,组合模式,模板方法模式和装饰器模式 。从后期的业务上实现了可扩展性设计。

实现细节

  • 每一种的合同导出的render可以设计单例的(无状态)以达到高性能的目的
  • 模板的flush的api的参数设计成OutputStream,方便后期的导出以及预览
  • 要释放pdf文件资源,避免内存溢出的问题。 (IO资源一定要关闭 )
  • 无论是ftl或者html文件都可以支持实时的更新和渲染,但是要加上缓存层(装饰器设计)
  • builder可以采用模板模式实现,避免业务逻辑冗余。

Gitalking ...