SpringBoot生成PDF中文缺失求助(Thymeleaf+Flying-saucer)
排查与修复Flying Saucer PDF中文缺失问题
以下是针对你的问题的具体排查方向和修复方案:
一、确认字体加载逻辑正确性
很多情况下中文缺失并非字体本身问题,而是字体未被正确加载到Flying Saucer的渲染上下文:
字体文件路径与打包验证
- 将字体文件(如
SimSun.ttf、NotoSansSC-Regular.ttf)放置在src/main/resources/fonts目录下 - 打包后检查jar包内是否包含字体文件:执行
jar -tf your-springboot-app.jar,确认存在BOOT-INF/classes/fonts/[字体文件名] - 注意:Linux环境下文件名大小写敏感,确保代码中引用的文件名与实际一致
- 将字体文件(如
正确注册字体(适配Jar包环境)
避免使用getFile()方法(Jar内无法直接获取文件路径),改用流加载方式:ITextRenderer renderer = new ITextRenderer(); // 加载SimSun字体 try (InputStream fontStream = getClass().getResourceAsStream("/fonts/SimSun.ttf")) { if (fontStream == null) { throw new IOException("字体文件未找到"); } renderer.getFontResolver().addFont( fontStream, BaseFont.IDENTITY_H, // 必须用IDENTITY_H支持Unicode全字符集 BaseFont.EMBEDDED // 嵌入字体到PDF,避免依赖客户端字体 ); }
二、CSS字体规则强制生效
确保HTML中的所有中文元素都正确关联到加载的中文字体:
全局字体覆盖
在Thymeleaf模板的<style>标签中设置全局字体:<style> * { font-family: 'SimSun', 'Noto Sans SC', serif !important; } body { font-size: 12pt; color: #333; } </style>- 使用
!important避免其他CSS规则覆盖字体设置 - 按优先级排列字体,优先使用已加载的中文字体
- 使用
验证HTML字符编码
确保HTML头部声明UTF-8编码,避免字符转义问题:<meta charset="UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
三、排查其他潜在问题
字体文件完整性
重新下载官方字体文件(如从系统字体目录复制SimSun,或获取官方版本的Noto Sans SC),避免使用损坏的字体文件Flying Saucer版本兼容性
升级到最新稳定版(如9.1.22),旧版本可能存在中文字体渲染Bug:<dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf</artifactId> <version>9.1.22</version> </dependency>PDF字体嵌入验证
生成PDF后,用Adobe Acrobat或其他PDF阅读器查看文档属性→字体列表,若能看到SimSun或Noto Sans SC,说明字体已成功嵌入;若未显示,需重新检查字体加载逻辑
四、完整示例代码
SpringBoot服务中的PDF生成核心逻辑:
@Service public class PdfService { private final TemplateEngine templateEngine; public PdfService(TemplateEngine templateEngine) { this.templateEngine = templateEngine; } public ByteArrayInputStream generateChinesePdf(String templateName, Map<String, Object> data) throws Exception { // 生成HTML内容 Context context = new Context(Locale.CHINA); context.setVariables(data); String html = templateEngine.process(templateName, context); // 初始化渲染器并加载字体 ITextRenderer renderer = new ITextRenderer(); try (InputStream simSunStream = getClass().getResourceAsStream("/fonts/SimSun.ttf")) { renderer.getFontResolver().addFont(simSunStream, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); } // 渲染并生成PDF renderer.setDocumentFromString(html); renderer.layout(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); renderer.createPDF(outputStream); return new ByteArrayInputStream(outputStream.toByteArray()); } }
内容的提问来源于stack exchange,提问作者Uday
相关产品推荐
相关产品推荐

