Java-实现PDF合同模板填写内容并导出PDF文件

news2025/7/19 6:34:47

可用于公司用户合同导出pdf文件

效果图

一、导入所需要jar包

        <!--生成PDF-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.11</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.icepdf.os</groupId>
            <artifactId>icepdf-core</artifactId>
            <version>6.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>fontbox</artifactId>
            <version>2.0.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.12</version>
        </dependency>

二、工具类代码实现

package com.example.excel.pdf;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author: reshui
 * description:
 * DateTime:2025/2/25-17:40
 */
@Slf4j
public class PdfTemplateFillUtil {

    /**
     * 文件暂存地址
     */
    public static final String TEMP_FILE_PATH = System.getProperty("java.io.tmpdir");

    /**
     * pdf文件暂存地址
     */
    private static final String FILE_PATH = TEMP_FILE_PATH + File.separator + "generate_pdf";

    /**
     * 时间格式
     */
    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static void main(String[] args) {
        Map<String, Object> paramsMap = new HashMap<String, Object>();
        Map<String, Object> textAreaMap = new HashMap<String, Object>();
        Map<String, Object> imageAreaMap = new HashMap<String, Object>();
        textAreaMap.put("partyAName", "胡图图");
        textAreaMap.put("partyBName", "胡英俊");
        textAreaMap.put("address", "翻斗大街翻斗花园二号楼1001室");
        textAreaMap.put("systemOrderNumber", "Vx2024121315555020011");
        textAreaMap.put("idCard", "44xxxxxxxxxxx132123");
        textAreaMap.put("mobile", "185700xxxxxx");
        textAreaMap.put("remark", "     * BaseFont.NOT_EMBEDDED该参数指定是否将字体嵌入到生成的 PDF 文件中。BaseFont.NOT_EMBEDDED 表示不嵌入字体,即生成的 PDF 文件不会包含字体文件本身,而是依赖于查看 PDF 的设备上是否安装了相应的字体。如果设置为 BaseFont.EMBEDDED,则会将字体文件嵌入到 PDF 中,确保在任何设备上都能正确显示字体,但会增加 PDF 文件的大小。\n");

        String formatDateTime = DateUtil.formatDateTime(new Date());
        textAreaMap.put("now", formatDateTime);
        textAreaMap.put("haha", "你好呀,我是胡图图");

        textAreaMap.put("checkNow", "yes");
        textAreaMap.put("check2", "yes");

        paramsMap.put("textAreaMap", textAreaMap);

        imageAreaMap.put("companySign", "https://profile-avatar.csdnimg.cn/128f2647a3ac408eafb94c7a6706689b_weixin_42477252.jpg!1");
        imageAreaMap.put("signatureImg", "https://profile-avatar.csdnimg.cn/128f2647a3ac408eafb94c7a6706689b_weixin_42477252.jpg!1");
        paramsMap.put("imageAreaMap", imageAreaMap);
        easyGeneratePdf(paramsMap, "C:\\Users\\86138\\Desktop\\xxx\\123.pdf");
    }

    public static void easyGeneratePdf(Map<String, Object> areaMap, String fileName, String readPdfTemplateUrl) {
        String formatDateTimeStamp = DateUtil.format(new Date(), YYYYMMDDHHMMSS);
        String pdfFilePath = FILE_PATH + File.separator + formatDateTimeStamp + StrUtil.UNDERLINE + fileName + ".pdf";
        FileUtil.touch(pdfFilePath);
        generatePdf(areaMap, pdfFilePath, readPdfTemplateUrl);
    }

    public static void easyGeneratePdf(Map<String, Object> areaMap, String readPdfTemplateUrl) {
        String formatDateTimeStamp = DateUtil.format(new Date(), YYYYMMDDHHMMSS);
        String pdfFilePath = FILE_PATH + File.separator + formatDateTimeStamp + ".pdf";
        FileUtil.touch(pdfFilePath);
        generatePdf(areaMap, pdfFilePath, readPdfTemplateUrl);
    }

