基于iText7的动态PDF生成技术方案

一、方案概述

本方案基于iText7 开源PDF操作库实现动态PDF生成服务 ,支持通过接口传入结构化参数,自动生成包含标题、正文段落、动态表格、分页的标准A4格式PDF文件,完美解决中文乱码问题,提供轻量化、可扩展、高可用的PDF生成能力,适用于报表导出、文档生成、电子凭证等业务场景。

二、技术选型

技术组件 版本 选型说明
iText7 Core 7.2.5 PDF核心操作库,负责文档创建、渲染、页面管理
iText7 Layout 7.2.5 布局渲染核心,支持段落、表格、样式排版
iText7 Font-Asian 7.2.5 亚洲字体支持包,解决PDF中文/日文/韩文乱码问题

三、核心功能

  1. 基础文档生成:创建标准A4尺寸PDF,自定义页面边距、文档元数据

  2. 中文完美支持:内置中文字体加载,无乱码、无字体缺失问题

  3. 动态内容渲染

    • 自定义标题:居中显示、可配置字号、边距

    • 正文段落:支持自定义字号、常规/加粗样式、段落间距

    • 动态表格:自适应列数、100%宽度占比、表头+数据渲染

    • 强制分页:支持手动触发新页面生成

  4. 服务化输出:提供REST接口,直接返回PDF字节流,支持浏览器下载

  5. 异常容错:统一异常捕获,抛出友好的业务异常

四、技术实现

核心流程:前端传入JSON参数 → Controller接收请求 → 调用工具类生成PDF → 内存流输出字节数组 → 响应PDF文件下载

1. 引入依赖

xml 复制代码
   <!-- iText 7 核心包 -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>kernel</artifactId>
        <version>7.2.5</version>
    </dependency>
	<!-- 布局渲染核心 -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>layout</artifactId>
        <version>7.2.5</version>
    </dependency>
    <!-- 中文支持(解决中文乱码必备)-->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>font-asian</artifactId>
        <version>7.2.5</version>
    </dependency>

2. 数据模型

java 复制代码
@Data
public class PdfRequest {
    // 文档标题
    private String title;
    // 作者(可选)
    private String author;
    // 内容元素
    private List<Element> elements;

    @Data
    public static class Element {
        // paragraph / table / newPage
        private String type;
        // 文本内容
        private String content;
        // 字体大小
        private Integer fontSize;
        // 是否加粗
        private Boolean bold;
        // 表头
        private List<String> headers;
        // 表数据
        private List<List<String>> rows;
    }

3. 工具类

PdfGeneratorUtil :iText7封装工具类,核心方法generatePdf()

核心步骤:

  1. 初始化PDF文档:创建PdfWriter、PdfDocument、Document,设置A4尺寸+页面边距

  2. 加载中文字体:使用STSong-Light字体+UniGB-UCS2-H编码,解决中文乱码

  3. 渲染文档标题:居中、18号字体、底部边距20

  4. 遍历渲染内容元素:

    • 段落:自定义字号、段落间距

    • 表格:动态列数、100%宽度、表头+数据逐行渲染

    • 分页:手动新增PDF页面

  5. 关闭文档,返回PDF字节数组

java 复制代码
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;

import java.io.ByteArrayOutputStream;
import java.util.List;


/**
 * iText 7 标准排版 PDF 生成工具
 * 包含:标题、正文、表格、分页、中文支持
 */
public class PdfGeneratorUtil {

