欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

用Java验证pdf文件的电子章签名

程序员文章站 2022-06-17 18:27:51
pom.xml

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("验签完成...");

  }

}

以上就是用java验证pdf文件的电子章签名的详细内容,更多关于java验证pdf文件的电子章签名的资料请关注其它相关文章!