    /**
     * 模板填充生成PDF
     *
     * @param areaMap                  域集合
     * @param outPutPdfFilePath        输出文件路径
     * @param readPdfTemplateUrlOrPath 读取pdf模板路径
     *                                 Linix 字体
     *                                 BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
     *                                 Windows 字体
     *                                 BaseFont bf = BaseFont.createFont("c://windows//fonts//simsunb.ttf" , BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
     *                                 <p>
     *                                 BaseFont.IDENTITY_H这个参数指定了字符编码。BaseFont.IDENTITY_H 表示使用 Unicode 水平书写方向的编码,这对于支持中文等多语言字符非常重要。如果不使用合适的编码,可能会导致字符显示乱码。
     *                                 BaseFont.NOT_EMBEDDED该参数指定是否将字体嵌入到生成的 PDF 文件中。BaseFont.NOT_EMBEDDED 表示不嵌入字体,即生成的 PDF 文件不会包含字体文件本身,而是依赖于查看 PDF 的设备上是否安装了相应的字体。如果设置为 BaseFont.EMBEDDED,则会将字体文件嵌入到 PDF 中,确保在任何设备上都能正确显示字体,但会增加 PDF 文件的大小。
     */
    protected static synchronized File generatePdf(Map<String, Object> areaMap, String outPutPdfFilePath, String readPdfTemplateUrlOrPath) {
        PdfReader reader;
        FileOutputStream out;
        ByteArrayOutputStream bos;
        PdfStamper stamper;
        PdfTemplateFillConfig config = getSystemType();
        try {
            Document doc = new Document();
            BaseFont bf = BaseFont.createFont(config.getFontName(), config.getEncoding(), config.getEmbedded());
            out = new FileOutputStream(outPutPdfFilePath);// 输出模板
            //读取 PDF 模板
            reader = new PdfReader(readPdfTemplateUrlOrPath);
            bos = new ByteArrayOutputStream();
            // 创建一个 PdfStamper 对象,用于修改 PDF
            stamper = new PdfStamper(reader, bos);
            // 获取 PDF 中的表单域
            AcroFields form = stamper.getAcroFields();
            //文字类的内容处理
            Map<String, String> textAreaMap = (Map<String, String>) areaMap.get("textAreaMap");
            if (Objects.nonNull(textAreaMap) && !textAreaMap.isEmpty()) {
                // 遍历表单数据,将数据填充到对应的表单域中
                for (Map.Entry<String, String> entry : textAreaMap.entrySet()) {
                    String fieldName = entry.getKey();
                    String fieldValue = entry.getValue();
                    if (fieldName.startsWith("check")) {
                        form.setField(fieldName, fieldValue, true);
                    } else {
                        form.setField(fieldName, fieldValue);
                    }
                }
            }
            form.addSubstitutionFont(bf);
            //图片类的内容处理
            Map<String, String> imageAreaMap = (Map<String, String>) areaMap.get("imageAreaMap");
            if (Objects.nonNull(imageAreaMap) && !imageAreaMap.isEmpty()) {
                // 遍历表单数据,将数据填充到对应的表单域中
                for (Map.Entry<String, String> entry : imageAreaMap.entrySet()) {
                    String fieldName = entry.getKey();
                    String fieldValue = entry.getValue();
                    List<AcroFields.FieldPosition> fieldPositions = form.getFieldPositions(fieldName);
                    if (form.getFieldPositions(fieldName) != null) {
                        int pageNo = fieldPositions.get(0).page;
                        Rectangle signRect = fieldPositions.get(0).position;
                        float x = signRect.getLeft();
                        float y = signRect.getBottom();
                        //根据路径读取图片
                        Image image = Image.getInstance(fieldValue);
                        //获取图片页面
                        PdfContentByte under = stamper.getOverContent(pageNo);
                        //图片大小自适应
                        image.scaleToFit(signRect.getWidth(), signRect.getHeight());
                        //添加图片
                        image.setAbsolutePosition(x, y);
                        under.addImage(image);
                    }
                }
            }
            ///*必须要调用这个,否则文档不会生成的  如果为false那么生成的PDF文件还能编辑,一定要设为true*/
            stamper.setFormFlattening(true);
            stamper.close();
            PdfCopy copy = new PdfCopy(doc, out);
            doc.open();
            for (int i = 1; i < reader.getNumberOfPages() + 1; i++) {
                doc.newPage();
                PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), i);
                copy.addPage(importPage);
            }
            doc.close();
            File file = new File(outPutPdfFilePath);
            log.info("pdf文件生成成功,文件路径为:" + file.getAbsolutePath());
            return file;
        } catch (Exception e) {
            log.error("pdf文件生成失败:", e);
        }
        return null;
    }


    public static PdfTemplateFillConfig getSystemType() {
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win")) {
            return PdfTemplateFillConfig.getWindowsInstance();
        } else if (os.contains("nix") || os.contains("nux") || os.contains("aix")) {
            return PdfTemplateFillConfig.getLinuxInstance();
        } else {
            log.error("未知操作系统,无法加载配置。os-{}", os);
            return null;
        }
    }
}
package com.example.excel.pdf;

import lombok.Data;

/**
 * @author: reshui
 * description:
 * DateTime:2025/2/28-15:48
 */
@Data
public class PdfTemplateFillConfig {


    /**
     * 字体名
     */
    private String fontName;

    /**
     * 编码
     */
    private String encoding;

