后端 PDF 生成方案(OpenPDF + Thymeleaf)
前言
企业项目中可能存在需要生成一些 PDF 报表的功能,需要后端提供一个下载 PDF 的接口,本文将介绍通过采用 OpenPDF + Thymeleaf 的技术方案来解决该问题。
什么是 OpenPDF
他是基于 iText 的开源替代方案,通过使用 OpenPDF 可以让我们生成 PDF 文件。相较于 iText,OpenPDF 更加轻量级,API 设计更加简洁。它允许商业使用,无传染性,适合企业项目。
核心功能
-
基础 PDF 生成(文本、表格、图片)
-
简单表单填充与加密(AES-128)
-
HTML 转 PDF(需配合 Flying Saucer)
什么是 Thymeleaf
用于 Java 应用中动态生成 HTML、XML 等文件的工具。
与 Spring 深度集成,可以在 Spring 项目直接进行引入。
Demo 实践
业务场景
项目中存在报表导出功能,前端为我们传入数据,需要后端对于数据进行整理然后生成对应的 PDF 文件报表进行返回。需要注意的是,我们的 PDF 文件中可能存在中文和图片,需要支持中文和图片的渲染。
实现流程
1、引入 Maven 依赖
<!-- Web开发启动项 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 模板引擎(动态生成HTML文件) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 替代 iText 的开源 PDF 操作库,用于生成 PDF 文件 -->
<dependency>
<groupId>com.github.librepdf</groupId>
<artifactId>openpdf</artifactId>
<version>1.3.38</version>
</dependency>
<!-- 基于 OpenPDF 的 HTML/CSS 渲染引擎,将模板渲染为 PDF -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-openpdf</artifactId>
<version>9.1.22</version>
</dependency>
2、准备静态资源文件
-
src/main/resources/templates/index.html:用于测试请求。
-
src/main/resources/templates/pdf-template.html:生成的 PDF 模板文件(通过 Thymeleaf)动态渲染。
-
src/main/resources/static/images/1111.png:用作测试的图片。
-
src/main/resources/static/fonts/simhei.ttf:支持中文的字体。
3、编写 Controller
@Controller
public class PdfController {
@Autowired
private PdfGenerationService pdfService;
@GetMapping("/")
public String index() {
return "index";
}
@PostMapping("/generate-pdf")
public void generatePdf(@RequestParam String name,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String userAgent = request.getHeader("User-Agent");
pdfService.generatePdf(response, name, userAgent);
}
}
4、编写 Service
@Service
public class PdfGenerationService {
//自动注入Thymeleaf模板引擎,用于处理HTML模板
@Autowired
private TemplateEngine templateEngine;
public void generatePdf(HttpServletResponse response, String name, String userAgent) throws IOException {
Context ctx = new Context();
ctx.setVariable("name", name);
ctx.setVariable("timestamp", new Date());
ctx.setVariable("userAgent", userAgent);
try {
String processedHtml = templateEngine.process("pdf-template", ctx);
//设置响应头信息
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"generated-pdf.pdf\"");
//创建PDF渲染器
ITextRenderer renderer = new ITextRenderer();
//添加字体解析
configureChineseFont(renderer);
// 添加图片路径解析
ClassPathResource imgResource = new ClassPathResource("static/images/");
String baseUrl = imgResource.getURL().toString();
renderer.getSharedContext().setBaseURL(baseUrl);
//将HTML转化为PDF
renderer.setDocumentFromString(processedHtml);
renderer.layout();
renderer.createPDF(response.getOutputStream());
renderer.finishPDF();
} catch (DocumentException e) {
throw new IOException("Error generating PDF", e);
}
}
/**
* 注册字体文件
* @param renderer
* @throws DocumentException
* @throws IOException
*/
private void configureChineseFont(ITextRenderer renderer) throws DocumentException, IOException {
try {
ClassPathResource fontResource = new ClassPathResource("static/fonts/simhei.ttf");
String fontPath = fontResource.getURL().toString();
renderer.getFontResolver().addFont(
fontPath,
BaseFont.IDENTITY_H,
BaseFont.NOT_EMBEDDED
);
} catch (Exception e) {
throw new DocumentException("字体加载失败: " + e.getMessage());
}
}
}
测试
-
进入 index 页面。
-
填写 name,后点击 Generate PDF 创建对应 PDF。
-
查看下载的 PDF,如下:
至此,需求满足,后续根据需求添加需求项即可。
总结
总结了企业中实现后端生成 PDF 的解决方案。通过使用 OpenPDF + Thymeleaf 的方案,该方案学习成本低,且无商业问题,适用于较低性能需求下的 PDF 生成问题。
Demo 代码 GitHub 源地址:https://github.com/Djhhhhhh/MakePDFdemo