【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文档的应用,尤其是那些涉及安全性和高级功能的企业级应用。
示例代码:
复制代码
<!-- 添加依赖 -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext7-core</artifactId>
    <version>7.1.15</version> <!-- 请检查并使用最新版本 -->
</dependency>


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文档的应用,尤其是那些希望保持完全开源的项目。
示例代码:
复制代码
<!-- 添加依赖 -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.27</version> <!-- 请检查并使用最新版本 -->
</dependency>


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模板语法较为复杂,需要一定时间来掌握。
  • 依赖项较多: 需要引入多个依赖项,可能会增加项目的复杂度。
  • 性能问题: 在处理非常大的数据集时,可能会遇到性能瓶颈,尤其是在内存管理和渲染速度方面。
性能:
  • 在处理复杂报表和大数据集时表现较好,尤其是在需要高级功能(如分组、图表)的情况下。
适用场景:
  • 适合需要生成复杂报表的应用,尤其是包含大量数据、图表、分组等元素的场景。
  • 适合需要支持多种输出格式的应用。
示例代码:
复制代码
<!-- 添加依赖 -->
<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports</artifactId>
    <version>6.17.0</version> <!-- 请检查并使用最新版本 -->
</dependency>


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模板的情况。
  • 适合生成简单的文档,如发票、合同、报告等,而不涉及复杂的报表功能。
示例代码:
复制代码
<!-- 添加依赖 -->
<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>


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,或者只需要生成简单的文档(如发票、合同等)。它易于使用,开发速度快,特别适合前端开发人员。

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

相关推荐
IT_陈寒3 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码4 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo4 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志5 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..5 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects5 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰5 小时前
一些基础和问题解决
后端
陈随易5 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN6 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp
Imchendiana6 小时前
《狂人日记NO.9》— 前后端一把梭,我的全栈实录
前端·后端