    /**
     * 是否嵌入字体
     * 该参数指定是否将字体嵌入到生成的 PDF 文件中。BaseFont.NOT_EMBEDDED 表示不嵌入字体,即生成的 PDF 文件不会包含字体文件本身,
     * 而是依赖于查看 PDF 的设备上是否安装了相应的字体。如果设置为 BaseFont.EMBEDDED,则会将字体文件嵌入到 PDF 中,确保在任何设备上都能正确显示字体,
     * 但会增加 PDF 文件的大小。
     */
    private Boolean embedded;

    public static PdfTemplateFillConfig getLinuxInstance() {
        PdfTemplateFillConfig config = new PdfTemplateFillConfig();
        config.setFontName("STSong-Light");
        config.setEncoding("UniGB-UCS2-H");
        config.setEmbedded(true);
        return config;
    }

    public static PdfTemplateFillConfig getWindowsInstance() {
        PdfTemplateFillConfig config = new PdfTemplateFillConfig();
        config.setFontName("c://windows//fonts//simsunb.ttf");
        config.setEncoding("Identity-H");
        config.setEmbedded(true);
        return config;
    }
}

三、pdf模板效果

四、实现效果图

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2310046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于STM32的环境监测系统(自制蓝牙APP)

目录 项目概述 实物图 演示视频 概述 硬件模块 原理图以及PCB 0.96寸OLED屏幕&#xff08;SSD1306&#xff09; CubeMX配置 初始化代码 MQ-2烟雾传感器 CubeMX配置 初始化代码 DHT11温湿度模块 驱动代码 HC-05蓝牙模块 CubeMX配置 ​编辑 空闲中断回调函数 有…

月结保障:回滚慢、行锁频发

问题背景 3.1号月结现场保障&#xff0c;到场了先让kill了一个账务的会话&#xff0c;回滚了20min&#xff0c;巡检的时候发现报表库有几条行锁&#xff1a;enq: TX - row lock contention&#xff0c;sql&#xff1a;delete from table_name 语句已经失败&#xff0c;正在回滚…

Golang的微服务服务发现机制

## 1. Golang微服务服务发现机制 微服务架构已经成为当今软件开发的主流趋势&#xff0c;它能将复杂的单体应用拆分成小而独立的服务单元&#xff0c;实现更快的开发、部署和扩展。在微服务架构中&#xff0c;服务发现是非常重要的一环&#xff0c;它能够实现服务之间的自动发现…

Keepalived 入门详解:高可用集群部署最佳实践!

1. 什么是 Keepalived&#xff1f; 在分布式集群中&#xff0c;单点故障&#xff08;SPOF&#xff09; 是影响系统稳定性的重要问题。Keepalived 作为一款高可用服务软件&#xff0c;可以有效防止集群单点故障&#xff0c;保障系统的高可用性。 Keepalived 最初是为 LVS&#…

SparkStreaming之04:调优

SparkStreaming调优 一 、要点 4.1 SparkStreaming运行原理 深入理解 4.2 调优策略 4.2.1 调整BlockReceiver的数量 案例演示&#xff1a; object MultiReceiverNetworkWordCount {def main(args: Array[String]) {val sparkConf new SparkConf().setAppName("Networ…

开发博客系统

前言 准备工作 数据库表分为实体表和关系表 第一&#xff0c;建数据库表 然后导入前端页面 创建公共模块 就是统一返回值&#xff0c;异常那些东西 自己造一个自定义异常 普通类 mapper 获取全部博客 我们只需要返回id&#xff0c;title&#xff0c;content&#xff0c;us…

微信小程序上如何使用图形验证码

1、php服务器生成图片验证码的代码片段如下&#xff1a; 注意红框部分的代码&#xff0c;生成的是ArrayBuffer类型的二进制图片 2、显示验证码 显示验证码&#xff0c;不要直接image组件加上src显示&#xff0c;那样拿不到cookie&#xff0c;没有办法做图形验证码的验证&…

IntelliJ IDEA 构建项目时内存溢出问题

问题现象 在使用 IntelliJ IDEA 构建 Java 项目时&#xff0c;遇到了以下错误&#xff1a; java: java.lang.OutOfMemoryError: Java heap space java.lang.RuntimeException: java.lang.OutOfMemoryError: Java heap space这是一个典型的 Java 堆内存不足错误&#xff0c;表…

大模型微调与RAG检索增强技术深度解析

一、引言 随着人工智能技术的飞速发展&#xff0c;大模型&#xff08;如BERT、GPT等&#xff09;在自然语言处理、计算机视觉等领域取得了显著成效。然而&#xff0c;这些预训练好的大模型往往难以直接应用于特定业务场景&#xff0c;因此&#xff0c;大模型微调&#xff08;F…

