Backend Development 8 min read

Generate PDFs in Spring Boot with OpenHtmlToPdf and Freemarker – Step‑by‑Step Guide

This tutorial demonstrates how to integrate OpenHtmlToPdf with a Spring Boot 3.2.8 application, using Freemarker templates and custom fonts to render HTML content and deliver high‑quality PDF files via a REST endpoint, complete with code examples and configuration details.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Generate PDFs in Spring Boot with OpenHtmlToPdf and Freemarker – Step‑by‑Step Guide

Overview

OpenHtmlToPdf is an open‑source Java library that converts HTML content into PDF documents, supporting most CSS styles and part of HTML5. The article shows how to use it in a Spring Boot 3.2.8 project together with the Freemarker template engine to generate PDFs on the fly.

Dependencies

<code><!-- 该库进行HTML的解析 -->
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.18.1</version>
</dependency>
<!-- 将HTML内容转换为PDF文档 -->
<dependency>
    <groupId>com.openhtmltopdf</groupId>
    <artifactId>openhtmltopdf-core</artifactId>
    <version>${openhtmltopdf.version}</version>
</dependency>
<dependency>
    <groupId>com.openhtmltopdf</groupId>
    <artifactId>openhtmltopdf-pdfbox</artifactId>
    <version>${openhtmltopdf.version}</version>
</dependency>
</code>

Template preparation

<code><html>
<head>
<meta charset="UTF-8">
<title>用户列表</title>
<style>
body {font-family: "BabelStoneHan",sans-serif;}
table {width: 100%;border-collapse: collapse;}
th,td {border: 1px solid black;padding: 8px;text-align: left;}
th {background-color: #f2f2f2;}
</style>
</head>
<body>
<div class="title-container"><h2>XXXOOO全部用户列表信息</h2></div>
<div class="content-container">
<table>
<tr>
<th>编号</th><th>姓名</th><th>性别</th><th>身份证</th><th>年龄</th><th>邮箱</th><th>头像</th>
</tr>
<#list users as user>
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.sex}</td>
<td>${user.idNo}</td>
<td>${user.age}</td>
<td>${user.email}</td>
<td><img src="https://img0.baidu.com/it/u=3366443890,3137275928&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500" alt="Avatar"></td>
</tr>
</#list>
</table>
</div>
</body>
</html>
</code>

Freemarker configuration and sample data

<code>@Bean
Configuration config(ResourceLoader loader) {
    freemarker.template.Configuration cfg = null;
    try {
        cfg = new Configuration(Configuration.VERSION_2_3_33);
        // 设置模板路径
        File baseDir = loader.getResource("classpath:/templates/").getFile();
        TemplateLoader templateLoader = new FileTemplateLoader(baseDir);
        cfg.setTemplateLoader(templateLoader);
        // 设置编码
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return cfg;
}

private static final List<User> DATAS = new ArrayList<>();
static {
    for (int i = 0; i < 10; i++) {
        DATAS.add(new User(
            i + 0L,
            "姓名 - " + i,
            new Random().nextInt(3) % 2 == 0 ? "男" : "女",
            "身份证 - " + i,
            new Random().nextInt(100),
            i + "@qq.com",
            "avatar.png" // 头像实际在模板中写死了
        ));
    }
}
</code>

PDF generation controller

<code>@RestController
@RequestMapping("/users")
public class UserController {
    private final Configuration cfg;
    public UserController(Configuration cfg) {
        this.cfg = cfg;
    }

    // 生成PDF
    @GetMapping("/gen")
    public Object gen(HttpServletResponse response) {
        // 设置文件下载 Header
        String fileName = new String("用户列表.pdf".getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        response.setContentType("application/octet-stream");
        try {
            // 获取模板
            Template template = this.cfg.getTemplate("users.ftl");
            // 准备模板需要的数据
            Map<String, Object> root = new HashMap<>();
            root.put("users", DATAS);
            // 生成 HTML 内容到内存中
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Writer out = new OutputStreamWriter(baos);
            template.process(root, out);
            // 将上面生成的 HTML 内容进行解析
            Document document = Jsoup.parse(baos.toString(StandardCharsets.UTF_8), "UTF-8");
            document.outputSettings().syntax(Document.OutputSettings.Syntax.html);
            // 构建 PDF 文档,最后将上面的 Document 进行输出
            PdfRendererBuilder builder = new PdfRendererBuilder();
            // 使用字体,字体名要与模板中 CSS 样式中指定的字体名相同
            builder.useFont(new ClassPathResource("/fonts/BabelStoneHan.ttf").getFile(),
                "BabelStoneHan", 1, BaseRendererBuilder.FontStyle.NORMAL, true);
            builder.toStream(response.getOutputStream());
            builder.useFastMode();
            builder.withW3cDocument(new W3CDom().fromJsoup(document), new ClassPathResource("/templates/").getPath());
            builder.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "生成成功";
    }
}
</code>

Conclusion

OpenHtmlToPdf is a powerful open‑source Java library designed for converting HTML content into high‑quality PDF documents. Its strong HTML/CSS compatibility, flexible configuration options, and easy integration make it suitable for generating reports, contracts, e‑books, and other PDF‑based outputs in Spring Boot applications.

JavaSpring BootPDF generationfreemarkerHTML to PDFOpenHtmlToPdf
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.