pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.yalong</groupId>
<artifactId>verifyPdf</artifactId>
<version>1.0-SNAPSHOT</version> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<lombok.version>1.18.10</lombok.version> </properties>
<dependencies>
<!-- <dependency>-->
<!-- <groupId> e-iceblue </groupId>-->
<!-- <artifactId>spire.pdf</artifactId>-->
<!-- <version>3.4.2</version>-->
<!-- </dependency>-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.pdf.free</artifactId>
<version>2.6.3</version>
</dependency> <dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies> <repositories>
<repository>
<id>com.e-iceblue</id>
<url>http://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
</project>

VerifySignature.java

import com.spire.pdf.PdfDocument;
import com.spire.pdf.security.PdfCertificate;
import com.spire.pdf.security.PdfSignature;
import com.spire.pdf.widget.PdfFormFieldWidgetCollection;
import com.spire.pdf.widget.PdfFormWidget;
import com.spire.pdf.widget.PdfSignatureFieldWidget;
import lombok.Data;
import lombok.ToString;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.xssf.streaming.SXSSFWorkbook; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;
import java.awt.*; @Data
@ToString
class ExcelDataVO implements Serializable {
private String fileName;
private String signDate;
private String validBefore;
private String validAfter;
private String subject;
private String serialNumber;
private Boolean isEffective = false; } class ExcelWriter { //表头
private static final List<String> CELL_HEADS; static {
// 类装载时就载入指定好的表头信息,如有需要,可以考虑做成动态生成的表头
CELL_HEADS = new ArrayList<>();
CELL_HEADS.add("文件名");
CELL_HEADS.add("签名时间");
CELL_HEADS.add("有效期");
CELL_HEADS.add("有效期");
CELL_HEADS.add("签名机构");
CELL_HEADS.add("序列号");
CELL_HEADS.add("是否通过验签");
} /**
* 生成Excel并写入数据信息
*
* @param dataList 数据列表
* @return 写入数据后的工作簿对象
*/
public static Workbook exportData(List<ExcelDataVO> dataList) {
// 生成xlsx的Excel
Workbook workbook = new SXSSFWorkbook(); // 如需生成xls的Excel,请使用下面的工作簿对象,注意后续输出时文件后缀名也需更改为xls
//Workbook workbook = new HSSFWorkbook(); // 生成Sheet表,写入第一行的表头
Sheet sheet = buildDataSheet(workbook);
//构建每行的数据内容
int rowNum = 1;
for (ExcelDataVO data : dataList) {
if (data == null) {
continue;
}
//输出行数据
Row row = sheet.createRow(rowNum++);
convertDataToRow(workbook, data, row);
}
return workbook;
} /**
* 生成sheet表,并写入第一行数据(表头)
*
* @param workbook 工作簿对象
* @return 已经写入表头的Sheet
*/
private static Sheet buildDataSheet(Workbook workbook) {
Sheet sheet = workbook.createSheet();
// 设置表头宽度
for (int i = 0; i < CELL_HEADS.size(); i++) {
sheet.setColumnWidth(i, 4000);
}
// 设置默认行高
sheet.setDefaultRowHeight((short) 400);
// 构建头单元格样式
CellStyle cellStyle = buildHeadCellStyle(sheet.getWorkbook());
// 写入第一行各列的数据
Row head = sheet.createRow(0);
for (int i = 0; i < CELL_HEADS.size(); i++) {
Cell cell = head.createCell(i);
cell.setCellValue(CELL_HEADS.get(i));
cell.setCellStyle(cellStyle);
}
return sheet;
} /**
* 设置第一行表头的样式
*
* @param workbook 工作簿对象
* @return 单元格样式对象
*/
private static CellStyle buildHeadCellStyle(Workbook workbook) {
CellStyle style = workbook.createCellStyle();
//对齐方式设置
style.setAlignment(HorizontalAlignment.CENTER);
//边框颜色和宽度设置
style.setBorderBottom(BorderStyle.THIN);
style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 下边框
style.setBorderLeft(BorderStyle.THIN);
style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 左边框
style.setBorderRight(BorderStyle.THIN);
style.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 右边框
style.setBorderTop(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 上边框
//设置背景颜色
style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
//粗体字设置
Font font = workbook.createFont();
font.setBold(true);
style.setFont(font);
return style;
} /**
* 将数据转换成行
*
* @param data 源数据
* @param row 行对象
*/
private static void convertDataToRow(Workbook workbook, ExcelDataVO data, Row row) { int cellNum = 0;
Cell cell; //对特殊数值设置颜色
CellStyle cellStyle = workbook.createCellStyle(); //字体设置
Font font = workbook.createFont();
font.setBold(true);
font.setColor(IndexedColors.GREEN.getIndex());
cellStyle.setFont(font); // 文件名
cell = row.createCell(cellNum++);
cell.setCellValue(data.getFileName()); // 签名时间
cell = row.createCell(cellNum++);
cell.setCellValue(null == data.getSignDate() ? "" : data.getSignDate()); // 有效期
cell = row.createCell(cellNum++);
cell.setCellValue(null == data.getValidBefore() ? "" : data.getValidBefore()); // 有效期
cell = row.createCell(cellNum++);
cell.setCellValue(null == data.getValidAfter() ? "" : data.getValidAfter());
//主题
cell = row.createCell(cellNum++);
cell.setCellValue(null == data.getSubject() ? "" : data.getSubject());
//序列号
cell = row.createCell(cellNum++);
cell.setCellValue(null == data.getSerialNumber() ? "" : data.getSerialNumber());
//是否通过验签
cell = row.createCell(cellNum);
if (data.getIsEffective()) {
cell.setCellValue("签名有效");
} else {
cell.setCellValue("签名无效");
cell.setCellStyle(cellStyle); }
} public static void writeExcel(List<ExcelDataVO> dataVOList, String exportFilePath) { // 写入数据到工作簿对象内
Workbook workbook = ExcelWriter.exportData(dataVOList); // 以文件的形式输出工作簿对象
FileOutputStream fileOut = null;
try {
File exportFile = new File(exportFilePath);
if (!exportFile.exists()) {
boolean newFile = exportFile.createNewFile();
if (!newFile) {
System.out.println("文件创建失败");
}
} fileOut = new FileOutputStream(exportFilePath);
workbook.write(fileOut);
fileOut.flush();
} catch (Exception e) {
System.out.println("输出Excel时发生错误,错误原因:" + e.getMessage());
} finally {
try {
if (null != fileOut) {
fileOut.close();
}
workbook.close();
} catch (IOException e) {
System.out.println("关闭输出流时发生错误,错误原因:" + e.getMessage());
}
}
}
} public class VerifySignature {
private static String fromDirPath;
private static String toFilePath; public static void main(String[] args) {
final JFrame jf = new JFrame("测试窗口");
jf.setSize(400, 250);
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); JPanel panel = new JPanel(); // 创建文本区域, 用于显示相关信息
final JTextArea msgTextArea = new JTextArea(10, 30);
msgTextArea.setLineWrap(true);
panel.add(msgTextArea); JButton openBtn = new JButton("选择文件路径");
openBtn.addActionListener(e -> showFileOpenDialog(jf, msgTextArea));
panel.add(openBtn); JButton saveBtn = new JButton("结果保存位置");
saveBtn.addActionListener(e -> showFileSaveDialog(jf, msgTextArea));
panel.add(saveBtn); jf.setContentPane(panel);
jf.setVisible(true); JButton enSureBtn = new JButton("确认");
enSureBtn.addActionListener(e -> enSureListener(jf));
panel.add(enSureBtn); jf.setContentPane(panel);
jf.setVisible(true);
} /*
* 打开文件
*/
private static void showFileOpenDialog(Component parent, JTextArea msgTextArea) {
// 创建一个默认的文件选取器
JFileChooser fileChooser = new JFileChooser(); // 设置默认显示的文件夹为当前文件夹
fileChooser.setCurrentDirectory(new File(".")); // 设置文件选择的模式(只选文件、只选文件夹、文件和文件均可选)
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); // 设置是否允许多选
fileChooser.setMultiSelectionEnabled(false); // // 添加可用的文件过滤器(FileNameExtensionFilter 的第一个参数是描述, 后面是需要过滤的文件扩展名 可变参数)
// fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("zip(*.zip, *.rar)", "zip", "rar"));
//
// // 设置默认使用的文件过滤器
// fileChooser.setFileFilter(new FileNameExtensionFilter("image(*.jpg, *.png, *.gif)", "jpg", "png", "gif")); // 打开文件选择框(线程将被阻塞, 直到选择框被关闭)
int result = fileChooser.showOpenDialog(parent); if (result == JFileChooser.APPROVE_OPTION) {
// 如果点击了"确定", 则获取选择的文件路径
File file = fileChooser.getSelectedFile();
fromDirPath = file.getAbsolutePath(); msgTextArea.append("选择源文件: " + fromDirPath + "\n\n");
}
} /*
* 选择文件保存路径
*/
private static void showFileSaveDialog(Component parent, JTextArea msgTextArea) {
// 创建一个默认的文件选取器
JFileChooser fileChooser = new JFileChooser(); //把时间戳经过处理得到期望格式的时间
Date date = new Date();
SimpleDateFormat format0 = new SimpleDateFormat("yyyyMMddHHmmss");
String now = format0.format(date.getTime()); // 设置打开文件选择框后默认输入的文件名
fileChooser.setSelectedFile(new File(now + ".xlsx")); // 打开文件选择框(线程将被阻塞, 直到选择框被关闭)
int result = fileChooser.showSaveDialog(parent); if (result == JFileChooser.APPROVE_OPTION) {
// 如果点击了"保存", 则获取选择的保存路径
File file = fileChooser.getSelectedFile();
toFilePath = file.getAbsolutePath();
msgTextArea.append("结果文件路径: " + toFilePath + "\n\n");
}
} //找到需要的内容
public final static Pattern pattern = Pattern.compile("\\[Subject\\].*?O=(.*?),.*?\\[Issuer\\](.*?)\\[Serial Number\\](.*?)\\[Not Before\\](.*?)\\[Not After\\](.*?)\\[Thumbprint\\](.*?)");
// 剔除特殊字符
public final static Pattern replacePattern = Pattern.compile("\t|\r|\n"); /**
* 查找某个路径下的所有pdf文件
*
* @return 所有的pdf绝对路径
*/
public static HashSet<String> listDir(String path) {
HashSet<String> FileNameString = new HashSet<String>();
File file = new File(path); //获取其file对象
File[] fs = file.listFiles(); //遍历path下的文件和目录,放在File数组中
if (fs == null) {
System.out.println(path + "路径下没有文件");
return null;
} //遍历File[]数组
for (File f : fs) {
String fileName = String.valueOf(f);
if (!f.isDirectory() && fileName.toLowerCase().endsWith(".pdf")) //若非目录(即文件),则打印
FileNameString.add(fileName);
}
return FileNameString;
} /**
* 检验pdf文件是否签名
*
* @param filePath pdf文件绝对路径
*/
public static ExcelDataVO checkPdf(String filePath) {
//创建PdfDocument实例
PdfDocument doc = new PdfDocument(); //创建结果集
ExcelDataVO excelDataVO = new ExcelDataVO(); //文件名,注意windows下应该是\\,linux下是/
String fileName = filePath.substring(filePath.lastIndexOf("\\") + 1);
excelDataVO.setFileName(fileName); //加载含有签名的PDF文件
doc.loadFromFile(filePath); //获取域集合
PdfFormWidget pdfFormWidget = (PdfFormWidget) doc.getForm();
PdfFormFieldWidgetCollection pdfFormFieldWidgetCollection = pdfFormWidget.getFieldsWidget();
// int countCollection = pdfFormFieldWidgetCollection.getCount();
// System.out.println("共发现" + countCollection + "个域"); //遍历域
for (int i = 0; i < pdfFormFieldWidgetCollection.getCount(); i++) {
//判定是否为签名域
if (pdfFormFieldWidgetCollection.get(i) instanceof PdfSignatureFieldWidget) {
//获取签名域
PdfSignatureFieldWidget signatureFieldWidget = (PdfSignatureFieldWidget) pdfFormFieldWidgetCollection.get(i);
//获取签名时间
PdfSignature signature = signatureFieldWidget.getSignature();
excelDataVO.setSignDate(String.valueOf(signature.getDate())); //获取签名的内容
PdfCertificate certificate = signature.getCertificate(); // System.out.println("Issuer:" + certificate.getIssuer()); // System.out.println("Subject:" + certificate.getSubject());
// System.out.println("---------"); // excelDataVO.setSubject(String.valueOf(certificate.getSubject())); String certificateString = certificate.toString(); Matcher m = replacePattern.matcher(certificateString);
certificateString = m.replaceAll(""); Matcher matcher = pattern.matcher(certificateString);
while (matcher.find()) {
// String group = matcher.group(0);
String subject = matcher.group(1);
// String issuer = matcher.group(2);
String serialNumber = matcher.group(3); String before = matcher.group(4);
String after = matcher.group(5);
// String sha1 = matcher.group(6);
excelDataVO.setSubject(subject);
excelDataVO.setSerialNumber(serialNumber);
excelDataVO.setValidBefore(before);
excelDataVO.setValidAfter(after);
} //判定签名是否有效
boolean result = signature.verifySignature();
excelDataVO.setIsEffective(result); if (result) {
return excelDataVO;
}
}
}
return excelDataVO;
} /*
* 开始执行业务逻辑
*/
private static void enSureListener(JFrame parent) {
parent.dispose();
System.out.println("开始验签..."); //从某个路径下获取所有的pdf文件路径
HashSet<String> filePaths = listDir(fromDirPath);
if (filePaths == null) {
return;
}
List<ExcelDataVO> excelDataVOS = new ArrayList<>(); for (String filePath : filePaths) {
ExcelDataVO excelDataVO = checkPdf(filePath);
excelDataVOS.add(excelDataVO);
} ExcelWriter.writeExcel(excelDataVOS, toFilePath);
System.out.println("验签完成..."); } }

