当前位置: 首页 > news >正文

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是一个开源的监控和数据可视化平台&#xff0c;主要用于展示和分析时间序列数据。提供功能强大且灵活的数据可视化和监控工具&#xff0c;适用于多种场景&#xff0c;它广泛应用于DevOps、IT运维、物联网&#xff08;IoT&#xff09;和业务分析等领域。 Grafana的主…...

MyBatis-Plus 自动填充功能

MyBatis-Plus&#xff08;MP&#xff09; 提供了一个非常强大的功能——自动填充功能。该功能可以在执行插入或更新操作时&#xff0c;自动为某些字段赋值&#xff0c;免去手动设置这些字段的麻烦。常见的应用场景包括 创建时间 和 更新时间 字段的自动填充&#xff0c;帮助开发…...

解决redis lettuce连接池经常出现连接拒绝(Connection refused)问题

一.软件环境 windows10、11系统、springboot2.x、redis 6 7 linux&#xff08;centos&#xff09;系统没有出现这问题&#xff0c;如果你是linux系统碰到的&#xff0c;本文也有一定大参考价值。 根本思路就是&#xff1a;tcp/ip连接的保活(keepalive)。 二.问题描述 在spr…...

武汉大学生命科学学院与谱度众合(武汉)生命科技有限公司举行校企联培座谈会

2025年2月21日下午&#xff0c;武汉大学生命科学学院与谱度众合&#xff08;武汉&#xff09;生命科技有限公司&#xff08;以下简称“谱度众合”&#xff09;在学院学术厅举行校企联培专业学位研究生合作交流会。武汉大学生命科学学院副院长刘星教授、生命科学学院周宇教授、产…...

4.网络技术与应用

一、计算机网络基础 1. 网络基本原理 通信模型&#xff1a; OSI七层模型&#xff1a; 物理层&#xff08;传输比特流&#xff0c;如网线、光纤&#xff09;数据链路层&#xff08;MAC地址&#xff0c;交换机&#xff09;网络层&#xff08;IP地址&#xff0c;路由器&#xff0…...

Kafka 主题 retention.ms 配置修改及深度问题排查指南

文章目录 Kafka 主题 retention.ms 配置修改及深度问题排查指南版本背景查看 Kafka 主题当前状态修改 retention.ms 配置的正确方式为什么不能使用 kafka-topics.sh&#xff1f;使用 kafka-configs.sh 动态更新配置 深入解析 retention 配置retention.ms 与 retention.bytes 的…...

React实现无缝滚动轮播图

实现效果&#xff1a; 由于是演示代码&#xff0c;我是直接写在了App.tsx里面在 文件位置如下&#xff1a; App.tsx代码如下&#xff1a; import { useState, useEffect, useCallback, useRef } from "react"; import { ImageContainer } from "./view/ImageC…...

deepseek+mermaid【自动生成流程图】

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

分布式锁的简单实现

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

C语言(19)----------->函数(2)

本文介绍了C语言的return语句及其它在C语言函数中的作用&#xff0c;以及介绍了二维数组和一维数组传参时的一些注意事项和使用数组传参时的方法。 若没有学习过C语言的一维数组和二维数组&#xff0c;建议参考如下文章&#xff1a; C语言&#xff08;15&#xff09;--------…...

动态扩缩容引发的JVM堆内存震荡:从原理到实践的GC调优指南

目录 一、典型案例&#xff1a;系统发布后的GC雪崩事件 &#xff08;一&#xff09;故障现象 1. 刚刚启动时 GC 次数较多 2. 堆内存锯齿状波动 3. GC日志特征&#xff1a;Allocation Failure &#xff08;二&#xff09;问题定位 二、原理深度解析&#xff1a;JVM内存弹…...

为何在用户注销时使用 location.href 而非 Vue Router 的 router.push

在开发 Web 应用时&#xff0c;用户注销功能的设计看似简单&#xff0c;但背后隐藏着对状态管理、安全性和用户体验的深层考量。以下将详细探讨为何许多项目在注销跳转时选择 location.href&#xff08;强制刷新页面&#xff09;而非 Vue Router 的 router.push&#xff08;单页…...

开源工具推荐:Uptime Kuma监控

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

《基于Selenium的论坛系统自动化测试实战报告》

一、项目背景与技术选型 项目简介 目标系统&#xff1a;论坛系统 核心功能&#xff1a;用户注册/登录、会话框发送信息、好友列表、信息发送 技术栈&#xff1a;html Springboot MySQL数据库 为什么选择Selenium 支持多浏览器兼容性测试&#xff08;Chrome/Firefox/Edge&…...

深入解析SQL Server高级SQL技巧

SQL Server 是一种功能强大的关系型数据库管理系统&#xff0c;广泛应用于各种数据驱动的应用程序中。在开发过程中&#xff0c;掌握一些高级SQL技巧&#xff0c;不仅能提高查询性能&#xff0c;还能优化开发效率。这篇文章将全面深入地探讨SQL Server中的一些高级技巧&#xf…...

分布式中间件:环境准备

在当今数字化的时代&#xff0c;分布式系统已经成为了开发领域的主流。分布式中间件在其中扮演着至关重要的角色&#xff0c;它能够帮助我们更好地处理高并发、高可用等复杂的业务场景。在这个系列的博客中&#xff0c;我将带大家深入学习分布式中间件的相关知识&#xff0c;主…...

c# winform程序 vs2022 打包生成安装包

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

探索Elasticsearch:文档的CRUD

在企业环境中&#xff0c;Elasticsearch对文档操作的支持不仅是实现高效搜索的关键&#xff0c;更是数据驱动决策的重要支柱。它通过强大的索引机制和灵活的查询语言&#xff0c;使企业能够实时处理和分析海量文档数据&#xff0c;迅速获取有价值的洞察&#xff0c;从而加速创新…...

面试基础--Spring Boot启动流程及源码实现

深度解析Spring Boot启动流程及源码实现 一、Spring Boot启动全景图&#xff08;含核心阶段&#xff09; #mermaid-svg-dYTQ6WPa3o6vKFHh {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-dYTQ6WPa3o6vKFHh .error-i…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

API网关Kong的鉴权与限流:高并发场景下的核心实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中&#xff0c;API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关&#xff0c;Kong凭借其插件化架构…...