当前位置: 首页 > news >正文

Java通过Html(ftl模板)生成PDF实战, 可支持商用

Java通过Html(freemarker模板)生成PDF实战, 可支持商用

技术架构

springboot + freemarker + [pdfbox] + flying-saucer-pdf

生成流程:

  1. freemarker: 根据数据填充ftl模板文件,得到包含有效数据的html文件(包含页眉页脚页码的处理,和解决中文渲染等问题)。
  2. flying-saucer-pdf: 将html转换成PDF文件。
  3. pdfbox: 操作PDF文件,完成加解密等操作。

依赖包

<!-- springboot版本, 2.2.x也是支持的 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>3.3.0</version>
</dependency>
<!-- load freemarker template file --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.30</version></dependency>
<!-- convert html to pdf --><dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf</artifactId><version>9.4.1</version></dependency><dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-core</artifactId><version>9.4.1</version></dependency><!-- operate pdf, such as encypt/decypt,不做加解密可不引用 --><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.24</version></dependency><!-- encrypt/decrypt zip --><dependency><groupId>net.lingala.zip4j</groupId><artifactId>zip4j</artifactId><version>2.11.5</version></dependency>
PS:网上很多文章使用 itext5/7来生成PDF的,用于个人学习或者开源项目确实没问题,但是不方便用于公司商业项目,因为itext是基于AGPL 的开源协议,商用是需要收费的,当然贵司愿意付费也是okay的。

1. 准备PDF的模板文件(freemarker文件)

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><title>PDF Demo Title</title><style>@page {size: A4;margin: 35mm 10mm 23mm 10mm;@top-center {content: element(headerTop);}@bottom-center {content: element(footerBottom);}}#pagenumber:before {content: counter(page);}#pagecount:before {content: counter(pages);}.headerTop {position: running(headerTop);color: white;}.footerBottom {color: #777E90;position: running(footerBottom);margin-top: 10mm;}* {padding: 0;margin: 0;}html,body {/*优先加载 Poppins英文字体,无法渲染则使用PingFang中文字体*/font-family: Poppins-Medium, PingFang, sans-serif;margin: 0 auto;}.content {color: #23262F;font-size: 8px;padding: 0 0;margin-top: 0;}.size16 {font-size: 16px;}.size12 {font-size: 12px;}.size10 {font-size: 10px;}.size8 {font-size: 8px;}.lineHeight18 {line-height: 18px;}.weight600 {font-weight: 600;}.weight500 {font-weight: 500;}.padding18 {padding: 18px;}.marginBottom8 {margin-bottom: 8px;}.marginLeft6 {margin-left: 6px;}.marginLeft24 {margin-left: 24px;}.marginLeft16 {margin-left: 16px;}.marginLeft13 {margin-left: 13px;}.marginLeft4 {margin-left: 4px;}.marginTop4 {margin-top: 4px;}.marginTop8 {margin-top: 8px;}.width140 {width: 140px;}.widthFull {width: 100%;}.heightFull {height: 100%;}.textAlignCenter {text-align: center;}.inlineCenter {display: inline-block;vertical-align: top;}.backGray {background-color: #F7F7F7;}.backBlue {background-color: #0E59F0;}.border {border: 1px solid #E5E5E5;}.colorBlue {color: #6E9BF6;}.colorDark {color: #777E90;}.colorBlack {color: #23262F;}.colorBottomLine {background-color: #6E9BF6;}.colorGray {color: #838CA4;}.table {border-spacing: 0;/*跨页表格标题*/-fs-table-paginate: paginate;}.table>thead>tr>th,.table>tbody>tr>td {padding: 16px 4px;text-align: left;word-break: break-all;word-wrap: break-word;white-space: normal;page-break-inside: avoid;page-break-after: auto;}.table>thead>tr>th {color: #838CA4;font-weight: 400;size: 12px;}.positionAbsolute {position: absolute;}.rightBottom8 {top: 80px;right: 30px;}.height8 {height: 8px;}.height6 {height: 6px;}.height16 {height: 16px;}.right0 {right: 0;}.lineGary {height: 1px;background-color: #E5E5E5;}</style>
</head><body>
<!-- 页眉 -->
<div class="headerTop"><img class="widthFull" style="margin-left: -1px" width="716px"src="data:image/jpeg;base64,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" /><div class="positionAbsolute rightBottom8 size12 weight500">${headerDate}</div>
</div><!-- 页脚 -->
<div class="footerBottom"><div class="height6 colorBottomLine"></div><div class="marginTop8 size10"><div class="inlineCenter">footer name<span class="marginLeft4 colorBlack"><![CDATA[${footerName}]]></span></div><!-- 页码 --><div class="inlineCenter colorBlack positionAbsolute right0"><span id="pagenumber"></span>/<span id="pagecount"></span></div></div>
</div><div class="content"><!-- 用户信息 --><div class="border padding18"><div class="colorBlue marginBottom8 weight500 size16"><![CDATA[${userName}]]></div><div class=""><span>Account Name</span><span class="colorBlue marginLeft6 weight500"><![CDATA[${accountName}]]></span><span class="marginLeft24">Account ID</span><span class="colorBlue marginLeft6 weight500"><![CDATA[${accountId}]]></span></div></div><div class="height8"></div><!-- 表格 --><section style="display: ${display}"><div class="height16"></div><div class=""><span class="colorBlack size16 weight600 marginLeft4 inlineCenter">Deposit</span></div><div class="marginTop8 weight500 colorBlack size10">Deposit History</div><div class="height16"></div><div class="lineGary"></div><div class="marginTop8"><table class="widthFull table"><thead><tr class="backGray"><th>Currency</th><th>Request ID</th><th>Bank Name</th><th>Bank Number</th><th>Amount</th><th>Time</th></tr></thead><tbody><#if list?? && (list?size> 0)><#list list as detail><tr><td>${detail.tokenCode}</td><td>${detail.orderNo}</td><td><#if detail.bankName??><![CDATA[${detail.bankName}]]><#else>-</#if></td><td><#if detail.bankNumber??><#-- 处理特殊字符的渲染 --><![CDATA[${detail.bankNumber}]]><#else>-</#if></td><td><#if detail.qty??>${detail.qty}<#else>-</#if></td><td><#if detail.updateTime??>${detail.updateTime}<#else>-</#if></td></tr></#list></#if></tbody></table></div><div class="height16"></div><div class="lineGary"></div></section>
</div>
</body>
</html>
freemarker模板注意事项:
  1. 图片需要通过base64的方式加载,直接加载图片路径可能无法渲染
  2. 字体名称需要和Java代码中加载的字体名称保持一致,中文无法渲染可能是没有设置别名
  3. 替换的变量,如果有null值需要在模板中判断
  4. 如果填充的变量中存在特殊字符,通过<![CDATA[${变量名}]]> 方式设置
  5. 部分高级的CSS样式或者标签可能不支持
  6. 页眉页脚采用running的方式处理

