强大!Spring Boot 3.3 集成 PDFBox 轻松实现电子签章功能!

强大!Spring Boot 3.3 集成 PDFBox 轻松实现电子签章功能!

随着数字化办公和电子合同的普及,PDF 文档已经成为很多业务场景中的标准文件格式。为了确保文档的安全性和法律效力,电子签章技术应运而生。电子签章不仅可以证明文件的真实性,还能防止文件被篡改。在本文中,我们将详细讲解如何使用 Spring Boot 3.3 与 Apache PDFBox 集成,来实现电子签章功能。我们将结合 PDFBox 这一强大的 PDF 处理库,并通过 jQuery + Bootstrap 实现前端文件上传和结果展示的功能。

PDFBox 框架简介

Apache PDFBox 是一个开放源码的 Java 库,专门用于创建、操作和编辑 PDF 文件。它为开发人员提供了丰富的 PDF 操作功能,包括创建 PDF、解析 PDF 文本、操作图像以及表单数据等。PDFBox 的以下特性使其非常适合处理电子签章功能:

  1. 强大的 PDF 文档创建和编辑功能:PDFBox 支持动态创建、读取和编辑 PDF 文档,适用于各种电子文档操作。

  2. 内嵌图像与文本支持:通过 PDFBox,用户可以轻松将图片和文本嵌入到 PDF 文档中的指定位置,这为签章和水印功能提供了便利。

  3. 高效的 PDF 表单解析和填写功能:对于需要生成或修改带有表单域的 PDF 文档,PDFBox 提供了友好的 API,适合在合同或协议等场景中进行签名的自动化处理。

  4. 多平台支持:作为一个基于 Java 的库,PDFBox 可以在多个操作系统上使用,并且与 Spring Boot 集成良好,特别适合用于服务端处理 PDF 文件。

在本文中,我们将使用 PDFBox 的 PDF 编辑功能,结合 Spring Boot 实现电子签章,并通过前端 Thymeleaf + jQuery + Bootstrap 提供用户友好的操作界面,完成整个电子签章流程。

运行效果:

签名效果:

项目依赖配置

首先,我们需要在 pom.xml 中引入所需依赖,包括 Spring BootPDFBox 以及前端模板引擎 Thymeleaf。这些依赖提供了 PDF 操作、Web 服务和前端渲染等功能。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.icoderoad</groupId><artifactId>signature</artifactId><version>0.0.1-SNAPSHOT</version><name>signature</name><description>Demo project for Spring Boot</description><properties><java.version>17</java.version><pdfbox.version>3.0.3</pdfbox.version></properties><dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot Starter Thymeleaf --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- PDFBox for PDF manipulation --><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>${pdfbox.version}</version></dependency><!-- Lombok (optional for simplifying Java code) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

配置文件

为方便管理电子签章相关的参数配置,我们可以使用 application.yml 文件存储如签章图片路径、签章字体大小以及签章位置等属性。

server:port: 8080spring:servlet:multipart:max-file-size: 50MB  # 单个文件最大上传大小max-request-size: 50MB  # 总的请求最大大小signature:upload_dir: /Users/icoderoad/signature/upload/image-path: src/main/resources/static/images/signature.pngfont-size: 12signature-position-x: 300signature-position-y: 620

接下来,创建 SignatureProperties 配置类,使用 @ConfigurationProperties 注解来读取这些配置。

package com.icoderoad.signature.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import lombok.Data;@Data
@Component
@ConfigurationProperties(prefix = "signature")
public class SignatureProperties {private String uploadDir;private String imagePath;private int fontSize;private float signaturePositionX;private float signaturePositionY;}

配置类

package com.icoderoad.signature.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate SignatureProperties signatureProperties;@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {// 配置静态资源路径,使得上传文件可以通过 /upload 访问String uploadDir = "file:" + signatureProperties.getUploadDir();registry.addResourceHandler("/upload/**").addResourceLocations(uploadDir);}
}

签章服务实现

PdfSignatureService 是核心业务逻辑类,主要职责是通过 PDFBox 在指定的 PDF 文件上添加签章。通过 PDImageXObject 来加载签章图片,并通过 PDPageContentStream 将图片绘制在 PDF 文件的指定位置。