    public static byte[] generatePdf(PdfRequest request) {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            PdfWriter writer = new PdfWriter(outputStream);
            PdfDocument pdfDoc = new PdfDocument(writer);
            Document document = new Document(pdfDoc, PageSize.A4);
            // 设置页面边距(上下左右)
            document.setMargins(50, 50, 50, 50);

            // ========== 1. 加载中文字体(核心:解决中文乱码 【正常 + 加粗】) ==========
            PdfFont fontNormal = PdfFontFactory.createFont(
                    "STSong-Light",
                    "UniGB-UCS2-H",
                    PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED
            );

            // ========== 2. 标题 ==========
            Paragraph title = new Paragraph(request.getTitle())
                    .setFont(fontNormal)
                    .setFontSize(18)
                    .setTextAlignment(TextAlignment.CENTER)
                    .setMarginBottom(20);
            document.add(title);

            // ===================== 遍历内容元素 ======================
            for (PdfRequest.Element element : request.getElements()) {
                switch (element.getType()) {
                    // ========== 3. 正文段落 ==========
                    case "paragraph" -> {
                        Paragraph p = new Paragraph(element.getContent())
                                .setFont(fontNormal)
                                .setFontSize(element.getFontSize() == null ? 12 : element.getFontSize());
                        document.add(p.setMarginBottom(10));
                    }
                    // ========== 4. 标准表格(4列) ==========
                    case "table" -> {
                        List<String> headers = element.getHeaders();
                        List<List<String>> rows = element.getRows();

                        Table table = new Table(headers.size())
                                .setWidth(UnitValue.createPercentValue(100))
                                .setMarginBottom(15);

                        // 表头(加粗)
                        for (String header : headers) {
//                            table.addHeaderCell(new Cell()
//                                    .add(new Paragraph(header).setFont(fontNormal).setBold())
//                                    .setTextAlignment(TextAlignment.CENTER)
//                                    .setPadding(8));
                            table.addHeaderCell(new Paragraph(header).setFont(fontNormal));
                        }
                        // 表数据(正常)
                        for (List<String> row : rows) {
                            for (String val : row) {
//                                table.addCell(new Cell()
//                                        .add(new Paragraph(val).setFont(fontNormal))
//                                        .setTextAlignment(TextAlignment.CENTER)
//                                        .setPadding(6));
                                table.addCell(new Paragraph(val).setFont(fontNormal));
                            }
                        }
                        document.add(table);
                    }
                    case "newPage" -> {
                        pdfDoc.addNewPage();
                    }
                }
            }
            document.close();
            return outputStream.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("PDF生成失败");
        }
    }
}

4. 接口层

java 复制代码
@RestController
public class MarkDownToPdfController {

    @PostMapping("/generate")
    public ResponseEntity<byte[]> generatePdf(@RequestBody PdfRequest request) {
        byte[] pdfBytes = PdfGeneratorUtil.generatePdf(request);

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=document.pdf");

        return ResponseEntity.status(HttpStatus.OK)
                .headers(headers)
                .contentType(MediaType.APPLICATION_PDF)
                .body(pdfBytes);
    }
}

五、接口请求示例

  • 请求地址

POST localhost:8080/generate

  • 请求体(JSON)
json 复制代码
{
    "title": "员工信息报表",
    "author": "管理员",
    "elements": [
        {
            "type": "paragraph",
            "content": "以下是本公司员工详细信息列表,数据统计日期:2025年12月",
            "fontSize": 14
        },
        {
            "type": "table",
            "headers": ["员工ID", "姓名", "部门", "职位"],
            "rows": [
                ["1001", "张三", "技术部", "Java开发"],
                ["1002", "李四", "产品部", "产品经理"]
            ]
        },
        {
            "type": "newPage"
        },
        {
            "type": "paragraph",
            "content": "第二页:报表备注:本数据仅供内部使用",
            "fontSize": 12
        }
    ]
}
  • 响应结果

浏览器自动下载名为document.pdf的PDF文件。

相关推荐
常利兵2 小时前
Spring Boot配置diff:解锁配置管理新姿势
java·spring boot·后端
悟乙己2 小时前
Advanced RAG 02:揭秘 PDF 解析
ai·pdf·llm·文档解析
卓怡学长2 小时前
w1基于springboot高校学生评教系统
java·spring boot·tomcat·maven·intellij-idea
lq12332103 小时前
PDF工具箱 PDF24 Creator 11.30.0
pdf
大佐不会说日语~3 小时前
Spring AI Alibaba 的 Function Calling 使用 @Tool 调用中,无法获取用户ID踩坑记录
java·人工智能·spring boot·spring·alibaba·function
阿丰资源3 小时前
java项目-基于SpringBoot+MySQL+Vue的前后端分离宠物商店系统(附资料)
java·spring boot·mysql
java1234_小锋13 小时前
Java高频面试题:Springboot的自动配置原理?
java·spring boot·面试
陌殇殇15 小时前
001 Spring AI Alibaba框架整合百炼大模型平台 — 快速入门
人工智能·spring boot·ai