【Spring Boot 实现 PDF 导出】

Spring Boot 实现 PDF 导出

在Spring Boot应用程序中实现PDF导出功能,可以选择多种库和技术栈。每种方法都有其优缺点,适用于不同的场景。以下是四种常见的方式:iText、Apache PDFBox、JasperReports 和 Thymeleaf + Flying Saucer。我将详细对比这些方法,并提供相应的代码示例。


1. iText

优点:

  • 丰富的API: 支持复杂的PDF操作,如加密、数字签名、表单处理等。
  • 企业级支持: 提供广泛的文档和支持社区。
  • 多格式输出: 除了PDF,还支持其他格式(如HTML、XML)的转换。

缺点:

  • 商业许可: iText 7 是商业软件,某些高级功能需要购买许可证。
  • 学习曲线: API较为复杂,可能需要一定的学习成本。

性能:

  • 对于大多数应用场景来说,iText 的性能是足够的。它在内存管理和文件处理速度方面表现优秀,尤其适合处理复杂的PDF文档。

适用场景:

  • 适合需要生成复杂PDF文档的应用,尤其是那些涉及安全性和高级功能的企业级应用。

示例代码:

xml 复制代码
<!-- 添加依赖 -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext7-core</artifactId>
    <version>7.1.15</version> <!-- 请检查并使用最新版本 -->
</dependency>
java 复制代码
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ITextPdfService {

    public void export(HttpServletResponse response) throws IOException {
        // 设置响应头
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "attachment; filename=users.pdf");

        try (PdfWriter writer = new PdfWriter(response.getOutputStream());
             PdfDocument pdf = new PdfDocument(writer);
             Document document = new Document(pdf)) {

            // 添加内容到PDF
            document.add(new Paragraph("Hello, this is a PDF document created with iText in Spring Boot!"));

            // 关闭文档
            document.close();
        }
    }
}

2. Apache PDFBox

优点:

  • 完全开源: 没有商业限制,适合所有类型的项目。
  • 轻量级: 依赖项较少,项目结构简洁。
  • 易于上手: API相对简单,适合快速开发和学习。

缺点:

  • 功能有限: 在一些复杂的功能上,如处理大型PDF或执行高级操作,可能不如iText强大。
  • 性能问题: 在处理非常大的文件或高并发场景下,性能可能会略逊于iText。

性能:

  • PDFBox 在处理较小的PDF文件时表现良好,但在处理大文件或者高并发场景下,其性能可能会略逊于iText。

适用场景:

  • 适合需要生成简单PDF文档的应用,尤其是那些希望保持完全开源的项目。

示例代码:

xml 复制代码
<!-- 添加依赖 -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.27</version> <!-- 请检查并使用最新版本 -->
</dependency>
java 复制代码
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class PdfBoxPdfService {

    public void export(HttpServletResponse response) throws IOException {
        // 设置响应头
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "attachment; filename=users.pdf");

        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage();
            document.addPage(page);

            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
                contentStream.beginText();
                contentStream.newLineAtOffset(100, 700);
                contentStream.showText("Hello, this is a PDF document created with Apache PDFBox in Spring Boot!");
                contentStream.endText();
            }

            // 将PDF写入响应输出流
            document.save(response.getOutputStream());
        }
    }
}

3. JasperReports

优点:

  • 强大的报表设计能力: 支持复杂的表格、图表、分组、子报表等功能。
  • 多数据源支持: 可以从数据库、JavaBean集合、CSV、XML等多种数据源获取数据。
  • 丰富的样式和格式化: 支持多种字体、颜色、边框、背景等样式设置,以及日期、数字等格式化。
  • 集成度高: 与Spring Boot集成方便,可以轻松地将报表生成逻辑嵌入到应用程序中。
  • 输出格式多样: 除了PDF,还支持HTML、Excel、CSV等多种输出格式。

缺点:

  • 学习曲线较陡: JRXML模板语法较为复杂,需要一定时间来掌握。
  • 依赖项较多: 需要引入多个依赖项,可能会增加项目的复杂度。
  • 性能问题: 在处理非常大的数据集时,可能会遇到性能瓶颈,尤其是在内存管理和渲染速度方面。

性能:

  • 在处理复杂报表和大数据集时表现较好,尤其是在需要高级功能(如分组、图表)的情况下。

适用场景:

  • 适合需要生成复杂报表的应用,尤其是包含大量数据、图表、分组等元素的场景。
  • 适合需要支持多种输出格式的应用。

示例代码:

xml 复制代码
<!-- 添加依赖 -->
<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports</artifactId>
    <version>6.17.0</version> <!-- 请检查并使用最新版本 -->
</dependency>
java 复制代码
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class JasperReportController {

    @GetMapping("/export-jasper-pdf")
    public void export(HttpServletResponse response) throws Exception {
        // 设置响应头
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "attachment; filename=report.pdf");

        // 加载JRXML模板
        InputStream reportTemplate = getClass().getResourceAsStream("/templates/report.jrxml");
        JasperReport jasperReport = JasperCompileManager.compileReport(reportTemplate);

        // 准备数据
        List<User> users = userService.getAllUsers(); // 假设有一个UserService类
        JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(users);

        // 设置参数
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("title", "User Report");

        // 生成PDF
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
        JasperExportManager.exportReportToPdfStream(jasperPrint, response.getOutputStream());
    }
}

4. Thymeleaf + Flying Saucer