package com.icoderoad.signature.service;import java.io.File;
import java.io.IOException;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.icoderoad.signature.config.SignatureProperties;@Service
public class PdfSignatureService {@Autowiredprivate SignatureProperties signatureProperties;// 实现PDF签章public void signPdf(String inputPdfPath, String outputPdfPath) throws IOException {File file = new File(inputPdfPath);try (PDDocument document = PDDocument.load(file)) {// 获取签章图片PDImageXObject pdImage = PDImageXObject.createFromFile(signatureProperties.getImagePath(), document);float imageWidth = 100; // 设置签章图片的宽度float imageHeight = 50; // 设置签章图片的高度// 遍历所有页面for (PDPage page : document.getPages()) {float pageWidth = page.getMediaBox().getWidth();float pageHeight = page.getMediaBox().getHeight();// 计算签章位置:页面右下角float x = pageWidth - imageWidth - 20; // 右边距20float y = 70; // 下边距20// 为每个页面创建一个新的内容流以添加签名try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {// 绘制签章图片contentStream.drawImage(pdImage, x, y, imageWidth, imageHeight);}}document.save(outputPdfPath); // 保存修改后的PDF}}
}

控制器实现

控制器 PdfController 负责处理来自前端的文件上传请求,调用 PdfSignatureService 实现 PDF 文件的签章,并返回结果给前端。

