强大!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 的以下特性使其非常适合处理电子签章功能:
-
强大的 PDF 文档创建和编辑功能:PDFBox 支持动态创建、读取和编辑 PDF 文档,适用于各种电子文档操作。
-
内嵌图像与文本支持:通过 PDFBox,用户可以轻松将图片和文本嵌入到 PDF 文档中的指定位置,这为签章和水印功能提供了便利。
-
高效的 PDF 表单解析和填写功能:对于需要生成或修改带有表单域的 PDF 文档,PDFBox 提供了友好的 API,适合在合同或协议等场景中进行签名的自动化处理。
-
多平台支持:作为一个基于 Java 的库,PDFBox 可以在多个操作系统上使用,并且与
Spring Boot
集成良好,特别适合用于服务端处理 PDF 文件。
在本文中,我们将使用 PDFBox
的 PDF 编辑功能,结合 Spring Boot 实现电子签章,并通过前端 Thymeleaf + jQuery + Bootstrap
提供用户友好的操作界面,完成整个电子签章流程。
运行效果:
签名效果:
项目依赖配置
首先,我们需要在 pom.xml
中引入所需依赖,包括 Spring Boot
、PDFBox
以及前端模板引擎 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 文档,添加电子签章,保证了文档的安全性和有效性。