[liorf_localization_imuPreintegration-2] process has died

使用liorf&#xff0c;编译没报错&#xff0c;但是roslaunch报错如下&#xff1a; 解决方法&#xff1a; step1: 如果你之前没有安装 GTSAM&#xff0c;可以尝试安装它 step2: 检查是否缺少依赖库 ldd /home/zz/1210/devel/lib/liorf_localization/liorf_localization_imuPr…

2024 年 MySQL 8.0.40 安装配置、Workbench汉化教程最简易(保姆级)

首先到官网上下载安装包&#xff1a;http://www.mysql.com 点击下载&#xff0c;拉到最下面&#xff0c;点击社区版下载 windows用户点击下面适用于windows的安装程序 点击下载&#xff0c;网络条件好可以点第一个&#xff0c;怕下着下着断了点第二个离线下载 双击下载好的安装…

【Python/Pytorch】-- 创建3090Ti显卡所需环境

文章目录 文章目录 01 服务器上&#xff0c;存在三个anaconda&#xff0c;如何选择合适的&#xff0c;创建python环境&#xff1f;02 conda、anaconda、cuda、cudnn区别03 用到一些指令04 如何指定cuda的版本&#xff1f;05 conda跟pip的区别&#xff1f;06 pycharm控制台07 服…

如何在无图形化界面的服务器上下载百度网盘的超大文件(10GB以上)?

目录 登录百度网盘账号 进入特定的文件夹 下载 完整教程 登录百度网盘账号 第一次登录的时候会展示&#xff1a; Please visit: https://openapi.baidu.com/oauth/2.0/authorize?client_idxxx And authorize this app Paste the Authorization Code here within 10 minut…

Linux磁盘情况查询

一、查询系统整体磁盘使用情况 1、基本语法 df -h 2、示例 二、查询指定目录的磁盘占用情况 1、基本语法 du -h 查询指定目录的磁盘占用情况&#xff0c;默认为当前目录 2、常用选项 选项 说明 -h 以人类可读的格式显示磁盘使用情况&#xff08;例如&#xff0c;KB、…

【3D格式转换SDK】HOOPS Exchange技术概览(二):3D数据处理高级功能

​ 在当今数字化工程领域&#xff0c;HOOPS Exchange作为一款强大的SDK&#xff0c;为3D工程应用程序的开发提供了关键支持。本文将深入剖析其基本组件、特定功能以及数据结构&#xff0c;带您全面了解这一驱动3D数据处理的核心工具。 一、概述 HOOPS Exchange专注于访问和重…

利用Adobe Acrobat 实现PPT中图片分辨率的提升

1. 下载适用于 Windows 的 64 位 Acrobat 注册方式参考&#xff1a;https://ca.whu.edu.cn/knowledge.html?type1 2. 将ppt中需要提高分辨率的图片复制粘贴到新建的pptx问价中&#xff0c;然后执行“文件—>导出---->创建PDF、XPS文档” 3. 我们会发现保存下来的distrib…

Elasticsearch:解锁深度匹配,运用Elasticsearch DSL构建闪电般的高效模糊搜索体验

目录 Elasticsearch查询分类 叶子查询 全文检索查询 match查询 multi_match查询 精确查询 term查询 range查询 复杂查询 bool查询简单应用 bool查询实现排序和分页 bool查询实现高亮 场景分析 问题思考 解决方案 search_after方案(推荐) point in time方案 方案…

解决局域网访问Dify却仅显示nginx页面的问题

为什么dify在本机可以正常访问&#xff0c;局域网通过ip访问却只看到欢迎使用nginx的提示&#xff0c;如果访问服务器ip/apps则直接提示404 Not Found。这是怎么回事该如何解决呢&#xff1f;文章中将一步步解决这些问题。 前言 之前在服务器部署了dify&#xff0c;也在服务器…

从小米汽车召回看智驾“命门”:智能化时代 — 时间就是安全

2025年1月&#xff0c;小米因车辆“授时同步异常”召回3万余辆小米SU7&#xff0c;成为其造车历程中的首个重大安全事件。 从小米SU7召回事件剖析&#xff0c;授时同步何以成为智能驾驶的命门&#xff1f; 2024年11月&#xff0c;多名车主反馈SU7标准版的智能泊车辅助功能出现…

OpenAI 最后一代非推理模型:OpenAI 发布 GPT-4.5预览版

最后一代非推理大模型 在人工智能领域&#xff0c;OpenAI 一直以其创新的技术和卓越的产品引领着行业的发展。近期&#xff0c;OpenAI 正式发布了 GPT-4.5 研究预览版。不仅如此&#xff0c;官方还宣称 GPT-4.5 被定位为 “最后一代非推理模型”&#xff0c;这一消息再次引起了…