Java-实现PDF合同模板填写内容并导出PDF文件
可用于公司用户合同导出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 对象,用于修改 PDFstamper = 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模板效果
四、实现效果图
相关文章:

Java-实现PDF合同模板填写内容并导出PDF文件
可用于公司用户合同导出pdf文件 效果图 一、导入所需要jar包 <!--生成PDF--><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.11</version></dependency><dependency&…...

Docker安装Grafana数据可视化平台
介绍 Grafana是一个开源的监控和数据可视化平台,主要用于展示和分析时间序列数据。提供功能强大且灵活的数据可视化和监控工具,适用于多种场景,它广泛应用于DevOps、IT运维、物联网(IoT)和业务分析等领域。 Grafana的主…...
MyBatis-Plus 自动填充功能
MyBatis-Plus(MP) 提供了一个非常强大的功能——自动填充功能。该功能可以在执行插入或更新操作时,自动为某些字段赋值,免去手动设置这些字段的麻烦。常见的应用场景包括 创建时间 和 更新时间 字段的自动填充,帮助开发…...

解决redis lettuce连接池经常出现连接拒绝(Connection refused)问题
一.软件环境 windows10、11系统、springboot2.x、redis 6 7 linux(centos)系统没有出现这问题,如果你是linux系统碰到的,本文也有一定大参考价值。 根本思路就是:tcp/ip连接的保活(keepalive)。 二.问题描述 在spr…...

武汉大学生命科学学院与谱度众合(武汉)生命科技有限公司举行校企联培座谈会
2025年2月21日下午,武汉大学生命科学学院与谱度众合(武汉)生命科技有限公司(以下简称“谱度众合”)在学院学术厅举行校企联培专业学位研究生合作交流会。武汉大学生命科学学院副院长刘星教授、生命科学学院周宇教授、产…...
4.网络技术与应用
一、计算机网络基础 1. 网络基本原理 通信模型: OSI七层模型: 物理层(传输比特流,如网线、光纤)数据链路层(MAC地址,交换机)网络层(IP地址,路由器࿰…...
Kafka 主题 retention.ms 配置修改及深度问题排查指南
文章目录 Kafka 主题 retention.ms 配置修改及深度问题排查指南版本背景查看 Kafka 主题当前状态修改 retention.ms 配置的正确方式为什么不能使用 kafka-topics.sh?使用 kafka-configs.sh 动态更新配置 深入解析 retention 配置retention.ms 与 retention.bytes 的…...

React实现无缝滚动轮播图
实现效果: 由于是演示代码,我是直接写在了App.tsx里面在 文件位置如下: App.tsx代码如下: import { useState, useEffect, useCallback, useRef } from "react"; import { ImageContainer } from "./view/ImageC…...

deepseek+mermaid【自动生成流程图】
成果: 第一步打开deepseek官网(或百度版(更快一点)): 百度AI搜索 - 办公学习一站解决 第二步,生成对应的Mermaid流程图: 丢给deepseek代码,或题目要求 生成mermaid代码 第三步将代码复制到me…...

分布式锁的简单实现
1. 什么是分布式锁? 在分布式系统中,也会涉及到多个节点访问同一个公共资源的情况,和 Java 中多线程的锁不一样,由于分布式系统中涉及到多个进程多个主机,所以说 Java 中 synchronized 就不合适了。 2. 分布式锁的简…...

C语言(19)----------->函数(2)
本文介绍了C语言的return语句及其它在C语言函数中的作用,以及介绍了二维数组和一维数组传参时的一些注意事项和使用数组传参时的方法。 若没有学习过C语言的一维数组和二维数组,建议参考如下文章: C语言(15)--------…...

动态扩缩容引发的JVM堆内存震荡:从原理到实践的GC调优指南
目录 一、典型案例:系统发布后的GC雪崩事件 (一)故障现象 1. 刚刚启动时 GC 次数较多 2. 堆内存锯齿状波动 3. GC日志特征:Allocation Failure (二)问题定位 二、原理深度解析:JVM内存弹…...
为何在用户注销时使用 location.href 而非 Vue Router 的 router.push
在开发 Web 应用时,用户注销功能的设计看似简单,但背后隐藏着对状态管理、安全性和用户体验的深层考量。以下将详细探讨为何许多项目在注销跳转时选择 location.href(强制刷新页面)而非 Vue Router 的 router.push(单页…...

开源工具推荐:Uptime Kuma监控
1. 概述 Github:louislam/uptime-kuma: A fancy self-hosted monitoring tool Uptime Kuma is an easy-to-use self-hosted monitoring tool. Uptime Kuma 是一款开源的监控工具,可以帮助你实时监测网站或服务的状态,并在发生故障时及时通…...

《基于Selenium的论坛系统自动化测试实战报告》
一、项目背景与技术选型 项目简介 目标系统:论坛系统 核心功能:用户注册/登录、会话框发送信息、好友列表、信息发送 技术栈:html Springboot MySQL数据库 为什么选择Selenium 支持多浏览器兼容性测试(Chrome/Firefox/Edge&…...
深入解析SQL Server高级SQL技巧
SQL Server 是一种功能强大的关系型数据库管理系统,广泛应用于各种数据驱动的应用程序中。在开发过程中,掌握一些高级SQL技巧,不仅能提高查询性能,还能优化开发效率。这篇文章将全面深入地探讨SQL Server中的一些高级技巧…...
分布式中间件:环境准备
在当今数字化的时代,分布式系统已经成为了开发领域的主流。分布式中间件在其中扮演着至关重要的角色,它能够帮助我们更好地处理高并发、高可用等复杂的业务场景。在这个系列的博客中,我将带大家深入学习分布式中间件的相关知识,主…...

c# winform程序 vs2022 打包生成安装包
最近,利用c# winform程序该客户开发一套进销存管理系统,项目在部署前,需要生成安装包,以便部署在客户电脑上面。总结步骤如下: 1、在打包之前 (VS中需要包括Microsoft visual studio installer projects扩展项目)&…...

探索Elasticsearch:文档的CRUD
在企业环境中,Elasticsearch对文档操作的支持不仅是实现高效搜索的关键,更是数据驱动决策的重要支柱。它通过强大的索引机制和灵活的查询语言,使企业能够实时处理和分析海量文档数据,迅速获取有价值的洞察,从而加速创新…...
面试基础--Spring Boot启动流程及源码实现
深度解析Spring Boot启动流程及源码实现 一、Spring Boot启动全景图(含核心阶段) #mermaid-svg-dYTQ6WPa3o6vKFHh {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-dYTQ6WPa3o6vKFHh .error-i…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...

毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...