廢話不多說直接進入正題,首先分析生成pdf場景及生成內容,考慮復用性和維護難度是我們當前開發工作的第一要務!
下面是調研的幾個主要方案:
一、itext 表單填充
使用方式:
itext表單填充方案是以pdf作為基礎模板,通過在pdf中嵌入表單元素組件的方式(需要使用pdf編輯工具),最后由程序進行數據填充并另存為pdf結果。
方案優缺點:
優點:代碼優雅,生成后格式變化影響極小。
缺點:原始模板變化需要重新生成pdf,重新編輯表單元素;不支持列表填充數據。
基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
項目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
視頻教程:https://doc.iocoder.cn/video/
二、freemarker + doc4J 基于Word 生成 PDF
使用方式:
首先將調整好格式的原始 word 導出為 XML 格式,編輯 XML 模板中需要填充元素的位置,最后由程序處理先由freemarker模板工具替換元素內容,再使用doc4J進行pdf導出。
方案優缺點:
優點:通用性強,基于模板引擎功能強大。
缺點:XML 格式的word真的有夠復雜,想要在此模板上調整樣式真的難上加難;由于系統不支持的原因需要導入中文字體庫;doc4J 部分 doc 元素不支持(例如直線),導出格式差異較大。
這可能是由于doc4J迭代問題無法保證新元素的支持,導出結果比較奔放。。。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
三、freemarker + aspose-words 導出PDF
使用方式:
類似于 freemarker+doc4J 方式,同樣需要編輯XML,導出格式相較doc4J而言有極大提升。
方案優缺點:
優點:通用性強,基于模板引擎功能強大,無需手工管理字體(macOS),代碼簡單,導出格式與模板基本無差異。
缺點:需要編輯 XML 模板;該方案不是免費版(當然有大神)。
受限于調試前期需要的修修改改,模板能給人整吐了,所以才有了下一個方案。
四、html + freemarker + itextpdf(html2pdf)
使用方式:
翻譯 word 為 html 頁面(當然就是手寫啦,還原度很重要!),html中模板元素插入(文字填充、列表循環 freemarker 支持的全都能寫),最后由程序處理先由freemarker模板工具替換元素內容,再使用html2pdf進行pdf導出。
方案優缺點:
優點:可維護性相較與上面方案都有極大提升(調試可見性,動態替換生效);通用性強,基于模板引擎功能強大;導出格式可控性較強;
缺點:需要中文字體庫。
這個方案是綜合以上多次踩坑的結果,結果是顯而易見的。
淺淺來一點代碼,省的大家到處找
com.itextpdf itextpdf 5.5.13 com.itextpdf html2pdf 3.0.3 org.xhtmlrenderer flying-saucer-pdf-itext5 9.0.3 binarta.oss groovy-template-enginex-freemarker 0.1.3
個人以為自己的代碼會自解釋,就不貼太多注釋了
importcn.hutool.core.io.FileUtil; importcn.hutool.core.map.MapUtil; importcom.google.common.collect.Lists; importcom.itextpdf.text.pdf.BaseFont; importfreemarker.cache.ByteArrayTemplateLoader; importfreemarker.template.Configuration; importfreemarker.template.Template; importlombok.SneakyThrows; importorg.xhtmlrenderer.pdf.ITextFontResolver; importorg.xhtmlrenderer.pdf.ITextRenderer; importjava.io.BufferedWriter; importjava.io.ByteArrayOutputStream; importjava.io.File; importjava.io.StringWriter; importjava.nio.charset.Charset; importjava.nio.charset.StandardCharsets; importjava.util.List; importjava.util.Locale; importjava.util.Map; importjava.util.Objects; importjava.util.function.Supplier; publicclassHtmlToPdfUtil{ privatestaticfinalByteArrayTemplateLoaderTEMPLATE_LOADER=newByteArrayTemplateLoader(); //導入需要字體庫的位置哦;simsun 為宋體 publicstaticfinalStringFRONT_PATH="/usr/share/fonts/simsun.ttc"; /** *看明白的話只用這個方法就夠 */ publicstaticByteArrayOutputStreamhtmlToPdf(StringtemplateName,SupplierloadTemplateSupplier,Map modeViewMap){ Stringhtml=xmlFormat(templateName,loadTemplateSupplier,modeViewMap); returnhtmlToPdf(html); } @SneakyThrows publicstaticByteArrayOutputStreamhtmlToPdf(StringhtmlStr){ ByteArrayOutputStreamoutputStream=newByteArrayOutputStream(); ITextRendererrenderer=newITextRenderer(); renderer.setDocumentFromString(htmlStr); ITextFontResolverresolver=renderer.getFontResolver(); //添加字體,解決中文不顯示的問題 resolver.addFont(FRONT_PATH,BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED); renderer.layout(); renderer.createPDF(outputStream); returnoutputStream; } publicstaticStringxmlFormat(StringtemplateName,Supplier loadTemplateSupplier,Map modeViewMap){ if(Objects.isNull(TEMPLATE_LOADER.findTemplateSource(templateName))){ synchronized(TEMPLATE_LOADER){ if(Objects.isNull(TEMPLATE_LOADER.findTemplateSource(templateName))){ TEMPLATE_LOADER.putTemplate(templateName,loadTemplateSupplier.get()); } } } returnxmlFormat(templateName,modeViewMap); } @SneakyThrows publicstaticStringxmlFormat(StringtemplateName,Map modeViewMap){ Configurationcfg=newConfiguration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); //指定FreeMarker模板文件的位置 cfg.setTemplateLoader(TEMPLATE_LOADER); //設置模板的編碼格式 cfg.setEncoding(Locale.CHINA,Charset.defaultCharset().name()); //獲取模板文件template Templatetemplate=cfg.getTemplate(templateName,Charset.defaultCharset().name()); StringWriterstringWriter=newStringWriter(); BufferedWriterwriter=newBufferedWriter(stringWriter); template.process(modeViewMap,writer); returnstringWriter.toString(); } }
結
解決這個問題的核心思路方案其實一直沒變,變化的只是工具,一定要思路清晰!
審核編輯:劉清
-
XML
+關注
關注
0文章
188瀏覽量
33047 -
HTML
+關注
關注
0文章
277瀏覽量
34574
原文標題:服務端自定義生成PDF的幾種方案
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論