废话不多说直接进入正题,首先分析生成pdf场景及生成内容,考虑复用性和维护难度是我们当前开发工作的第一要务!

下面是调研的几个主要方案:

一、itext 表单填充

使用方式:

  • itext表单填充方案是以pdf作为基础模板,通过在pdf中嵌入表单元素组件的方式(需要使用pdf编辑工具),最后由程序进行数据填充并另存为pdf结果。

方案优缺点:

  • 优点:代码优雅,生成后格式变化影响极小。
  • 缺点:原始模板变化需要重新生成pdf,重新编辑表单元素;不支持列表填充数据。
    【参考 接了个变态需求:生成 Excel + PDF 导出,用 Java 怎么实现?】

二、freemarker + doc4J 基于Word 生成 PDF

使用方式:

  • 首先将调整好格式的原始 word 导出为 XML 格式,编辑 XML 模板中需要填充元素的位置,最后由程序处理先由freemarker模板工具替换元素内容,再使用doc4J进行pdf导出。

方案优缺点:

  • 优点:通用性强,基于模板引擎功能强大。
  • 缺点:XML 格式的word真的有够复杂,想要在此模板上调整样式真的难上加难;由于系统不支持的原因需要导入中文字体库;doc4J 部分 doc 元素不支持(例如直线),导出格式差异较大。

这可能是由于doc4J迭代问题无法保证新元素的支持,导出结果比较奔放。。。

三、freemarker + aspose-words 导出PDF

使用方式:

  • 类似于 freemarker+doc4J 方式,同样需要编辑XML,导出格式相较doc4J而言有极大提升。

方案优缺点:

  • 优点:通用性强,基于模板引擎功能强大,无需手工管理字体(macOS),代码简单,导出格式与模板基本无差异。
  • 缺点:需要编辑 XML 模板;该方案不是免费版(当然有大神)。

受限于调试前期需要的修修改改,模板能给人整吐了,所以才有了下一个方案。

四、html + freemarker + itextpdf(html2pdf)

使用方式:

  • 翻译 word 为 html 页面(当然就是手写啦,还原度很重要!),html中模板元素插入(文字填充、列表循环 freemarker 支持的全都能写),最后由程序处理先由freemarker模板工具替换元素内容,再使用html2pdf进行pdf导出。

方案优缺点:

  • 优点:可维护性相较与上面方案都有极大提升(调试可见性,动态替换生效);通用性强,基于模板引擎功能强大;导出格式可控性较强;
  • 缺点:需要中文字体库。

这个方案是综合以上多次踩坑的结果,结果是显而易见的。

浅浅来一点代码,省的大家到处找

 <dependencies><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>html2pdf</artifactId><version>3.0.3</version></dependency><dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf-itext5</artifactId><version>9.0.3</version></dependency><dependency><groupId>binarta.oss</groupId><artifactId>groovy-template-enginex-freemarker</artifactId><version>0.1.3</version></dependency>
<dependencies>