package com.icoderoad.signature.controller;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;import com.icoderoad.signature.config.SignatureProperties;
import com.icoderoad.signature.service.PdfSignatureService;@Controller
public class PdfController {@Autowiredprivate PdfSignatureService pdfSignatureService;@Autowiredprivate SignatureProperties signatureProperties;@GetMapping("/")public String index() {return "index";}@PostMapping("/uploadAndSignPdf")@ResponseBodypublic ResponseEntity<Object> uploadAndSignPdf(@RequestParam("file") MultipartFile file) {if (file.isEmpty()) {return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("{\"message\": \"文件上传失败,文件为空\"}");}try {// 保存上传文件到服务器File uploadedFile = saveUploadedFile(file);// 创建签章后的PDF保存路径String signedPdfPath = signatureProperties.getUploadDir() + "signed_" + file.getOriginalFilename();// 调用 PdfSignatureService 进行签章pdfSignatureService.signPdf(uploadedFile.getAbsolutePath(), signedPdfPath);// 返回成功信息给前端return ResponseEntity.status(HttpStatus.OK).body("{\"message\": \"文件签章成功\", \"signedPdf\": \"/upload/signed_" + file.getOriginalFilename() + "\"}");} catch (IOException e) {e.printStackTrace();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"message\": \"文件处理失败\"}");}}// 保存上传的文件到服务器本地private File saveUploadedFile(MultipartFile file) throws IOException {File destFile = new File(signatureProperties.getUploadDir() + file.getOriginalFilename());try (InputStream inputStream = file.getInputStream();FileOutputStream outputStream = new FileOutputStream(destFile)) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}}return destFile;}
}

前端实现

前端界面使用 Thymeleaf 渲染,并通过 jQuery 处理文件上传操作。在文件上传成功后,页面将展示签章结果的链接,供用户下载签章后的 PDF 文件。

在 src/main/resources/templates 目录下创建 index.html 文件:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>电子签章</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"><script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body><div class="container mt-5"><h2>上传PDF文件进行签章</h2><form id="uploadForm" enctype="multipart/form-data"><div class="mb-3"><input type="file" class="form-control" name="file" id="file" required></div><button type="submit" class="btn btn-primary">上传并签章</button></form><!-- 显示签章结果 --><div id="resultMessage" class="mt-3" style="display: none;"><p id="message"></p><a id="downloadLink" href="#" target="_blank">下载签章后的 PDF</a></div></div><script>$(document).ready(function() {$('#uploadForm').submit(function(event) {event.preventDefault();var formData = new FormData();formData.append('file', $('#file')[0].files[0]);$.ajax({url: '/uploadAndSignPdf',type: 'POST',data: formData,processData: false,contentType: false,success: function(jsonResponse) {response = JSON.parse(jsonResponse); $('#message').text(response.message);$('#downloadLink').attr('href', response.signedPdf);$('#resultMessage').show();},error: function(xhr) {$('#message').text('签章失败:' + xhr.responseText);$('#resultMessage').show();}});});});</script>
</body>
</html>

总结

本文详细讲解了如何通过 Spring Boot 3.3 与 Apache PDFBox 实现电子签章功能,并展示了如何通过 jQuery 实现前端文件上传和结果展示。PDFBox 的强大功能使我们能够灵活地操作 PDF 文档,添加电子签章,保证了文档的安全性和有效性。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频美颜平台的搭建指南:基于直播美颜SDK的完整解决方案

众所周知&#xff0c;直播美颜SDK是实现视频美颜功能的核心。本文将详细解析如何基于直播美颜SDK搭建一个完整的视频美颜平台。 一、视频美颜SDK的核心功能 直播美颜SDK作为平台的技术核心&#xff0c;能够提供丰富的美颜效果和稳定的视频处理能力。通常&#xff0c;SDK具备以…

传输层TCP

报头 1.报头和有效载荷如何分离将&#xff0c;有效载荷向上交付&#xff1f; tcp有个标准报头长度为20&#xff0c;那是不是以为我们可以像udp一样分离依靠报头大小去分离&#xff0c;我们仔细去看我们报头中还有个选项没包含到。 我们还有个首部长度&#xff0c;四位可以表…

【Axure高保真原型】分级树筛选中继器表格

今天和大家分享分级树筛选中继器表格的原型模板&#xff0c;点击树的箭头可以展开或者收起子级内容&#xff0c;点击内容&#xff0c;可以筛选出该内容及子级内容下所有的表格数据。左侧的树和右侧的表格都是用中继器制作的&#xff0c;所以使用也很方便&#xff0c;只需要在中…

SwiftUI:单个App支持设置多语言

SwiftUI 全新多语言方案 简化本地化的字符串- WWDC21 - 视频 本地化您的SwiftUI app - WWDC21 - 视频 构建全球化App&#xff1a;本地化的示例- WWDC22 - 视频 构建支持多语言的App - WWDC24 - 视频 单个App支持设置多语言 工程 Info.plist里添加 键值UIPrefersShowingLangua…

论1+2+3+4+... = -1/12 的不同算法

我们熟知自然数全加和&#xff0c; 推导过程如下&#xff0c; 这个解法并不难&#xff0c;非常容易看懂&#xff0c;但是并不容易真正理解。正负交错和无穷项计算&#xff0c;只需要保持方程的形态&#xff0c;就可以“预知”结果。但是这到底说的是什么意思&#xff1f;比如和…

【AI换装整合及教程】CatVTON:时尚与科技的完美融合

在当今数字化时代&#xff0c;时尚行业正经历着一场前所未有的变革&#xff0c;而 CatVTON 作为一款由中山大学、Pixocial 等机构联合研发的轻量化 AI 虚拟换装工具&#xff0c;无疑是这场变革中的璀璨明星。 一、独特的技术架构 CatVTON 基于 Stable Diffusion v1.5 inpainit…

css 切角实现(全)

效果 样式代码 <template><div class"container"><div class"clip-all-angle"> 4个角全部剪切 </div><div class"clip-two-angle"> 切底部两个角 </div><div class"clip-two-top-angle"> …

新鲜出炉,ECCV2024.9.25 首次提出基于 YOLO 目标检测的无源域自适应

原文标题&#xff1a;Source-Free Domain Adaptation for YOLO Object Detection 中文标题&#xff1a;基于 YOLO 目标检测的无源域自适应 论文地址&#xff1a; https://arxiv.org/abs/2409.16538 代码地址&#xff1a; GitHub - vs-cv/sf-yolo 1、Abstract 无源域自适应&…

ACL访问控制

要求&#xff1a; PC1与PC2不能通信。PC1可以和PC3通信。PC2可以和PC3通信。 1. VLAN配置 根据拓扑图的连接&#xff0c;PC1、PC2、PC3属于不同的VLAN。我们需要确保交换机上的端口已经正确划分到不同的VLAN。假设交换机接口的VLAN配置已经完成&#xff08;其他博文有)&…

【Linux】线程池详解及其基本架构与单例模式实现

目录 1.关于线程池的基本理论 1.1.线程池是什么&#xff1f; 1.2.线程池的应用场景&#xff1a; 2.线程池的基本架构 2.1.线程容器 2.2.任务队列 2.3.线程函数&#xff08;HandlerTask&#xff09; 2.4.线程唤醒机制 3.添加单例模式 3.1.单例模式是什么&…

多IP访问网站

1.创建挂载点 mount /dev/sr0 /mnt vim /etc/yum.repos.d/base.repo [BaseOS] nameBaseOS baseurlfile:///mnt/BaseOS gpgcheck0 [Appstream] nameAppStream baseurlfile:///mnt/AppStream gpgcheck0 2.关闭防火墙等 systemctl stop firewalld setenforce 0 3.下载nginx…

【我的 PWN 学习手札】setcontext + shellcode

目录 一、setcontext gadget 二、setcontext shellcode &#xff08;一&#xff09;覆写__free_hook为setcontext53 &#xff08;二&#xff09;在堆块布置了一块sigframe &#xff08;三&#xff09;覆写__free_hook0x8__free_hook0x10 &#xff08;四&#xff09;从__…

流媒体协议.之(RTP,RTCP,RTSP,RTMP,HTTP)(一)

闲着没事做&#xff0c;记录一下开发项目用过的协议&#xff0c;项目中&#xff0c;大多是是实时显示播放的&#xff0c;通过私有协议&#xff0c;传输到上位机&#xff0c;实时播放&#xff0c;延时小于200ms&#xff0c;仿照这些协议&#xff0c;定义的数据格式。如果用这些协…

新王Claude 3.5的6大应用场景

Anthropic AI深夜发布了备受期待的Claude 3.5系列更新&#xff0c;包括了全新升级的Claude 3.5 Sonnet和首发的Claude 3.5 Haiku。 Claude 3.5 Sonnet能够理解细微的指令和上下文&#xff0c;识别并纠正自身错误&#xff0c;还能从复杂数据中生成深入的分析和洞察。 结合最先进…

10.22.2024刷华为OD C题型(三)--for循环例子

脚踝动了手术&#xff0c;现在宾馆恢复&#xff0c;伤筋动骨一百天还真不是说笑的&#xff0c;继续努力吧。 文章目录 靠谱的车灰度图恢复灰度图恢复 -- for循环使用例子 靠谱的车 https://www.nowcoder.com/discuss/564514429228834816 这个题目思路不难&#xff0c;就是要自…

手把手教你安装最强文生图工具ComfyUI

ComfyUI 是一款专为稳定扩散&#xff08;Stable Diffusion&#xff09;设计、基于节点的高效用户界面&#xff0c;因其高度的可定制性&#xff0c;正逐渐成为广大用户的新宠。本文教你如何在 Windows 和 Mac 上安装 ComfyUI&#xff0c;并提供一些快速上手的小贴士。 1 ComfyU…

【mysql进阶】4-7. 通用表空间

通⽤表空间 - General Tablespace 1 通⽤表空间的作⽤和特性&#xff1f; ✅ 解答问题 通⽤表空间是使⽤ CREATE tablespace 语法创建的共享InnoDB表空间 通⽤表空间能够存储多个表的数据&#xff0c;与系统表空间类似也是共享表空间&#xff1b; 服务器运⾏时会把表空间元数…

python爬虫——Selenium的基本使用

目录 一、Selenium的介绍 二、环境准备 1.安装Selenium 2.安装WebDriver 三、元素定位 1.常用定位元素的方法 2. 通过指定方式定位元素 四、窗口操作 1.最大化浏览器窗口 2.设置浏览器窗口大小 3.切换窗口或标签页 切换回主窗口 4. 关闭窗口 关闭当前窗口 关闭所…

博客搭建之路:hexo增加搜索功能

文章目录 hexo增加搜索功能本地搜索弊端algolia搜索 hexo增加搜索功能 hexo版本5.0.2 npm版本6.14.7 next版本7.8.0 作为一个博客&#xff0c;没有搜索功能&#xff0c;如何在大批文章中找到自己想要的&#xff0c;那在hexo中如何增加搜索功能呢&#xff1f; search:path: sea…

用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(一)

概述 从 WWDC 24 开始&#xff0c;苹果推出了全新的测试机制&#xff1a;Swift Testing。利用它我们可以大幅度简化之前“老态龙钟”的 XCTest 编码范式&#xff0c;并且使得单元测试更加灵动自由&#xff0c;更符合 Swift 语言的优雅品味。 在这里我们会和大家一起初涉并领略…