2. Java Code

2.1 FreeMarkerUtils

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Map;@Slf4j
public class FreeMarkerUtils {private static Template getTemplate(String templateFileName) {Configuration configuration = new Configuration(Configuration.VERSION_2_3_29);Template template = null;try {configuration.setObjectWrapper(new DefaultObjectWrapper());//设置编码格式configuration.setDefaultEncoding("UTF-8");//模板文件configuration.setClassForTemplateLoading(FreeMarkerUtils.class, "/templates");template = configuration.getTemplate(templateFileName + ".ftl", StandardCharsets.UTF_8.toString());} catch (IOException e) {e.printStackTrace();log.error("get template file failed, fileName:{}", templateFileName);}return template;}public static String generateHtmlStr(Map<String, Object> variables, String templateFileName) {Template template = getTemplate(templateFileName);StringWriter stringWriter = new StringWriter();template.setEncoding("UTF-8");try (BufferedWriter writer = new BufferedWriter(stringWriter)) {template.process(variables, writer);String htmlStr = stringWriter.toString();writer.flush();return htmlStr;} catch (TemplateException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}}/*** 删除xml无法识别的非法字符* @param content* @return*/public static String removeIllegalChar(String content) {return content.replaceAll("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "");}
}

2.2 PdfTest Code


import com.janche.pdf.utils.FileUtil;
import com.janche.pdf.utils.FreeMarkerUtils;
import com.janche.pdf.vo.PdfVo;
import com.lowagie.text.pdf.BaseFont;
import freemarker.cache.ClassTemplateLoader;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;/*** @Description:* @Auther: lirong* @Date: 2024/04/16*/
@Slf4j
public class PdfTest {public static void main(String[] args) {ITextRenderer renderer = new ITextRenderer();try {addPdfFont(renderer);String htmlStr = FreeMarkerUtils.generateHtmlStr(loadPdfData(), "pdfTemplate");renderer.setDocumentFromString(FreeMarkerUtils.removeIllegalChar(htmlStr));renderer.layout();} catch (IOException e) {throw new RuntimeException(e);}File pdfFile = new File("output/demo.pdf");File encryptPdfFile = new File("output/demo_encrypt.pdf");File zipFile = new File("output/demo.zip");try (OutputStream os = new FileOutputStream(pdfFile)) {renderer.createPDF(os);// encrypt pdf, if needn't encrypt pdf file, can remove pdfBox dependencyPDDocument document = PDDocument.load(pdfFile);StandardProtectionPolicy policy = new StandardProtectionPolicy("123456", "1234", new AccessPermission());policy.setEncryptionKeyLength(128);policy.setPermissions(new AccessPermission());document.protect(policy);document.save(encryptPdfFile);document.close();} catch (Exception e) {throw new RuntimeException(e);}log.info("PDF file generated successfully!");}private static void addPdfFont(ITextRenderer renderer) throws IOException {// add English fontClassTemplateLoader classTemplateLoader = new ClassTemplateLoader(FreeMarkerUtils.class, "/static/font");String enFontPath = classTemplateLoader.getBasePackagePath() + "Poppins-Medium.ttf";ITextFontResolver fontResolver = renderer.getFontResolver();// the first font needn't set aliasfontResolver.addFont(enFontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);// add Chinese font, the second font must set aliasString chFontPath = classTemplateLoader.getBasePackagePath() + "PingFang-Regular.ttf";fontResolver.addFont(chFontPath, "PingFang", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, null);}public static Map<String, Object> loadPdfData() {Map<String, Object> data = new HashMap<>();// 启用data.put("display", "block");// 隐藏
//        data.put("display", "none");data.put("footerName", "footer-龍");data.put("userName", "龍年發财");data.put("accountName", "Jackson-龍");data.put("accountId", "234324");LocalDateTime now = LocalDateTime.now();DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");data.put("headerDate", now.format(dateFormatter));ArrayList<PdfVo> tableList = new ArrayList<>();IntStream.range(1, 20).forEach(i -> {LocalDateTime dateTime = now.plusDays(i);PdfVo pdfVo = PdfVo.builder().tokenCode("USD" + i).bankName("HK Bank" + i).bankNumber("&23**94&" + i).qty(BigDecimal.TEN.add(new BigDecimal(i))).orderNo("ab123445" + i).updateTime(dateTime.format(dateFormatter)).build();tableList.add(pdfVo);});data.put("list", tableList);return data;}
}
PS:
  1. 关于中文字体不显示的问题: 一般是字体未正确加载,或者读取时字体名称不正确,完全不需要去更改什么源码class文件,高版本的flying-saucer-pdf 早已支持。
  2. 加载多个字体时,后面的字体需要设置别名,ftl模板中也需要使用设置的别名。
字体文件:(可在文章底部的github项目中获取)
  1. PingFang-Regular.ttf 中文字体
  2. Poppins-Medium.ttf 英文字体

3. PDF展示

在这里插入图片描述

Github源码下载:https://github.com/Janche/springboot-html2pdf-demo

相关文章:

