• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

使用itextpdf填充表单域并生成pdf

武飞扬头像
你家宝宝
帮助1

前言

最近手上有个任务,就是需要做一个pdf导出的功能。

可选择的技术点比较多,我这边综合考虑之后,使用的是 itext。
大致有两种实现思路:
1️⃣:使用软件【Adobe Acrobat DC】去做一个pdf模版,将表单域指定好,随后使用代码去填充参数,最终得到一个pdf或字节数组。

2️⃣:使用【Freemarker】渲染html页面,最终使用代码将该页面转换为pdf。

我这边当前的需求比较适合第一种方式。

一、准备工作

1.1 安装软件

首先是安装软件(失效的话麻烦评论区留言)
链接:https://pan.百度.com/s/1O8JtVuK87VYbzx0DGQyJ1g
提取码:a0hy

1.2 准备pdf

新建一个word文档,插入一个表格,效果如下:
学新通

然后将word导出为pdf文件。
再使用我们刚刚安装好的软件打开。

1.3 设置表单域

在工具栏中找到“准备表单”功能,点击打开。
学新通

然后修改自己想要的文本域字段名、字体大小等配置:
学新通

也可以右键新增文本域(我这里的title就是新增的):
学新通
随后我们保存pdf即可。最终我们会得到这样一个pdf:
学新通

二、创建项目

创建一个普通的 springboot项目,引入依赖如下:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext7-core</artifactId>
            <version>7.2.5</version>
            <type>pom</type>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
学新通

resources 目录中创建 templates 文件夹,并将我们前边准备好的pdf放进去。效果如下:
学新通
我这里准备的文件是 personal_info.pdf

三、编写代码

3.1 编写工具类

package org.feng.pdf;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
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.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ResourceUtils;

import java.io.*;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * 填充pdf表单域
 *
 * @author fengjinsong
 * @date 2023-06-28 16:55:38
 * @version: 1.0
 */
@Slf4j
@Data
public class FillFormFieldsToPdfTemplateUtil {

    /**
     * 默认模板路径
     */
    private static final String DEFAULT_TEMPLATE_DIRECTORY;

    /**
     * 默认字体(pdf显示中文)
     */
    private static final PdfFont DEFAULT_FONT;

    /**
     * 模版路径
     */
    private String templateDirectory;

    /**
     * 字体
     */
    private PdfFont pdfFont;

    public FillFormFieldsToPdfTemplateUtil() {
    }

