参考:https://blog.csdn.net/w116858389/article/details/64921991
目录
我自己试了一下,貌似不能用 ,如果你的可以,请告诉我
简介
,这篇主要实现数字签名及HTML转成PDF功能。
在弄功能时有几个细节,调试了半天,
- 将不标准的HTML转成标准的HTML格式(就是必须是有始有终),不然itextpdf转不了,报错。
- 印章定位的问题,最后经过一遍遍调试,终于能将图在指定的位置显示了。
主要功能如下
1,将HTML转成PDF
2,对此PDF进行签名
3,打印签名。
一,HContent.java 常量类,定义图片资源的位置
package com.wowoyoo.helper;
/**
* @author hubs
* @version 创建时间:2017年3月22日 下午3:34:56
* 类说明
*/
public class Content {
public static String BASE = "/home/hubs/桌面/ssl/ok/"; //文件存放路径
/** The resulting PDF */
public static String PDF_NEW = BASE + "/test1.pdf"; // 创建的PDF
/** The resulting PDF */
public static String PDF_SIGNED = BASE + "/signature_1.pdf"; // 签名的文件
/** Info after verification of a signed PDF */
public static String PDF_VERIFICATION = BASE + "verify.txt"; // 签证的信息,如果已更改,则值为空
public static final String PFX_PATH = BASE + "client.pfx";// 证书,包含密钥
public static final String PFX_PASS = "xxxxx"; // 这是签名的密码
public static final String STAMP_PATH = BASE + "test.gif"; // 签名的图
public static final String LOGO_PATH = BASE + "logo.png"; // 签名的图
public static final String CER_PATH = BASE + "client.crt"; // 解答的证书,公钥
public static byte[] OPEN_PASSWORD = "hello".getBytes(); // 密码
public static final String HTML_PATH = BASE + "test.html";
public static final String WORD_PATH = BASE + "word.doc";
}
二,HTML转PDF类
package com.wowoyoo.helper;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import org.jsoup.Jsoup;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
/**
* @author hubs
* @version 创建时间:2017年3月22日 下午3:29:21
* 类说明"HTML转PDF
*/
public class HtmlToPdf {
public static void createPdf(String HTML,String outFileName) throws IOException,DocumentException {
Document document = new Document(PageSize.A4);
PdfWriter pdfWriter = PdfWriter.getInstance(document,new FileOutputStream(outFileName));
document.open();
document.addAuthor("蜗蜗游旅行网");
document.addTitle("蜗蜗游旅行网电子合同");
document.addCreator("蜗蜗游旅行网");
document.addHeader("wowoyoo.com", "蜗蜗游");
document.addKeywords("蜗蜗游,电子合同 ");
document.addSubject("蜗蜗游旅行网电子合同");
// 标准化HTML代码
org.jsoup.nodes.Document _doc = Jsoup.parse(new File(HTML), "UTF-8");
_doc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
String _html = _doc.html();
//HTML转PDF
XMLWorkerHelper.getInstance().parseXHtml(pdfWriter, document,new ByteArrayInputStream(_html.getBytes()),Charset.forName("UTF-8"), new AsianFontProvider());
document.close();
}
}
三,中文汉字类,主要是使用了itext-asian包
package com.wowoyoo.helper;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
/**
* @author hubs
* @version 创建时间:2017年3月21日 下午4:18:49 类说明
*/
public class AsianFontProvider extends XMLWorkerFontProvider {
public Font getFont(final String fontname, final String encoding,
final boolean embedded, final float size, final int style,
final BaseColor color) {
BaseFont bf = null;
try {
bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
e.printStackTrace();
}
Font font = new Font(bf, size, style, color);
font.setColor(color);
return font;
}
}
四,签名类
package com.wowoyoo.helper;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfAnnotation;
import com.itextpdf.text.pdf.PdfAppearance;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.CertificateInfo;
import com.itextpdf.text.pdf.security.CertificateVerification;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PdfPKCS7;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
import com.itextpdf.text.pdf.security.VerificationException;
/**
* @author hubs
* @version 创建时间:2017年3月22日 下午3:39:42
* 类说明
*/
public class Sign {
//对PDF进行签名
public static void signPdf(String src, String dest) throws Exception {
KeyStore ks = KeyStore.getInstance("pkcs12", "BC");
//证书与证书密码(不要问我是什么意思,我的直接copy网上的....)
ks.load(new FileInputStream(Content.PFX_PATH),Content.PFX_PASS.toCharArray());
String alias = (String) ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, Content.PFX_PASS.toCharArray());
Certificate[] chain = ks.getCertificateChain(alias);
//读取需要签名的PDF源文件
PdfReader reader = new PdfReader(src);
//写入目标文件
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
// 加密,只充许打印
stamper.setEncryption(Content.OPEN_PASSWORD, null, PdfWriter.ALLOW_PRINTING,PdfWriter.ENCRYPTION_AES_128| PdfWriter.DO_NOT_ENCRYPT_METADATA);
int qtyPages = reader.getNumberOfPages();
//这个是在每一页的印章(除最后一页)
Image _image = Image.getInstance(Content.LOGO_PATH);
//这个宽度是图片定位用的
float _width = PageSize.A4.getWidth() - _image.getScaledWidth();
//设置为A4纸大小
Rectangle _rect = PageSize.A4;
Rectangle _cell = new Rectangle(_rect);
//除了最后一页,其他每页都盖章
for (int i = 1; i < qtyPages; i++) {
PdfAnnotation stp = PdfAnnotation.createStamp(stamper.getWriter(),_cell, "蜗蜗游旅行网", "wowoyoo.com");// 每一页加标签
PdfAppearance tp = PdfAppearance.createAppearance(stamper.getWriter(), _rect.getWidth(), _rect.getHeight());
_image.setAbsolutePosition(_width - 50, 50);// X:坐标,Y:右下角坐标
tp.addImage(_image, true);
stp.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp);
stamper.addAnnotation(stp, i);
}
// 最后一个界面加印章
Image _last_image = Image.getInstance(Content.STAMP_PATH);
PdfAnnotation stp = PdfAnnotation.createStamp(stamper.getWriter(),_cell, "蜗蜗游旅行网", "wowoyoo.com");// 每一页加标签
PdfAppearance tp = PdfAppearance.createAppearance(stamper.getWriter(),_rect.getWidth(), _rect.getHeight());
_last_image.setAbsolutePosition(_width - 150, 200);// X:坐标,Y:右下角坐标,这里自己调位置
tp.addImage(_last_image, true);
stp.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp);
stamper.addAnnotation(stp, qtyPages);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "BC");
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance, digest, es, chain, null, null,null, 0, CryptoStandard.CMS);
}
//签证签名(这里暂时只打印出信息,不作判断)
/**
* 打印结果如下:
* Signature name: Signature1
* Signature covers whole document: true
*Document revision: 1 of 1
*Subject: {E=[273579540@qq.com], ST=[guanxi], C=[zh], L=[guilin], OU=[wowoyoo], O=[wowoyoo], CN=[wowoyoo]}
* Revision modified: false
* Certificates verified against the KeyStore
* @throws Exception
*/
public static void verifySignatures() throws Exception {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
Certificate cert1 = getPublicCertificate();
ks.setCertificateEntry("cacert", cert1);
PrintWriter out = new PrintWriter(new FileOutputStream(Content.PDF_VERIFICATION));
PdfReader reader = new PdfReader(Content.PDF_SIGNED, Content.OPEN_PASSWORD);//这里要加上签名的密码
AcroFields af = reader.getAcroFields();
ArrayListnames = af.getSignatureNames();
for (String name : names) {
out.println("Signature name: " + name);
out.println("Signature covers whole document: "+ af.signatureCoversWholeDocument(name));
out.println("Document revision: " + af.getRevision(name) + " of "+ af.getTotalRevisions());
PdfPKCS7 pk = af.verifySignature(name);
Calendar cal = pk.getSignDate();
Certificate[] pkc = pk.getCertificates();
out.println("Subject: "+ CertificateInfo.getSubjectFields(pk.getSigningCertificate()));
out.println("Revision modified: " + !pk.verify());
Listerrors = CertificateVerification.verifyCertificates(pkc, ks, null, cal);
if (errors.size() == 0)
out.println("Certificates verified against the KeyStore");
else
out.println(errors);
}
out.flush();
out.close();
}
//公钥证书
private static Certificate getPublicCertificate() throws Exception {
FileInputStream is = new FileInputStream(Content.CER_PATH);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
return cert;
}
}
五,直接调用
package com.wowoyoo.main;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.wowoyoo.helper.Content;
import com.wowoyoo.helper.HtmlToPdf;
import com.wowoyoo.helper.Sign;
/**
* @author hubs
* @version 创建时间:2017年3月20日 下午6:03:10 类说明
*/
public class Main {
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
HtmlToPdf.createPdf(Content.HTML_PATH, Content.PDF_NEW);
Sign.signPdf(Content.PDF_NEW, Content.PDF_SIGNED);
Sign.verifySignatures();
}
}
上图:
依赖类
<?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>wowoyoo</groupId>
<artifactId>ConverPdf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.56</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-pdfa</artifactId>
<version>5.5.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-ext-jdk16 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk16</artifactId>
<version>1.46</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-xtra</artifactId>
<version>5.5.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcmail-jdk16 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk16</artifactId>
<version>1.46</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bctsp-jdk16 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bctsp-jdk16</artifactId>
<version>1.46</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-scratchpad -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.16-beta2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.7-beta3</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.18</version>
</dependency>
</dependencies>
</project>
最后感谢网上提供的资源,由于找资源时太乱太杂了,没能记下资源原地址,在此表示感谢。