  • 从零学会【分镜头意识】拍摄思维
  • 一个与 WSL2 建立远程的简单方法
  • 基于朴素贝叶斯算法的新闻类型预测,django框架开发,前端bootstrap,有爬虫有数据库
  • 数字认证携手华为鸿蒙生态,升级智慧办公新体验
  • 【Qt】探索Qt绘图世界:自定义控件与视觉效果的全面指南
  • ggplot2绘图如何根据一个变量即区分颜色又区分深浅?
  • 超强算力 Orange Pi Kunpeng Pro 开发板基础测评与体验
  • pyqt绘制各种直线
  • LLM基础知识
  • LLM主要类别架构
  • PTA字符串删除
  • 19、matlab信号预处理中的中值滤波(medfilt1()函数)和萨维茨基-戈雷滤波滤(sgolayfilt()函数)
  • 【Python Cookbook】S01E14 从字典中提取子集
  • 【Linux】进程(4):优先级
  • 论文笔记:Image Anaimation经典论文-运动关键点模型(Monkey-Net)
  • php的引用
  •  D - 粉碎叛乱F - 其他起义
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • mac修复ab及siege安装
  • Mac转Windows的拯救指南
  • MySQL主从复制读写分离及奇怪的问题
  • node.js
  • nodejs调试方法
  • React系列之 Redux 架构模式
  • 安卓应用性能调试和优化经验分享
  • 创建一个Struts2项目maven 方式
  • 技术发展面试
  • 开源SQL-on-Hadoop系统一览
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 七牛云假注销小指南
  • 十年未变!安全,谁之责?(下)
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • zabbix3.2监控linux磁盘IO
  • 回归生活:清理微信公众号
  • # .NET Framework中使用命名管道进行进程间通信
  • # 消息中间件 RocketMQ 高级功能和源码分析(七)
  • #ifdef 的技巧用法
  • $ git push -u origin master 推送到远程库出错
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (C#)获取字符编码的类
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (pojstep1.3.1)1017(构造法模拟)
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (回溯) LeetCode 46. 全排列
  • (一)SpringBoot3---尚硅谷总结
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)人的集合论——移山之道
  • (转)重识new
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • .aanva
  • .NET CORE 第一节 创建基本的 asp.net core
  • .net core docker部署教程和细节问题
  • .NET Core使用NPOI导出复杂,美观的Excel详解