验证pdf文件的电子章签名
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文件的电子章签名的更多相关文章
- 实战动态PDF在线预览及带签名的PDF文件转换
		开篇语: 最近工作需要做一个借款合同,公司以前的合同都是通过app端下载,然后通过本地打开pdf文件,而喜欢创新的我,心想着为什么不能在线H5预览,正是这个想法,说干就干,实践过程总是艰难的,折腾了3 ... 
- PHP通过PDFParser解析PDF文件
		之前一直找到的资料都是教你怎么生成pdf文档,比如:TCPDF.FPDF.wkhtmltopdf.而我碰到的项目里需要验证从远程获取的pdf文件是否受损.文件内容是否一致这些问题,这些都不能直接提供给 ... 
- 【电子签章】HTML格式合同转化成PDF文件
		代码地址如下:http://www.demodashi.com/demo/12476.html 一.主要思路 通过itextpdf 生成想要的pdf 文件 通过itextpdf 中 XMLWorker ... 
- 转:MVC2表单验证失败后,直接返回View,已填写的内容就会清空,可以这样做;MVC2输出文本;MVC2输出PDF文件
		ViewData.ModelState.AddModelError("FormValidator", message); foreach (string field in Requ ... 
- 第二章:视图层 - 10:动态生成PDF文件
		可以通过开源的Python PDF库ReportLab来实现PDF文件的动态生成. 一.安装ReportLab ReportLab库在PyPI上提供,可以使用pip来安装: $ pip install ... 
- 【Java】使用iText生成PDF文件
		iText介绍 iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库.通过iText不仅可以生成PDF或rtf的文档,而且可以将XML.Html文件转 ... 
- C# Parsing 类实现的 PDF 文件分析器
		下载示例 下载源代码 1. 介绍 这个项目让你可以去读取并解析一个PDF文件,并将其内部结构展示出来. PDF文件的格式标准文档可以从Adobe那儿获取到. 这个项目基于“PDF指南,第六版,Adob ... 
- python从TXT创建PDF文件——reportlab
		使用reportlab创建PDF文件电子书一般都是txt格式的,某些电子阅读器不能读取txt的文档,如DPT-RP1.因此本文从使用python实现txt到pdf的转换,并且支持生成目录,目录能够生成 ... 
- Java 添加、验证PDF 数字签名
		在设置文档内容保护的方法中,除了对文档加密.添加水印外,应用数字签名也是一种有效防伪手段.数字签名的文件比较容易验证,并且具有较高的权威性和可信度.在PDF文档中,有可直接添加或验证数字签名的功能方法 ... 
随机推荐
- linux中ugo权限管理(chmod/chown)
			查看ugo权限: ll [root@localhost test]# ll total 12 -rwxr-xr-x 2 root root 4 Oct 3 11:44 a lrwxrwxrwx 1 ... 
- 高性能arm运行ceph存储基准测试
			关于arm 之前wdlab对外发布过一次约500个节点的arm的ceph集群,那个采用的是微集群的结构,使用的是双核的cortex-a9 ARM处理器,运行速度为1.3 GHz,内存为1 GB,直接焊 ... 
- ceph在centos7下一个不容易发现的改变
			在centos6以及以前的osd版本,在启动osd的时候,回去根据ceph.conf的配置文件进行挂载osd,然后进行进程的启动,这个格式是这样的 [osd.0] host = hostname de ... 
- JVM(一)-JVM入门
			JVM的定义: JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的 ... 
- C#设计模式——代理模式(Proxy Pattern)
			引言 在我们的生活中,经常会遇到需要什么东西,但是自己又不是很方便或者对方不是很方便,则就需要中间的一个代理人去解决.例如代购.在软件开发中,也会遇到这样的问题.有些对象有时候会由于网络或其他的障碍, ... 
- less和more的区别
			more: 顾名思义显示更多less: 由于more不能后退,就取more的反义词less加上后退功能所以Linux里流传着这样一句话:"less is more". 总结下mor ... 
- 面试阿里,字节,美团必看的Spring的Bean管理详解
			IOC容器 工厂只负责创建对象,而Spring当然不仅仅是一个对象工厂,其核心是一个对象容器,其具备控制反转的能力,所以也称为IOC容器. 帮助我们存放对象,并且管理对象,包括:创建.销毁.装配,这样 ... 
- 巧妙运用Camtasia制作爱豆的动感影集
			对于追星族来说,收集爱豆的图片.视频是日常必做的事情,而对于进阶型的追星族来说,为爱豆自制各种精美的视频.影集等,会让自己追星之路显得更为充实. 我们可以借助Camtasia教程录制软件为爱豆制作各种 ... 
- ②SpringCloud 实战:引入Feign组件,完善服务间调用
			这是SpringCloud实战系列中第二篇文章,了解前面第一篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 简介 Feign 是一个声明式的 RE ... 
- 网络拓扑实例之交换机基于接口地址池作为DHCP服务器(六)
			组网图形 DHCP服务器简介 通常用户希望网络中的每台终端能够动态获取IP地址.DNS服务器的IP地址.路由信息.网关信息等网络参数,不需要手动配置终端的IP地址等网络参数:另外,针对一些移动终端(手 ... 