个人以为自己的代码会自解释,就不贴太多注释了

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import com.google.common.collect.Lists;
import com.itextpdf.text.pdf.BaseFont;
import freemarker.cache.ByteArrayTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.SneakyThrows;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;public class HtmlToPdfUtil {private static final ByteArrayTemplateLoader TEMPLATE_LOADER = new ByteArrayTemplateLoader();// 导入需要字体库的位置哦;simsun 为 宋体public static final String FRONT_PATH = "/usr/share/fonts/simsun.ttc";/*** 看明白的话只用这个方法就够*/public static ByteArrayOutputStream htmlToPdf(String templateName, Supplier<byte[]> loadTemplateSupplier, Map<String, Object> modeViewMap) {String html = xmlFormat(templateName, loadTemplateSupplier, modeViewMap);return htmlToPdf(html);}@SneakyThrowspublic static ByteArrayOutputStream htmlToPdf(String htmlStr) {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();ITextRenderer renderer = new ITextRenderer();renderer.setDocumentFromString(htmlStr);ITextFontResolver resolver = renderer.getFontResolver();//添加字体,解决中文不显示的问题resolver.addFont(FRONT_PATH, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);renderer.layout();renderer.createPDF(outputStream);return outputStream;}public static String xmlFormat(String templateName, Supplier<byte[]> loadTemplateSupplier, Map<String, Object> modeViewMap) {if (Objects.isNull(TEMPLATE_LOADER.findTemplateSource(templateName))) {synchronized (TEMPLATE_LOADER) {if (Objects.isNull(TEMPLATE_LOADER.findTemplateSource(templateName))) {TEMPLATE_LOADER.putTemplate(templateName, loadTemplateSupplier.get());}}}return xmlFormat(templateName, modeViewMap);}@SneakyThrowspublic static String xmlFormat(String templateName, Map<String, Object> modeViewMap) {Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);// 指定FreeMarker模板文件的位置cfg.setTemplateLoader(TEMPLATE_LOADER);// 设置模板的编码格式cfg.setEncoding(Locale.CHINA, Charset.defaultCharset().name());// 获取模板文件 templateTemplate template = cfg.getTemplate(templateName, Charset.defaultCharset().name());StringWriter stringWriter = new StringWriter();BufferedWriter writer = new BufferedWriter(stringWriter);template.process(modeViewMap, writer);return stringWriter.toString();}}

解决这个问题的核心思路方案其实一直没变,变化的只是工具,一定要思路清晰!

探讨服务端自定义生成PDF的几种方案相关推荐

  1. 传奇服务器npc位置文件,传奇GEE引擎服务端自定义NPC示列工具

    传奇GEE引擎服务端自定义NPC示列工具 测试自定义NPC 配置文件:D:\MirServer\Mir200\Envir\CustomNPC 先在 Merchant.txt 中,设置一个 appr = ...

  2. ESP32学习笔记(30)——BLE GATT服务端自定义服务和特征

    一.简介 1.1 低功耗蓝牙(BLE)协议栈 链路层(LL) 控制设备的射频状态,有五个设备状态:待机.广播.扫描.初始化和连接. 广播 为广播数据包,而 扫描 则是监听广播. GAP通信中角色,中心 ...

  3. Python原生服务端签名生成请求订单信息「orderString」

    接口文档:https://docs.open.alipay.com/204/105465/ 一.签名方法示例:「代码中的私钥是随机生成无法使用,做示例用」 def sign(params):sort_ ...

  4. 移动端h5显示pdf的3种方法总结

    移动端显示h5我目前已经尝试了3种方法: 我使用的是vue的2.X版本 后端返回一个pdf的链接,然后前端直接使用location.href = 'http://www.XXX.com/test.pd ...

  5. java生成PDF的几种方法

    问题场景 总结一下用java生成PDF的方法: A.itext-PdfStamper pdfStamper(俗称抠模板) B.itext-Document document(正常代码撰写) C.wkh ...

  6. 如何将HTML表格转换成精美的PDF,几种方案比较

    作为开发人员,如何让PDF输出看起来更专业?大多数免费的在线PDF导出器实际上只是将HTML内容转换为PDF,而不进行任何额外的格式化,这会使数据难以阅读.如果你也能添加诸如页眉和页脚.页码或重复的表 ...

  7. java word插件开发_java生成word的几种方案

    1. Jacob是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁.使用Jacob自带的DLL动态链接库,并通过JNI的方式实现了在Java平台上对COM程序的调用 ...

  8. java word转pdf_java里实现Word转PDF的几种方案

    一.libreOffice 与openOffice类似,但比openOffice稳定. 优点:样式稳定 缺点:性能较差 调用方式:windows:1 2 3 4 5 6 7 8 9 10 11 12 ...

  9. 前端生成海报的 N 种方案和优劣对比

    点击上方关注 前端技术江湖,一起学习,天天进步 一.背景 工作中做了很多生成海报的功能,不同需求,不同场景,使用了几种方案,各有优劣.一直想要整理一下,但这个过程中的思考和遇到的问题没有记录下来,比如 ...

最新文章

  1. iOS 用自签名证书实现 HTTPS 请求的原理实例讲解
  2. Android应用程序键盘(Keyboard)消息处理机制分析(8)
  3. python的excel数据分析_excel VS python 谁更适合数据分析?
  4. 网易云网络服务研发实践—第1代云网络服务|网易云
  5. 利用XML实现通用WEB报表打印 卢彦
  6. 专业课程设计之客户与服务器程序的同步与通信机制的设计(一)项目介绍
  7. Filestream 使用简单步骤
  8. 火车票放票时间 潜规则
  9. c语言中自定义函数的流程图这么画,c语言流程图怎么画?
  10. shell 发送短信
  11. AWS RDS services
  12. 荣耀笔记本pro linux版本,荣耀MagicBook Pro锐龙版发布:首发锐龙7 3750H、还有Linux版...
  13. 为什么戏说php,戏说PHP的嵌套函数
  14. 数组索引必须为正整数或逻辑值。
  15. 浅谈android中手机联系人字母索引表的实现
  16. Chrome的HTTPS安全站点标志将于今年9月停用
  17. Vue Node vue-socket.io 联合使用 简易聊天程序
  18. Windows7中双击py文件运行程序
  19. 马云回国/ 文心一言员工跳槽工资翻倍/ 马斯克退出OpenAI内幕曝光…今日更多新鲜事在此...
  20. 洛谷 P5858 「SWTR-03」Golden Sword

热门文章

  1. 活动星投票国风正当红网络评选微信的投票方式线上免费投票
  2. php 化学泥浆,天水化学泥浆
  3. Java基于Redis实现附近的人(内附源码)
  4. 国家认证的Python技术工程师有什么能力要求?
  5. ja_charity模板研究_contin_1
  6. matplotlib红橙黄绿青蓝紫(含颜色大全)
  7. Vue.js框架学习,数据绑定
  8. 手把手教你Photoshop蒙版的使用(二)
  9. 关于联想拯救者Y7000/Y7000P电源显示0%的问题及解决办法
  10. [Android]APP中保持屏幕不自动灭屏的一种方法