使用 Spring Boot 集成 Thymeleaf 和 Flying Saucer 实现 PDF 导出
在 Spring Boot 项目中,生成 PDF 报表或发票是常见需求。本文将介绍如何使用 Spring Boot 集成 Thymeleaf 模板引擎和 Flying Saucer 实现 PDF 导出,并提供详细的代码实现和常见问题解决方案。
目录
- 一、项目依赖
- 二、创建 Thymeleaf 模板
- 三、创建 PDF 生成工具类
- 四、在 Spring Boot 中使用 PDF 生成功能
- 五、常见错误及解决方案
- 1. 中文字符乱码
- 2. 图片加载失败
- 3. 样式不生效
- 4. 模板路径识别错误
- 5. 依赖冲突
- 6. 内存不足
- 总结
一、项目依赖
要实现 PDF 导出功能,首先需要在项目中添加以下依赖:
<dependencies><!-- Thymeleaf模板引擎 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- Flying Saucer for PDF generation --><dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf</artifactId><version>9.1.22</version></dependency><!-- iTextPDF (com.lowagie 版本,用于兼容 Flying Saucer) --><dependency><groupId>com.lowagie</groupId><artifactId>itext</artifactId><version>2.1.7</version></dependency>
</dependencies>
注意:Flying Saucer 使用的是旧版 iText 库
com.lowagie,而不是新版com.itextpdf,确保使用正确版本以避免依赖冲突。
二、创建 Thymeleaf 模板
新建一个 HTML 模板用于生成发票内容,例如在 resources/templates/pdf/invoice.html 文件中编写如下 HTML:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>发票</title><style>body { font-family: Arial, sans-serif; margin: 20px; }h1 { text-align: center; }table { width: 100%; border-collapse: collapse; margin-top: 20px; }th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }th { background-color: #f2f2f2; }.total { font-weight: bold; }.footer { margin-top: 30px; text-align: center; font-size: 12px; color: #888; }</style>
</head>
<body>
<h1>发票</h1>
<p>发票编号:<span th:text="${invoiceNumber}"></span></p>
<p>开具日期:<span th:text="${invoiceDate}"></span></p>
<p>买家姓名:<span th:text="${buyerName}"></span></p><h2>商品详情</h2>
<table><thead><tr><th>商品名称</th><th>描述</th><th>数量</th><th>单价</th><th>小计</th></tr></thead><tbody><tr th:each="item : ${goodsItems}"><td th:text="${item.goodsName}"></td><td th:text="${item.goodsDesc}"></td><td th:text="${item.quantity}"></td><td th:text="${item.unitPrice}"></td><td th:text="${item.totalPrice}"></td></tr></tbody>
</table><p class="total">总金额:<span th:text="${finalAmount}"></span></p>
<div class="footer">感谢您的购买!</div>
</body>
</html>
三、创建 PDF 生成工具类
接下来,创建 PdfUtil 工具类,通过 Thymeleaf 渲染 HTML 并使用 Flying Saucer 将 HTML 转为 PDF:
package com.xyh.transaction.utils;import com.xyh.transaction.entity.dto.goods.GoodsInvoice;
import com.xyh.transaction.exception.BusinessException;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.xhtmlrenderer.pdf.ITextRenderer;import java.io.ByteArrayOutputStream;
import java.util.List;public class PdfUtil {public static byte[] generateInvoicePdf(String buyerName, String invoiceNumber,List<GoodsInvoice> goodsItems, String finalAmount) {TemplateEngine templateEngine = new TemplateEngine();// 使用 Thymeleaf 渲染 HTMLContext context = new Context();context.setVariable("buyerName", buyerName);context.setVariable("invoiceNumber", invoiceNumber);context.setVariable("goodsItems", goodsItems);context.setVariable("finalAmount", finalAmount);String htmlContent = templateEngine.process("pdf/invoice.html", context);// 将 HTML 转换为 PDFtry (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {ITextRenderer renderer = new ITextRenderer();renderer.getFontResolver().addFont("/path/to/your/font/simhei.ttf", true); // 防止中文乱码renderer.setDocumentFromString(htmlContent);renderer.layout();renderer.createPDF(outputStream);return outputStream.toByteArray();} catch (Exception e) {e.printStackTrace();throw new BusinessException("发票PDF 生成失败");}}
}
四、在 Spring Boot 中使用 PDF 生成功能
在 Spring Boot 控制器中调用 PdfUtil.generateInvoicePdf,将生成的 PDF 返回给用户或作为附件发送邮件:
@RestController
@RequestMapping("/invoice")
public class InvoiceController {@GetMapping("/generate")public ResponseEntity<byte[]> generateInvoice() {byte[] pdfBytes = PdfUtil.generateInvoicePdf("张三", "INV-12345",goodsItems, "1000.00");HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_PDF);headers.setContentDispositionFormData("attachment", "invoice.pdf");return new ResponseEntity<>(pdfBytes, headers, HttpStatus.OK);}
}
五、常见错误及解决方案
1. 中文字符乱码
- 问题:生成的 PDF 中,中文字符可能出现乱码。
- 解决方案:确保
addFont引用支持中文的字体文件(如simhei.ttf)。
2. 图片加载失败
-
问题:HTML 中的图片在 PDF 中无法正常显示。
-
解决方案:将图片路径设置为绝对路径或通过
setBaseURL指定资源根路径:renderer.getSharedContext().setBaseURL("file:/path/to/resources/");
3. 样式不生效
- 问题:Flying Saucer 不支持高级 CSS。
- 解决方案:使用基本的
table布局和简单 CSS,不依赖 flex、CSS 变量等。
4. 模板路径识别错误
- 问题:模板引擎找不到指定 HTML 文件。
- 解决方案:检查文件路径和模板配置,确保模板放置在
resources/templates/pdf目录下。
5. 依赖冲突
- 问题:Flying Saucer 使用旧版 iText,与其他依赖产生冲突。
- 解决方案:独立模块管理依赖,使用
maven-shade-plugin处理冲突类。
6. 内存不足
- 问题:生成大型 PDF 时出现内存溢出。
- 解决方案:增加 JVM 内存配置,或简化 HTML 结构降低内存占用。
总结
使用 Spring Boot 集成 Thymeleaf 和 Flying Saucer 实现 PDF 导出是生成发票、报告等文档的高效方式。通过以上实现步骤和常见问题解决方案,希望可以帮助您顺利在项目中集成此功能。
相关文章:
使用 Spring Boot 集成 Thymeleaf 和 Flying Saucer 实现 PDF 导出
在 Spring Boot 项目中,生成 PDF 报表或发票是常见需求。本文将介绍如何使用 Spring Boot 集成 Thymeleaf 模板引擎和 Flying Saucer 实现 PDF 导出,并提供详细的代码实现和常见问题解决方案。 目录 一、项目依赖二、创建 Thymeleaf 模板三、创建 PDF 生…...
web——upload1——攻防世界
第一次做木马题目,有点懵逼,浮现一下做题思路 可以上传一个文件,通过学习学习到了一句话木马 一句话木马: 利用文件上传漏洞,往目标网站中上传一句话木马,然后你就可以在本地通过中国菜刀chopper.exe即可…...
nginx 搭建网站
1.查看防火墙状态systemctl status firewalld 2.getenforce 3.安装nginx yum install nginx -y 4.网站信息 echo "welcome to yinchuankejixuanyuan" > /usr/share/nginx/html/index.html 5.查看命令状态 nginx -t 6.重启 systemctl restart nginx...
Java基础-Java中的常用类(上)
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 String类 创建字符串 字符串长度 连接字符串 创建格式化字符串 String 方法 System类 常用方法 方…...
气压仪器智能打气泵方案芯片SIC8833
智能打气泵方案最开始是机械式的开发,后来慢慢地演变成由一个气缸、压力传感器和主控芯片的开发的PCBA方案,它具备小体积、智能数显、预设胎压、动态测量、精准压力检测以及过充过放等功能。 其方案设计原理是利用主控芯片和压力传感器的组合设计&#x…...
软件测试(系统测试)的定位和专业:完善产品;专业;非助手;自动化
软件测试(系统测试)的定位 在研发流程的后端,测试并非无中生有的创举,而是从既有基础(即“1”)出发,致力于推动产品向更高层次(即从“1”到“100”)的跃升与完善。在这一…...
2024 CSS保姆级教程四
CSS中的动画 CSS动画(CSS Animations)是为层叠样式表建议的允许可扩展标记语言(XML)元素使用CSS的动画的模块 即指元素从一种样式逐渐过渡为另一种样式的过程 常见的动画效果有很多,如平移、旋转、缩放等等&#…...
PostgreSQL技术内幕17:PG分区表
文章目录 0.简介1.概念介绍2.分区表技术产生的背景3.分区类型及使用方式4.实现原理4.1 分区表创建4.2 分区表查询4.3 分区表写入4.4 分区表删除 0.简介 本文主要介绍PG中分区表的概念,产生分区表技术的原因,使用方式和其内部实现原理,旨在能…...
群控系统服务端开发模式-应用开发-上传工厂开发
现在的文件、图片等上传基本都在使用oss存储。而现在常用的oss存储有阿里云、腾讯云、七牛云、华为云等,但是用的最多的还是前三种。而我主要封装的是本地存储、阿里云存储、腾讯云存储、七牛云存储。废话不多说,直接上传设计图及说明,就一目…...
【Docker系列】指定系统平台拉取 openjdk:8 镜像
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
语音识别:docker部署FunASR以及springboot集成funasr
内容摘选自: https://github.com/modelscope/FunASR/blob/main/runtime/docs/SDK_advanced_guide_offline_zh.md FunASR FunASR是一个基础语音识别工具包,提供多种功能,包括语音识别(ASR)、语音端点检测(VAD…...
Rust项目结构
文章目录 一、module模块1.文件内的module 二、模块化项目结构1.关于module2.各个模块之间互相引用 三、推荐项目结构1.实例 参考 一、module模块 1.文件内的module 关键字:mod 引入模块中的方法 usemod名字:方法名usemod名字.*写全路径 二、模块化项…...
计算并联电阻的阻值
计算并联电阻的阻值 C语言代码C代码Java代码Python代码 💐The Begin💐点点关注,收藏不迷路💐 对于阻值为r1和r2的电阻,其并联电阻阻值公式计算如下: R1/(1/r11/r2) 输入 两个电阻阻抗大小,浮…...
MySQL符号类型(详细)
在 MySQL 中,符号可以分为几种主要类型,以下是所有符号类型的小写分类: 1. 占位符 ?:用于准备语句中的占位符,表示将来要替换的值。 2. 分隔符 ;:表示 sql 语句的结束。 ,:用于分隔列、值或…...
Angular引用控件类
说明: angular 在一个控件类里面,引入另外一个控件类,这样做的好处,就是代码分离,当你一个页面存在多少类似于独立的界面时,可以使用这种方式,分离代码 更好维护程序 效果图: step…...
stm32 踩坑笔记
串口问题: 问题:会改变接收缓冲的下一个字节 串口的初始化如下,位长度选择了9位。因为要奇偶校验,要选择9位。但是接收有用数据只用到1个字节。 问题原因: 所以串口接收时会把下一个数据更改...
文件上传和文件包含
声明: 本文章只是适用于网络安全教学,请自觉遵守网络安全法,严禁用于非法途径,若读者做出来任何危害网络安全的行为,后果自负,均与本人无关. 文件上传: 大部分的网站和应用系统都有上传的功能,如用户头像上传,图片上传,文档上传…...
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十八集补充:制作空洞骑士独有的EventSystem和InputModule
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、制作空洞骑士独有的EventSystem和InputModule总结 前言 hello大家好久没见,之所以隔了这么久才更新并不是因为我又放弃了这个项目,而…...
yelp数据集上试验SVD,SVDPP,PMF,NMF 推荐算法
SVD、SVD、PMF 和 NMF 是几种常见的推荐算法,它们主要用于协同过滤和矩阵分解方法来生成个性化推荐。下面是对每种算法的简要介绍: 1. SVD(Singular Value Decomposition) 用途:SVD 是一种矩阵分解技术,通…...
计算机视觉常用数据集Cityscapes的介绍、下载、转为YOLO格式进行训练
我在寻找Cityscapes数据集的时候花了一番功夫,因为官网下载需要用公司或学校邮箱邮箱注册账号,等待审核通过后才能进行下载数据集。并且一开始我也并不了解Cityscapes的格式和内容是什么样的,现在我弄明白后写下这篇文章,用于记录…...
Debian服务器网络配置二选一:告别network与NetworkManager冲突,保姆级教程教你选对工具
Debian服务器网络配置终极指南:network与NetworkManager深度解析与实战选择 在Linux系统中,网络配置是系统管理员和开发者必须掌握的核心技能之一。Debian作为最流行的Linux发行版之一,提供了两种主要的网络管理工具:传统的ifupdo…...
别再只盯着P0XXX了!一文搞懂UDS诊断中DTC的三个字节到底在说什么(附实战解析)
解码UDS诊断中的DTC三字节:从十六进制到故障真相 当诊断仪屏幕上跳出"0x43E711"这样的神秘代码时,多数工程师的第一反应是翻查故障码手册。但真正的高手会像破译密码一样,直接拆解这三个字节背后的工程语言。本文将带您深入DTC的二…...
[模型解析] GPT: 模型演进分析从GPT-3到GPT-5.5
GPT 模型演进分析:从 GPT-3 到 GPT-5.5 OpenAI 的 GPT 系列模型在过去几年经历了快速演进,从 2020 年的 GPT-3 到 2026 年的 GPT-5.5,每一次迭代都带来了显著的能力提升和架构创新。本文将系统分析 GPT 模型的演进路径与技术特点。 一、GPT 模…...
Unity 2020.3.x下HybridCLR热更新落地实战指南
1. 这不是“加个插件就能热更”的童话,而是Unity 2020.3.x下HybridCLR落地的真实切片很多人第一次听说HybridCLR,是在某篇标题写着“Unity热更新终极方案”的公众号推文里。点进去,看到几行代码、一个Build按钮、一段“热更成功”的日志截图&…...
金仓数据库KingbaseES自动创建表空间目录:简化运维,适配国产生态
目录 一、前言:传统表空间创建的运维痛点 二、自动创建表空间目录核心方案 2.1 核心控制参数 2.2 功能强制约束条件 2.3 多场景实操测试(含大小写混合路径) 场景1:目标目录已存在 场景2:目标目录部分存在 场景…...
AI-native开发:从工具使用者到智能体编排工程师的范式跃迁
1. 这不是“学AI工具”,而是重构整个开发认知体系“AI-native软件开发者”这个说法最近在技术社区刷屏,但很多人一上来就去狂刷Copilot快捷键、背Prompt模板、堆砌LLM API调用——这就像当年刚有IDE时,有人花三个月专门练CtrlShiftF的肌肉记忆…...
C++ Kafka实战:用librdkafka手写一个带自定义分区和事件回调的生产者
C Kafka实战:构建高性能生产者客户端的深度实践 在分布式系统架构中,消息队列作为解耦生产者和消费者的关键组件,其重要性不言而喻。而Apache Kafka凭借其高吞吐、低延迟和水平扩展能力,已成为现代实时数据管道和流处理应用的首选…...
Gemini3.1Pro构建神经符号系统实战
用 Gemini 3.1 Pro 构建神经符号系统的可行性探讨:从“会推理”到“能落地执行”在大模型时代,大家越来越关心的不只是“模型会不会回答”,而是能不能把推理可靠地用到复杂任务里:比如自动化规划、合规决策、工具调用、甚至半自动…...
3步搞定M3U8视频下载:N_m3u8DL-CLI-SimpleG图形界面终极指南
3步搞定M3U8视频下载:N_m3u8DL-CLI-SimpleG图形界面终极指南 【免费下载链接】N_m3u8DL-CLI-SimpleG N_m3u8DL-CLIs simple GUI 项目地址: https://gitcode.com/gh_mirrors/nm3/N_m3u8DL-CLI-SimpleG 你是否曾经遇到过在线视频无法保存的烦恼?特别…...
AI导演系统:编排角色扮演,让多智能体协作效率飙升10倍
🧑💻 博主介绍 & 诚邀关注 作者:专注于 Java、Python、前端开发的技术博主 | 全网粉丝 30 万 在校期间协助导师完成毕业设计课题分类、论文格式初审及代码整理工作;工作后持续分享毕设思路,助力毕业生顺利完成…...