优点:

  • HTML/CSS友好: 使用标准的HTML和CSS进行页面布局和样式设置,非常适合前端开发人员。
  • 易于维护: HTML模板容易理解和修改,尤其适合那些已经熟悉HTML/CSS的团队。
  • 灵活性高: 可以轻松地将现有的Thymeleaf模板转换为PDF,减少了重复工作。
  • 轻量级: 相对于JasperReports,Flying Saucer的依赖项较少,项目结构更简洁。
  • 快速开发: 对于简单的PDF生成需求,开发速度较快,因为不需要学习新的模板语言。

缺点:

  • 功能有限: 相比JasperReports,Flying Saucer的功能较为有限,特别是在处理复杂报表(如分组、图表)时。
  • 性能一般: 在处理大文件或高并发场景下,性能可能不如JasperReports。
  • 样式兼容性: 某些CSS样式可能无法完全兼容,导致PDF渲染效果与预期不符。

性能:

  • 对于简单的PDF生成需求,性能足够,并且开发速度快,维护成本低。

适用场景:

  • 适合需要将现有的HTML页面转换为PDF的应用,尤其是那些已经有现成的HTML模板的情况。
  • 适合生成简单的文档,如发票、合同、报告等,而不涉及复杂的报表功能。

示例代码:

xml 复制代码
<!-- 添加依赖 -->
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.12.RELEASE</version> <!-- 请检查并使用最新版本 -->
</dependency>
<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>flying-saucer-pdf-itext5</artifactId>
    <version>9.1.20</version> <!-- 请检查并使用最新版本 -->
</dependency>
java 复制代码
import org.springframework.core.io.ClassPathResource;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.xhtmlrenderer.pdf.ITextRenderer;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

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

    private final TemplateEngine templateEngine;

    public PdfController(TemplateEngine templateEngine) {
        this.templateEngine = templateEngine;
    }

    @GetMapping("/export-thymeleaf-pdf")
    public void export(HttpServletResponse response) throws Exception {
        // 设置响应头
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "attachment; filename=report.pdf");

        // 加载HTML模板
        InputStream templateInputStream = new ClassPathResource("templates/report.html").getInputStream();
        String htmlContent = new String(templateInputStream.readAllBytes(), StandardCharsets.UTF_8);

        // 准备上下文数据
        Context context = new Context();
        context.setVariable("users", userService.getAllUsers()); // 假设有一个UserService类
        context.setVariable("title", "User Report");

        // 渲染HTML
        String processedHtml = templateEngine.process(htmlContent, context);

        // 将HTML转换为PDF
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocumentFromString(processedHtml);
        renderer.layout();

        // 输出PDF
        try (OutputStream outputStream = response.getOutputStream()) {
            renderer.createPDF(outputStream);
        }
    }
}

性能与易用性对比

特性 iText Apache PDFBox JasperReports Thymeleaf + Flying Saucer
性能 高(复杂报表) 中(简单文档)
易用性 复杂 简单 复杂 简单
功能 强大 有限 非常强大(报表) 有限(HTML/CSS)
依赖项 较多(部分需商业许可) 较多
适用场景 复杂PDF文档 简单PDF文档 复杂报表 简单文档/HTML转PDF
学习曲线 陡峭 平缓 陡峭 平缓

总结

  • 选择 iText 如果你需要生成复杂的PDF文档,尤其是涉及到安全性和高级功能的企业级应用。iText 提供了最全面的功能和最佳的性能,但需要注意其商业许可要求。

  • 选择 Apache PDFBox 如果你希望保持完全开源,并且只需要生成简单的PDF文档。PDFBox 轻量级且易于上手,适合小型项目或对性能要求不高的场景。

  • 选择 JasperReports 如果你需要生成复杂的报表,特别是涉及到分组、图表、子报表等功能。JasperReports 是一个功能强大且成熟的工具,适合企业级应用。

  • 选择 Thymeleaf + Flying Saucer 如果你需要将现有的HTML页面转换为PDF,或者只需要生成简单的文档(如发票、合同等)。它易于使用,开发速度快,特别适合前端开发人员。

在实际项目中,建议根据具体需求和技术栈选择合适的工具。如果你不确定哪种工具更适合,可以先尝试一个小规模的原型项目,评估其性能和易用性,再做最终决定。

相关推荐
sniper_fandc1 小时前
SpringBoot系列—入门
java·spring boot·后端
Albert Edison7 小时前
【最新版】IntelliJ IDEA 2025 创建 SpringBoot 项目
java·spring boot·intellij-idea
Piper蛋窝8 小时前
深入 Go 语言垃圾回收:从原理到内建类型 Slice、Map 的陷阱以及为何需要 strings.Builder
后端·go
六毛的毛10 小时前
Springboot开发常见注解一览
java·spring boot·后端
AntBlack10 小时前
拖了五个月 ,不当韭菜体验版算是正式发布了
前端·后端·python
315356691310 小时前
一个简单的脚本,让pdf开启夜间模式
前端·后端
uzong11 小时前
curl案例讲解
后端
开开心心就好11 小时前
免费PDF处理软件,支持多种操作
运维·服务器·前端·spring boot·智能手机·pdf·电脑
一只叫煤球的猫11 小时前
真实事故复盘:Redis分布式锁居然失效了?公司十年老程序员踩的坑
java·redis·后端
猴哥源码11 小时前
基于Java+SpringBoot的农事管理系统
java·spring boot