spring boot操作PDF

在sping boot中常用的操作PDF的的有以下三种

  • PDFBox:Apache2.0,底层 PDF 操作库,适合解析、提取、合并、签名 PDF;手写坐标绘制 PDF,不支持 HTML 转 PDFApache PDF...
  • iTextPDF(iText7):AGPL 协议,强大的编程式 PDF 生成库,支持表格、页眉页脚、表单、签名;HTML 转 PDF 需要额外`pdfHTML`插件,商用闭源项目要购买商业授权iText
  • Flying Saucer(xhtmlrenderer):LGPL 协议,专门 XHTML+CSS2.1 转 PDF,底层依赖 iText5;适合报表、发票模板,不是通用 PDF 编辑库

一:PDFBox介绍

1:优点

  1. Apache 2.0 协议,商业友好,闭源产品随便用,无传染性开源约束
  2. 纯 Java,Apache 顶级项目,社区稳定;功能:文本提取、PDF 合并 / 拆分、PDF 转图片、表单填充、数字签名、PDF/A 校验Apache PDF
  3. 底层 API,可以直接操作 PDF 页、文字、图片、坐标;适合对已有 PDF 做修改、解析
  4. 自带命令行工具,可离线处理 PDF 文件

2:缺点

  1. 没有高层排版 API:没有自动换行、自动分页、表格组件,写文字必须手动指定 x/y 坐标;复杂报表写起来极其麻烦,需要第三方扩展(Boxable/easytable)Apache PDF
  2. 原生不支持 HTML 转 PDF
  3. 默认字体无中文,必须手动加载中文字体
  4. 超大 PDF 性能一般;表格提取弱,需要额外 Tabula 等工具辅助

3:依赖包安装

复制代码
<!-- PDFBox 核心 -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>3.0.5</version>
</dependency>

4:操作示例

复制代码
package com.example.demo.controller;

import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.apache.pdfbox.pdmodel.PDDocument;

import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@RestController
@RequestMapping("/pdf")
public class PdfController {

    @GetMapping("/pdfbox")
    public String pdfbox()
    {
        try (PDDocument doc = new PDDocument()) {
            PDPage page = new PDPage();
            doc.addPage(page);
            try (PDPageContentStream stream = new PDPageContentStream(doc, page)) {
                // 加载中文字体
                PDType0Font font = PDType0Font.load(doc, new FileInputStream("fonts/simhei.ttf"));
                stream.setFont(font, 14);
                stream.beginText();
                stream.newLineAtOffset(100, 700);
                stream.showText("Hello PDFBox 中文测试");
                stream.endText();
            }
            DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String nowStr = LocalDateTime.now().format(fmt);
            String savePath = "file/" + nowStr + "/";
            File dir = new File(savePath);
            if (!dir.exists()) {
                // 创建多级目录,父目录不存在也自动创建
                boolean success = dir.mkdirs();
                if (!success) {
                    throw new RuntimeException("目录创建失败,检查权限");
                }
            }
            doc.save(savePath + "pdfbox-demo.pdf");
        } catch (Exception e) {
            //PDF生成异常
            throw new RuntimeException(e);
        }

        return "PDF生成完成";
    }
}

二:iTextPDF介绍

1:优点

  1. 高层排版 API:内置段落、表格、图片、页眉页脚、页码、水印、表单、PDFUA 无障碍文档,开发复杂报表非常方便iText
  2. 性能优秀,高并发批量生成 PDF 稳定;支持数字签名、加密、各种 PDF 高级特性
  3. 配套`pdfHTML`插件,可以直接 HTML 转 PDF,CSS 支持比 Flying Saucer 更强

2:缺点

  1. AGPL 协议大坑:如果你把 iText7 部署在 Web 服务(SaaS)并且不对外开源全部代码,必须购买商业授权,否则违反协议;内部离线使用也要评估法务风险iText
  2. iText7 API 和 iText5 改动巨大,升级成本高
  3. 中文同样需要手动嵌入字体

3:依赖包安装

复制代码
<!--itextpdf核心包 -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext7-core</artifactId>
    <version>8.0.4</version>
    <type>pom</type>
</dependency>
<!--html转PDF核心插件-->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>html2pdf</artifactId>
    <version>5.0.4</version>
</dependency>
<!-- 中文支持 -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>font-asian</artifactId>
    <version>8.0.4</version>
</dependency>

4:操作示例

复制代码
package com.example.demo.controller;

import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.io.font.FontProgramFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@RestController
@RequestMapping("/pdf")
public class PdfController {