验证pdf文件的电子章签名的更多相关文章

  1. 实战动态PDF在线预览及带签名的PDF文件转换

    开篇语: 最近工作需要做一个借款合同,公司以前的合同都是通过app端下载,然后通过本地打开pdf文件,而喜欢创新的我,心想着为什么不能在线H5预览,正是这个想法,说干就干,实践过程总是艰难的,折腾了3 ...

  2. PHP通过PDFParser解析PDF文件

    之前一直找到的资料都是教你怎么生成pdf文档,比如:TCPDF.FPDF.wkhtmltopdf.而我碰到的项目里需要验证从远程获取的pdf文件是否受损.文件内容是否一致这些问题,这些都不能直接提供给 ...

  3. 【电子签章】HTML格式合同转化成PDF文件

    代码地址如下:http://www.demodashi.com/demo/12476.html 一.主要思路 通过itextpdf 生成想要的pdf 文件 通过itextpdf 中 XMLWorker ...

  4. 转:MVC2表单验证失败后,直接返回View,已填写的内容就会清空,可以这样做;MVC2输出文本;MVC2输出PDF文件

    ViewData.ModelState.AddModelError("FormValidator", message); foreach (string field in Requ ...

  5. 第二章:视图层 - 10:动态生成PDF文件

    可以通过开源的Python PDF库ReportLab来实现PDF文件的动态生成. 一.安装ReportLab ReportLab库在PyPI上提供,可以使用pip来安装: $ pip install ...

  6. 【Java】使用iText生成PDF文件

    iText介绍 iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库.通过iText不仅可以生成PDF或rtf的文档,而且可以将XML.Html文件转 ...

  7. C# Parsing 类实现的 PDF 文件分析器

    下载示例 下载源代码 1. 介绍 这个项目让你可以去读取并解析一个PDF文件,并将其内部结构展示出来. PDF文件的格式标准文档可以从Adobe那儿获取到. 这个项目基于“PDF指南,第六版,Adob ...

  8. python从TXT创建PDF文件——reportlab

    使用reportlab创建PDF文件电子书一般都是txt格式的,某些电子阅读器不能读取txt的文档,如DPT-RP1.因此本文从使用python实现txt到pdf的转换,并且支持生成目录,目录能够生成 ...

  9. Java 添加、验证PDF 数字签名

    在设置文档内容保护的方法中,除了对文档加密.添加水印外,应用数字签名也是一种有效防伪手段.数字签名的文件比较容易验证,并且具有较高的权威性和可信度.在PDF文档中,有可直接添加或验证数字签名的功能方法 ...

随机推荐

  1. [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1076)'))) - skipping

    C:\Users>pip listPackage Version------------ -------behave 1.2.6configparser 3.7.4ddt 1.2.1parse ...

  2. 汇编语言CPU状态控制指令

    CPU状态控制指令 1.空操作指令NOP /该指令不执行任何操作,只是使IP加1,其机器码占有一个字节的存储单元,常用于程序调试./ 2.总线封锁前缀指令LOCK /该指令与其他指令联合使用,作为指令 ...

  3. 用十一张图讲清楚,当你CRUD时BufferPool中发生了什么!以及BufferPool的优化!

    一.收到了大佬们的建议 1.篇幅偏短,建议稍微加长一点. 这点说的确实挺对,有的篇幅确实比较短,针对这个提议我会考虑将相似的话题放在一篇文章中.但是这可能会导致我中断每天更新的步调,换成隔几天发一篇的 ...

  4. a标签禁用

    a标签禁用可以使用CSS3的特性来控制 <a class="disabled">我是a标签</a> a.disabled { pointer-events: ...

  5. HDU100题简要题解(2040~2049)

    HDU2040 亲和数 题目链接 Problem Description 古希腊数学家毕达哥拉斯在自然数研究中发现,220的所有真约数(即不是自身的约数)之和为: 1+2+4+5+10+11+20+2 ...

  6. PicGo+jsDelivr+GitHub搭建免费图床,Typora使用图床

    Github配置 首先,创建一个GitHub账号 然后添加一个仓库 创建完后点头像,Setting 然后点击Developer settings 然后点击Personal access tokens ...

  7. python-网络安全编程第七天(base64模块)

    前言 睡不着,那就起来学习其实base64模块很早之前用过今天做爬虫的时候有个URL需要用它来编码一下 所以百度又学了一下遇到最大的问题就是python3和python2区别问题 python3的这个 ...

  8. ASP.NET Core 3 起架设在 Windows IIS 方式改变

    最近要升级 windows 服务器的 ASP.NET Core 2.1 专案到 3.1 版本,发现 Windows 架设在 IIS 上面的方式有所改变. 一. 除了反向代理外,从 ASP.NET Co ...

  9. python接口测试2-开发WEB接口

    首先要安装flask包: pip install flask 开发一个简单的API接口 # 1. 导入包 from flask import Flask, request # 2. 实例化一个 app ...

  10. testlink——解决测试度量与报告或图表中中文显示乱码问题

    解决问题之前的图表: 解决方法: (1)下载SimHei.TTF字体(可以在自己电脑的C:/windows/fonts目录下找到,若找不到,可以在网上下载) (2)将SimHei.TTF文件拷贝到te ...