随着数字化办公和电子合同的普及,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: 8080
spring:
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.png
font-size: 12
signature-position-x: 300
signature-position-y: 620
接下来,创建 SignatureProperties
配置类,使用 @ConfigurationProperties
注解来读取这些配置。
@Data
@Component
@ConfigurationProperties(prefix = "signature")
public class SignatureProperties {
private String uploadDir;
private String imagePath;
private int fontSize;
private float signaturePositionX;
private float signaturePositionY;
}
配置类
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private SignatureProperties signatureProperties;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 配置静态资源路径,使得上传文件可以通过 /upload 访问
String uploadDir = "file:" + signatureProperties.getUploadDir();
registry.addResourceHandler("/upload/**")
.addResourceLocations(uploadDir);
}
}
签章服务实现
PdfSignatureService
是核心业务逻辑类,主要职责是通过 PDFBox
在指定的 PDF 文件上添加签章。通过 PDImageXObject
来加载签章图片,并通过 PDPageContentStream
将图片绘制在 PDF 文件的指定位置。
@Service
public class PdfSignatureService {
@Autowired
private 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; // 右边距20
float 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 文件的签章,并返回结果给前端。
@Controller
public class PdfController {
@Autowired
private PdfSignatureService pdfSignatureService;
@Autowired
private SignatureProperties signatureProperties;
@GetMapping("/")
public String index() {
return "index";
}
@PostMapping("/uploadAndSignPdf")
@ResponseBody
public 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 文档,添加电子签章,保证了文档的安全性和有效性。
来源:https://mp.weixin.qq.com/s/bJTk9e-5UWNDqY9vMYbJXA
没有回复内容