    static {
        try {
            DEFAULT_TEMPLATE_DIRECTORY = ResourceUtils.getURL("classpath:").getPath()   "/templates/";
            DEFAULT_FONT = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 依据pdf模板,填充表单域,生成pdf文件
     *
     * @param templateFileName 模版文件名,不能为空
     * @param formFieldsParams 表单域需要的参数,不能为空
     * @param destPdfPath      目标位置
     * @throws IOException 涉及到文件操作
     */
    public void generatePdfFile(String templateFileName, String destPdfPath, Map<String, String> formFieldsParams) throws IOException {
        // 构造pdf阅读器,指定输入流
        PdfReader pdfReader = new PdfReader(new FileInputStream(getTemplatePath(templateFileName)));
        // 构造pdf写出器,指定输出流
        OutputStream fos = new FileOutputStream(destPdfPath);

        // 构造pdfDocument实例
        PdfDocument pdf = new PdfDocument(pdfReader, new PdfWriter(fos));

        // 设置为a4纸张大小
        pdf.setDefaultPageSize(PageSize.A4);

        // 替换参数(如果有参数的话)
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
        fillFormFields(form, formFieldsParams);

        // 锁定表单,不让修改
        form.flattenFields();
        pdf.close();
    }

    /**
     * 根据pdf模版和表单域参数获取pdf对应的字节数组
     *
     * @param templateFileName 模版文件名,不能为空
     * @param formFieldsParams 表单域需要的参数,不能为空
     * @return 填充了表单域参数之后的pdf字节数组
     * @throws IOException 涉及到文件操作
     */
    public byte[] generatePdfByteArray(String templateFileName, Map<String, String> formFieldsParams) throws IOException, RuntimeException {

        // 构造pdf阅读器,指定输入流
        PdfReader pdfReader = new PdfReader(new FileInputStream(getTemplatePath(templateFileName)));
        // 构造pdf写出器,指定输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        PdfWriter pdfWriter = new PdfWriter(outputStream);

        // 构造pdfDocument实例
        PdfDocument pdf = new PdfDocument(pdfReader, pdfWriter);
        // 设置为a4纸张大小
        pdf.setDefaultPageSize(PageSize.A4);

        // 替换参数(如果有参数的话)
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
        fillFormFields(form, formFieldsParams);

        // 锁定表单,不让修改
        form.flattenFields();
        // 关闭资源
        pdf.close();
        // 返回最终结果
        return outputStream.toByteArray();
    }

    /**
     * 获取模版文件路径
     *
     * @param templateFileName 模版文件名,在指定的模版目录下
     * @return 模版文件路径
     */
    private String getTemplatePath(String templateFileName) {
        // 拼接完整模版路径
        return Objects.nonNull(templateDirectory) ?
                templateDirectory   templateFileName : DEFAULT_TEMPLATE_DIRECTORY   templateFileName;
    }

    /**
     * 填充表单域
     *
     * @param form             表单
     * @param formFieldsParams 表单需要的动态参数
     */
    private void fillFormFields(PdfAcroForm form, Map<String, String> formFieldsParams) {
        // 获取所有的表单域
        Map<String, PdfFormField> fields = form.getFormFields();
        // 获取当前字体
        PdfFont currentFont = pdfFont == null ? DEFAULT_FONT : pdfFont;
        formFieldsParams.forEach((key, value) -> {
            // 获取某个表单域
            Optional<PdfFormField> formFieldOptional = Optional.ofNullable(fields.get(key));
            formFieldOptional.ifPresent(formField -> {
                // 设置字体、替换值
                formField.setFont(currentFont).setValue(value);
            });
        });
    }
}

学新通

3.2 测试

准备一个 Controller 类,如下:

package org.feng.controller;

import lombok.extern.slf4j.Slf4j;
import org.feng.pdf.FillFormFieldsToPdfTemplateUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

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

/**
 * itextpdf7控制器
 *
 * @author fengjinsong
 * @date 2023-06-29 09:00:04
 * @version: 1.0
 */
@Controller
@Slf4j
public class ItextPdf7Controller {

    /**
     * 下载文件
     *
     * @param response 响应对象;用于设置响应参数
     */
    @GetMapping("/download")
    public ResponseEntity<byte[]> download(HttpServletResponse response) throws IOException {

        HttpHeaders headers = new HttpHeaders();
        // application/octet-stream二进制流数据(文本下载)。
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

        // 下载显示的文件名,解决中文名称乱码问题
        String downloadFileName = System.currentTimeMillis()   ".pdf";
        // 弹出保存框即资源选择器
        response.setHeader("Content-Disposition", "attachment;filename="   downloadFileName);

        // 组装参数
        Map<String, String> data = new HashMap<>();
        data.put("title", "个人简介");
        data.put("name", "我的某个朋友");
        data.put("age", "30");
        data.put("likes", "女");
        data.put("birthday", "2022-12-22");
        // 使用数据填充pdf模版并转换为字节数组
        FillFormFieldsToPdfTemplateUtil pdfTemplateUtil = new FillFormFieldsToPdfTemplateUtil();
        byte[] bytes = pdfTemplateUtil.generatePdfByteArray("personal_info.pdf", data);

        // 返回结果
        return new ResponseEntity<>(bytes, headers, HttpStatus.CREATED);
    }


    @ResponseBody
    @GetMapping("/generate")
    public String generatePdfFile() throws IOException {

        // 指定输出的目录
        String path = ResourceUtils.getURL("classpath:").getPath()   "/templates/";

        // 组装参数
        Map<String, String> data = new HashMap<>();
        data.put("title", "个人简介");
        data.put("name", "我的某个朋友");
        data.put("age", "30");
        data.put("birthday", "2022-12-22");
        data.put("likes", "女");

        // 在项目中生成pdf
        FillFormFieldsToPdfTemplateUtil pdfTemplateUtil = new FillFormFieldsToPdfTemplateUtil();
        pdfTemplateUtil.generatePdfFile("personal_info.pdf", path   "dsadsad.pdf", data);

        // 返回结果
        return "success";
    }
}
学新通

四、测试结果

在项目中生成pdf文件,发送请求 GET http://localhost:8080/generate
下载生成的pdf文件,发送请求 GET http://localhost:8080/download

生成的pdf效果如下:

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhiabbig
系列文章
更多 icon
同类精品
更多 icon
继续加载