用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文件的电子章签名的资料请关注其它相关文章!
推荐阅读