    @GetMapping("/itextpdf")
    public String itextpdf() {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String nowStr = LocalDateTime.now().format(fmt);
        String savePath = "file/" + nowStr + "/";
        File dir = new File(savePath);
        if (!dir.exists()) {
            // 创建多级目录,父目录不存在也自动创建
            boolean success = dir.mkdirs();
            if (!success) {
                throw new RuntimeException("目录创建失败,检查权限");
            }
        }

        String file = savePath + "itext-html-demo.pdf";

        try (FileOutputStream out = new FileOutputStream(file)) {
            ConverterProperties converterProperties = new ConverterProperties();
            //第三个参数 true:加载系统字体
            DefaultFontProvider fontProvider = new DefaultFontProvider(false, false, true);
            fontProvider.addFont(FontProgramFactory.createFont("fonts/simhei.ttf"));
            converterProperties.setFontProvider(fontProvider);
            String html = """
                    <html>
                    <head>
                        <meta charset="UTF-8"/>
                    </head>
                    <body>
                        <h1>测试PDF</h1>
                        <p>中文报表</p>
                    </body>
                    </html>
                    """;
            HtmlConverter.convertToPdf(html, out, converterProperties);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return "PDF生成完成";
    }

}

三:Flying Saucer介绍

1:优点

  1. HTML/CSS 开发 PDF,前端写模板,后端填充数据(Thymeleaf/Freemarker),开发报表速度极快;支持`@page`、`page-break`分页控制,适合打印样式报表、发票
  2. LGPL 协议,商用友好;纯 Java,无需浏览器、无头 Chrome,服务器部署简单,内存占用低
  3. 支持自定义字体解决中文,支持图片、表格、页码

2:缺点

  1. 仅支持 CSS2.1,少量 CSS3,不支持 flex、grid,现代 CSS 基本不可用;必须是合法 XHTML,普通 HTML5 直接渲染会报错,需要 Jsoup 清洗转 XHTML
  2. 不能修改、解析已有 PDF,只能把 XHTML 渲染生成新 PDF;不支持 PDF 签名、表单填充等高级 PDF 能力
  3. 项目维护活跃度一般;复杂嵌套样式容易排版错乱,需要严格控制模板

3:依赖包安装

复制代码
<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>flying-saucer-pdf-itext5</artifactId>
    <version>9.7.2</version>
</dependency>

4:操作示例

复制代码
package com.example.demo.controller;

import com.itextpdf.text.pdf.BaseFont;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@RestController
@RequestMapping("/pdf")
public class PdfController {

    @GetMapping("/flying")
    public String flying()
    {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String nowStr = LocalDateTime.now().format(fmt);
        String savePath = "file/" + nowStr + "/";
        File dir = new File(savePath);
        if (!dir.exists()) {
            // 创建多级目录,父目录不存在也自动创建
            boolean success = dir.mkdirs();
            if (!success) {
                throw new RuntimeException("目录创建失败,检查权限");
            }
        }

        String file = savePath + "flying-saucer-pdf.pdf";

        try (FileOutputStream out = new FileOutputStream(file)) {
            ITextRenderer renderer = new ITextRenderer();
            // 设置字体,解决中文
            renderer.getFontResolver().addFont("fonts/simhei.ttf", BaseFont.IDENTITY_H, true);

            String xhtml = """
                <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
                <html xmlns="http://www.w3.org/1999/xhtml">
                <head>
                    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
                    <style>
                        body {
                            font-family: SimHei;
                    }
                    </style>
                </head>
                <body>
                    <h1>报表标题</h1>
                    <p>Flying Saucer XHTML转PDF,中文测试</p>
                </body>
                </html>
                """;
            renderer.setDocumentFromString(xhtml);
            renderer.layout();
            renderer.createPDF(out);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return "PDF生成完成";
    }
}
相关推荐
她的男孩1 小时前
缓存明明命中了却报 ClassCastException:拆完多级缓存控制面,我挖出 5 个静默失效的坑
java·后端·架构
T_Apollo1 小时前
2.5 Java 8.0 版本新增特性和类
java
SimonKing1 小时前
SpringBoot 集成 SSE 实现服务端推送或可代替Websocket
java·后端·程序员
不正经的码狗1 小时前
JAVA 、Eclipse 安装及配置 JAVA 项目(无需配置环境)
java·eclipse
xiaoqiMikko1 小时前
你升的是 jackson-databind,中招的是 jackson-core:一个超长 JSON key 就能吃掉 200MB 堆
java·安全
不正经的码狗2 小时前
Eclipse汉化(快速,推荐)
java·eclipse
极客互动API2 小时前
极客互动-企业微信基于外部API接口实现AI客服自动接管外部联系人消息收发
java·微信·企业微信·ai编程·rpa
Sam_Deep_Thinking2 小时前
关于java final关键字的可见性
java·后端·面试·程序员
tryxr2 小时前
矩阵的几种基础变换
java·数据结构·算法·矩阵