国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 利用Java對PDF文件進行電子簽章的實戰過程

利用Java對PDF文件進行電子簽章的實戰過程

2021-10-06 11:22世界沉浮腳下 Java教程

隨著電子賬單、回單、通知、合同的流行,電子文檔的可信度變得非常重要,為防止非法篡改,確保文檔的權威性,我們可以對PDF進行電子簽章,這篇文章主要給大家介紹了關于如何利用Java對PDF文件進行電子簽章的相關資料,需要的朋友可

一、 概述

印章是我國特有的歷史文化產物,古代主要用作身份憑證和行駛職權的工具。它的起源是由于社會生活的實際需要。早在商周時代,印章就已經產生。如今的印章已成為一種獨特的,融實用性和藝術性為一體的藝術瑰寶。傳統的印章容易被壞人、小人私刻;從而新聞鮮有報道某某私刻公章,侵吞國家財產。隨著計算機技術、加密技術及圖像處理技術的發展,出現了電子簽章。電子簽章是電子簽名的一種表現形式,利用圖像處理技術、數字加密技術將電子簽名操作轉化為與紙質文件蓋章操作相同的可視效果,同時利用電子簽名技術保障電子信息的真實性和完整性以及簽名人的不可否認性。

電子簽章與數字證書一樣是身份驗證的一種手段,泛指所有以電子形式存在,依附在電子文件并與其邏輯關聯,可用以辨識電子文件簽署者身份,保證文件的完整性,并表示簽署者同意電子文件所陳述事實的內容。一般來說對電子簽章的認定都是從技術角度而言的。主要是指通過特定的技術方案來鑒別當事人的身份及確保電子資料內容不被篡改的安全保障措施。電子簽章常于發送安全電子郵件、訪問安全站點、網上招標投標、網上簽約、安全網上公文傳送、公司合同、電子處方箋等。

電子簽章是一個很復雜的問題,大到有相關的電子簽章系統;今天分享一下如何把電子簽章應用到電子處方箋的pdf文件里。

二、 技術選型

目前主流處理pdf文件兩個jar包分別是:

  • 開源組織apache的pdfbox,官網https://pdfbox.apache.org/
  • 大名鼎鼎adobe公司的itext,官網https://itextpdf.com/tags/adobe,其中itext又分為itext5和itext7

如何在pdfbox、itext5和itext7選出合適自己項目的技術呢?

對比pdfbox、itext5和itext7這三者:

  1. pdfbox的功能相對較弱,itext5和itext7的功能非常強悍;
  2. itext5的資料網上相對較多,如果出現問題容易找到解決方案;pdfbox和itext7的網上資料相對較少,如果出現問題不易找到相關解決方案;
  3. 通過閱讀pdfbox代碼目前pdfbox還沒提供自定義簽章的相關接口;itext5和itext7提供了處理自定義簽章的相關實現;
  4. pdfbox只能實現把簽章圖片加簽到pdf文件;itext5和itext7除了可以把簽章圖片加簽到pdf文件,還可以實現直接對簽章進行繪制,把文件繪制到簽章上。
  5. pdfbox和itext5/itext7使用的協議不一樣。pdfbox使用的是apache license version 2.0(https://www.apache.org/licenses/);itext5/itext7使用的是agpl(https://itextpdf.com/agpl)。pdfbox免費使用,agpl商用收費

本分享java對pdf文件進行電子簽章需要實現的功能:

  1. 生成證書。與pdfbox、itext5和itext7技術無關
  2. 按模板輸出pdf文件:pdfbox、itext5和itext7都可以完成,但是pdfbox會遇到中文亂碼比較棘手的問題
  3. 在pdf文件中實現把簽章圖片加簽到pdf文件:pdfbox、itext5和itext7都可以實現,沒有很多的區別
  4. 在pdf文件中繪制簽章:itext5和itext7都可以實現,pdfbox目前不支持
  5. 在pdf文件中生成高清簽章:itext5和itext7都可以實現,pdfbox目前不支持
  6. 在pdf文件中進行多次簽名::pdfbox、itext5和itext7都可以完成,沒有區別

通過相關技術分析和要實現的功能分析,采用itext5進行開發,唯一遺憾的是itext商用收費;但是這不是做技術需要關心的?。∵x用itext5的理由:

  • 使用itext5能實現全部的功能
  • 如何在開發中遇到相關問題,容易找到相應解決方案

三、 生成一個圖片簽章

1. 生成一個如下圖的簽章圖片

利用Java對PDF文件進行電子簽章的實戰過程

2. 相關代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
    import java.awt.color;
    import java.awt.font;
    import java.awt.fontmetrics;
    import java.awt.graphics2d;
    import java.awt.renderinghints;
    import java.awt.image.bufferedimage;
    import java.io.fileoutputstream;
    import java.io.ioexception;
    import sun.font.fontdesignmetrics;
 
    import com.sun.image.codec.jpeg.jpegcodec;
    import com.sun.image.codec.jpeg.jpegencodeparam;
    import com.sun.image.codec.jpeg.jpegimageencoder;
 
    public class signimage {
 
    /**
     * @param doctorname
     *            string 醫生名字
     * @param hospitalname
     *            string 醫生名稱
     * @param date
     *            string 簽名日期
     *            圖片高度
     * @param jpgname
     *            string jpg圖片名
     * @return
     */
    public static boolean createsigntextimg(
            string doctorname, //
            string hospitalname, //
            string date,
            string jpgname) {
        int width = 255;
        int height = 100;
        fileoutputstream out = null;
        //背景色
        color bgcolor = color.white;
        //字色
        color fontcolor = color.red;
        font doctornamefont = new font(null, font.bold, 20);
        font othortextfont = new font(null, font.bold, 18);
        try { // 寬度 高度
            bufferedimage bimage = new bufferedimage(width, height,
                    bufferedimage.type_int_rgb);
            graphics2d g = bimage.creategraphics();
            g.setcolor(bgcolor); // 背景色
            g.fillrect(0, 0, width, height); // 畫一個矩形
            g.setrenderinghint(renderinghints.key_antialiasing,
                    renderinghints.value_antialias_on); // 去除鋸齒(當設置的字體過大的時候,會出現鋸齒)
 
            g.setcolor(color.red);
            g.fillrect(0, 0, 8, height);
            g.fillrect(0, 0, width, 8);
            g.fillrect(0, height - 8, width, height);
            g.fillrect(width - 8, 0, width, height);
 
            g.setcolor(fontcolor); // 字的顏色
            g.setfont(doctornamefont); // 字體字形字號
            fontmetrics fm = fontdesignmetrics.getmetrics(doctornamefont);
            int font1_hight = fm.getheight();
            int strwidth = fm.stringwidth(doctorname);
            int y = 35;
            int x = (width - strwidth) / 2;
            g.drawstring(doctorname, x, y); // 在指定坐標除添加文字
 
            g.setfont(othortextfont); // 字體字形字號
 
            fm = fontdesignmetrics.getmetrics(othortextfont);
            int font2_hight = fm.getheight();
            strwidth = fm.stringwidth(hospitalname);
            x = (width - strwidth) / 2;
            g.drawstring(hospitalname, x, y + font1_hight); // 在指定坐標除添加文字
 
            strwidth = fm.stringwidth(date);
            x = (width - strwidth) / 2;
            g.drawstring(date, x, y + font1_hight + font2_hight); // 在指定坐標除添加文字
 
            g.dispose();
            out = new fileoutputstream(jpgname); // 指定輸出文件
            jpegimageencoder encoder = jpegcodec.createjpegencoder(out);
            jpegencodeparam param = encoder.getdefaultjpegencodeparam(bimage);
            param.setquality(50f, true);
            encoder.encode(bimage, param); // 存盤
            out.flush();
            return true;
        } catch (exception e) {
            return false;
        }finally{
            if(out!=null){
                try {
                    out.close();
                } catch (ioexception e) {
                }
            }
        }
    }
    public static void main(string[] args) {
        createsigntextimg("華佗", "在線醫院", "2018.01.01",   "sign.jpg");
    }
}

四、 如何按模板生成pdf文件

1. 制作pdf模板

目前pdf模板工具別無他物,只能使用偉大的adobe公司提供的adobe acrobatpro dc軟件進行制作。如何使用該軟件這里就不多說了,如果在使用中遇到什么可以另外咨詢。

2. 制作一個如下圖的pdf模板,該模板是帶有pdf的表單域的

利用Java對PDF文件進行電子簽章的實戰過程

五、 如何生成pkcs12證書

1. pkcs的簡單介紹

pkcs:the public-key cryptography standards (簡稱pkcs)是由美國rsa數據安全公司及其合作伙伴制定的一組公鑰密碼學標準,其中包括證書申請、證書更新、證書作廢表發布、擴展證書內容以及數字簽名、數字信封的格式等方面的一系列相關協議。

到1999年底,pkcs已經公布了以下標準:

  • pkcs#1:定義rsa公開密鑰算法加密和簽名機制,主要用于組織pkcs#7中所描述的數字簽名和數字信封[22]。
  • pkcs#3:定義diffie-hellman密鑰交換協議[23]。
  • pkcs#5:描述一種利用從口令派生出來的安全密鑰加密字符串的方法。使用md2或md5 從口令中派生密鑰,并采用des-cbc模式加密。主要用于加密從一個計算機傳送到另一個計算機的私人密鑰,不能用于加密消息[24]。
  • pkcs#6:描述了公鑰證書的標準語法,主要描述x.509證書的擴展格式[25]。
  • pkcs#7:定義一種通用的消息語法,包括數字簽名和加密等用于增強的加密機制,pkcs#7與pem兼容,所以不需其他密碼操作,就可以將加密的消息轉換成pem消息[26]。
  • pkcs#8:描述私有密鑰信息格式,該信息包括公開密鑰算法的私有密鑰以及可選的屬性集等[27]。
  • pkcs#9:定義一些用于pkcs#6證書擴展、pkcs#7數字簽名和pkcs#8私鑰加密信息的屬性類型[28]。
  • pkcs#10:描述證書請求語法[29]。
  • pkcs#11:稱為cyptoki,定義了一套獨立于技術的程序設計接口,用于智能卡和pcmcia卡之類的加密設備[30]。
  • pkcs#12:描述個人信息交換語法標準。描述了將用戶公鑰、私鑰、證書和其他相關信息打包的語法[31]。
  • pkcs#13:橢圓曲線密碼體制標準[32]。
  • pkcs#14:偽隨機數生成標準。
  • pkcs#15:密碼令牌信息格式標準[33]。

pkcs12也就是以上標準的pkcs#12,主要用來描述個人身份信息;本次分享中要進行簽章操作的是醫生和藥師,他們就是一個個人主體,給他們分配一個pkcs12的證書,就等于給他們分配了一個用于蓋章的印章。

2. 使用java生成一個pkcs12證書并進行存貯,相關分析見代碼注解

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
public class extension {
 
    private string oid;
 
    private boolean critical;
 
    private byte[] value;
 
    public string getoid() {
        return oid;
    }
 
    public byte[] getvalue() {
        return value;
    }
    public boolean iscritical() {
        return critical;
    }
}
 
 
import java.io.bytearrayinputstream;
import java.io.bytearrayoutputstream;
import java.io.file;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.math.biginteger;
import java.security.keypair;
import java.security.keypairgenerator;
import java.security.keystore;
import java.security.nosuchalgorithmexception;
import java.security.privatekey;
import java.security.publickey;
import java.security.securerandom;
import java.security.cert.certificate;
import java.security.cert.certificatefactory;
import java.security.cert.x509certificate;
import java.text.simpledateformat;
import java.util.calendar;
import java.util.date;
import java.util.hashmap;
import java.util.list;
import java.util.map;
import java.util.random;
 
import org.bouncycastle.asn1.asn1objectidentifier;
import org.bouncycastle.asn1.asn1primitive;
import org.bouncycastle.asn1.x500.x500name;
import org.bouncycastle.asn1.x509.basicconstraints;
import org.bouncycastle.asn1.x509.crldistpoint;
import org.bouncycastle.asn1.x509.distributionpoint;
import org.bouncycastle.asn1.x509.distributionpointname;
import org.bouncycastle.asn1.x509.generalname;
import org.bouncycastle.asn1.x509.generalnames;
import org.bouncycastle.asn1.x509.keyusage;
import org.bouncycastle.cert.x509certificateholder;
import org.bouncycastle.cert.x509v3certificatebuilder;
import org.bouncycastle.cert.jcajce.jcax509v3certificatebuilder;
import org.bouncycastle.jce.provider.bouncycastleprovider;
import org.bouncycastle.operator.contentsigner;
import org.bouncycastle.operator.jcajce.jcacontentsignerbuilder;
 
public class pkcs {
 
private static keypair getkey() throws nosuchalgorithmexception {
    keypairgenerator generator = keypairgenerator.getinstance("rsa",
            new bouncycastleprovider());
    generator.initialize(1024);
    // 證書中的密鑰 公鑰和私鑰
    keypair keypair = generator.generatekeypair();
    return keypair;
}
 
/**
 * @param password
 *            密碼
 * @param issuerstr 頒發機構信息
 *
 * @param subjectstr 使用者信息
 *
* @param certificatecrl 頒發地址
 *
 * @return
 */
public static map<string, byte[]> createcert(string password,
        string issuerstr, string subjectstr, string certificatecrl) {
    map<string, byte[]> result = new hashmap<string, byte[]>();
    bytearrayoutputstream out = null;
    try {
        // 生成jks證書
        // keystore keystore = keystore.getinstance("jks");
        // 標志生成pkcs12證書
        keystore keystore = keystore.getinstance("pkcs12",
                new bouncycastleprovider());
        keystore.load(null, null);
        keypair keypair = getkey();
        // issuer與 subject相同的證書就是ca證書
        certificate cert = generatecertificatev3(issuerstr, subjectstr,
                keypair, result, certificatecrl, null);
        // cretkey隨便寫,標識別名
        keystore.setkeyentry("cretkey", keypair.getprivate(),
                password.tochararray(), new certificate[] { cert });
        out = new bytearrayoutputstream();
        cert.verify(keypair.getpublic());
        keystore.store(out, password.tochararray());
        byte[] keystoredata = out.tobytearray();
        result.put("keystoredata", keystoredata);
        return result;
    } catch (exception e) {
        e.printstacktrace();
    } finally {
        if (out != null) {
            try {
                out.close();
            } catch (ioexception e) {
            }
        }
    }
    return result;
}
 
/**
 * @param issuerstr
 * @param subjectstr
 * @param keypair
 * @param result
 * @param certificatecrl
 * @param extensions
 * @return
 */
public static certificate generatecertificatev3(string issuerstr,
        string subjectstr, keypair keypair, map<string, byte[]> result,
        string certificatecrl, list<extension> extensions) {
    bytearrayinputstream bout = null;
    x509certificate cert = null;
    try {
        publickey publickey = keypair.getpublic();
        privatekey privatekey = keypair.getprivate();
        date notbefore = new date();
        calendar rightnow = calendar.getinstance();
        rightnow.settime(notbefore);
        // 日期加1年
        rightnow.add(calendar.year, 1);
        date notafter = rightnow.gettime();
        // 證書序列號
        biginteger serial = biginteger.probableprime(256, new random());
        x509v3certificatebuilder builder = new jcax509v3certificatebuilder(
                new x500name(issuerstr), serial, notbefore, notafter,
                new x500name(subjectstr), publickey);
        jcacontentsignerbuilder jbuilder = new jcacontentsignerbuilder(
                "sha1withrsa");
        securerandom securerandom = new securerandom();
        jbuilder.setsecurerandom(securerandom);
        contentsigner singer = jbuilder.setprovider(
                new bouncycastleprovider()).build(privatekey);
        // 分發點
        asn1objectidentifier crldistributionpoints = new asn1objectidentifier(
                "2.5.29.31");
        generalname generalname = new generalname(
                generalname.uniformresourceidentifier, certificatecrl);
        generalnames seneralnames = new generalnames(generalname);
        distributionpointname distributionpoint = new distributionpointname(
                seneralnames);
        distributionpoint[] points = new distributionpoint[1];
        points[0] = new distributionpoint(distributionpoint, null, null);
        crldistpoint crldistpoint = new crldistpoint(points);
        builder.addextension(crldistributionpoints, true, crldistpoint);
        // 用途
        asn1objectidentifier keyusage = new asn1objectidentifier(
                "2.5.29.15");
        // | keyusage.nonrepudiation | keyusage.keycertsign
        builder.addextension(keyusage, true, new keyusage(
                keyusage.digitalsignature | keyusage.keyencipherment));
        // 基本限制 x509extension.java
        asn1objectidentifier basicconstraints = new asn1objectidentifier(
                "2.5.29.19");
        builder.addextension(basicconstraints, true, new basicconstraints(
                true));
        // privkey:使用自己的私鑰進行簽名,ca證書
        if (extensions != null)
            for (extension ext : extensions) {
                builder.addextension(
                        new asn1objectidentifier(ext.getoid()),
                        ext.iscritical(),
                        asn1primitive.frombytearray(ext.getvalue()));
            }
        x509certificateholder holder = builder.build(singer);
        certificatefactory cf = certificatefactory.getinstance("x.509");
        bout = new bytearrayinputstream(holder.toasn1structure()
                .getencoded());
        cert = (x509certificate) cf.generatecertificate(bout);
        byte[] certbuf = holder.getencoded();
        simpledateformat format = new simpledateformat("yyyy-mm-dd");
        // 證書數據
        result.put("certificatedata", certbuf);
        //公鑰
        result.put("publickey", publickey.getencoded());
        //私鑰
        result.put("privatekey", privatekey.getencoded());
        //證書有效開始時間
        result.put("notbefore", format.format(notbefore).getbytes("utf-8"));
        //證書有效結束時間
        result.put("notafter", format.format(notafter).getbytes("utf-8"));
    } catch (exception e) {
        e.printstacktrace();
    } finally {
        if (bout != null) {
            try {
                bout.close();
            } catch (ioexception e) {
            }
        }
    }
    return cert;
}
 
public static void main(string[] args) throws exception{
    // cn: 名字與姓氏    ou : 組織單位名稱
    // o :組織名稱  l : 城市或區域名稱  e : 電子郵件
    // st: 州或省份名稱  c: 單位的兩字母國家代碼
    string issuerstr = "cn=在線醫院,ou=gitbook研發部,o=gitbook有限公司,c=cn,e=gitbook@sina.com,l=北京,st=北京";
    string subjectstr = "cn=huangjinjin,ou=gitbook研發部,o=gitbook有限公司,c=cn,e=huangjinjin@sina.com,l=北京,st=北京";
    string certificatecrl  = "https://gitbook.cn";
    map<string, byte[]> result = createcert("123456", issuerstr, subjectstr, certificatecrl);
 
    fileoutputstream outputstream = new fileoutputstream("c:/keystore.p12"); // ca.jks
    outputstream.write(result.get("keystoredata"));
    outputstream.close();
    fileoutputstream fos = new fileoutputstream(new file("c:/keystore.cer"));
    fos.write(result.get("certificatedata"));
    fos.flush();
    fos.close();
}
}

六、 如何生成一個高清晰的簽章

1. 由pdf模板生成一個pdf文件,見代碼注解

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import java.io.fileoutputstream;
import java.io.ioexception;
import java.io.outputstream;
import java.util.arraylist;
import java.util.hashmap;
import java.util.iterator;
import java.util.list;
import java.util.map;
import com.itextpdf.text.documentexception;
import com.itextpdf.text.pdf.acrofields;
import com.itextpdf.text.pdf.acrofields.item;
import com.itextpdf.text.pdf.basefont;
import com.itextpdf.text.pdf.pdfreader;
import com.itextpdf.text.pdf.pdfstamper;
 
public class pdfutils {
 
 
/**
 * @param fields
 * @param data
 * @throws ioexception
 * @throws documentexception
 */
private static void filldata(acrofields fields, map<string, string> data) throws ioexception, documentexception {
    list<string> keys = new arraylist<string>();
    map<string, item> formfields = fields.getfields();
    for (string key : data.keyset()) {
        if(formfields.containskey(key)){
            string value = data.get(key);
            fields.setfield(key, value); // 為字段賦值,注意字段名稱是區分大小寫的
            keys.add(key);
        }
    }
    iterator<string> itemskey = formfields.keyset().iterator();
    while(itemskey.hasnext()){
        string itemkey = itemskey.next();
        if(!keys.contains(itemkey)){
            fields.setfield(itemkey, " ");
        }
    }
}
 
/**
 * @param templatepdfpath
 *            模板pdf路徑
 * @param generatepdfpath
 *            生成pdf路徑
 * @param data
 *            數據
 */
public static string generatepdf(string templatepdfpath, string generatepdfpath, map<string, string> data) {
    outputstream fos = null;
    bytearrayoutputstream bos = null;
    try {
        pdfreader reader = new pdfreader(templatepdfpath);
        bos = new bytearrayoutputstream();
        /* 將要生成的目標pdf文件名稱 */
        pdfstamper ps = new pdfstamper(reader, bos);
        /* 使用中文字體 */
        basefont bf = basefont.createfont("stsong-light", "unigb-ucs2-h",basefont.not_embedded);
        arraylist<basefont> fontlist = new arraylist<basefont>();
        fontlist.add(bf);
        /* 取出報表模板中的所有字段 */
        acrofields fields = ps.getacrofields();
        fields.setsubstitutionfonts(fontlist);
        filldata(fields, data);
        /* 必須要調用這個,否則文檔不會生成的  如果為false那么生成的pdf文件還能編輯,一定要設為true*/
        ps.setformflattening(true);
        ps.close();
        fos = new fileoutputstream(generatepdfpath);
        fos.write(bos.tobytearray());
        fos.flush();
        return generatepdfpath;
    } catch (exception e) {
        e.printstacktrace();
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
        if (bos != null) {
            try {
                bos.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
    }
    return null;
}
 
public static void main(string[] args) {
    map<string, string> data = new hashmap<string, string>();
    //key為pdf模板的form表單的名字,value為需要填充的值
    data.put("title", "在線醫院");
    data.put("case", "123456789");
    data.put("date", "2018.12.07");
    data.put("name", "gitbook");
    data.put("sex", "男");
    data.put("age", "29");
    data.put("phone", "13711645814");
    data.put("office", "內科");
    data.put("cert", "身癢找打");
    data.put("drug", "1、奧美拉唑腸溶膠囊             0.25g10粒×2板 ");
    data.put("dose", "×2盒");
    data.put("cons", "用法用量:口服 一日兩次 一次2粒");
    data.put("tips", "溫馨提示");
    data.put("desc", "盡量呆在通風較好的地方,保持空氣流通,有利于病情康復。盡量呆在通風較好的地方");
    generatepdf("c:\\users\\zhilin\\desktop\\chat\\tpl.pdf",
            "c:\\users\\zhilin\\desktop\\chat\\filled.pdf", data );
}
}

利用Java對PDF文件進行電子簽章的實戰過程

2. 對pdf文件進行簽章

經過過上面的代碼可以生成一個名為sign.jpg的簽章圖片,生成一個keystore.p12的證書文件,還有一個已經通過模板填充了表單的名為filled.pdf的pdf文件。下面就可通過以上材料生成一個簽名的pdf文件。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import java.io.file;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.security.keystore;
import java.security.privatekey;
import java.security.security;
import java.security.cert.certificate;
import java.util.uuid;
 
import org.bouncycastle.jce.provider.bouncycastleprovider;
 
import com.itextpdf.text.image;
import com.itextpdf.text.rectangle;
import com.itextpdf.text.pdf.pdfreader;
import com.itextpdf.text.pdf.pdfsignatureappearance;
import com.itextpdf.text.pdf.pdfsignatureappearance.renderingmode;
import com.itextpdf.text.pdf.pdfstamper;
import com.itextpdf.text.pdf.security.bouncycastledigest;
import com.itextpdf.text.pdf.security.digestalgorithms;
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.privatekeysignature;
 
 
public class signpdf {
/**
 * @param password
 *            秘鑰密碼
 * @param keystorepath
 *            秘鑰文件路徑
 * @param signpdfsrc
 *            簽名的pdf文件
 * @param signimage
 *            簽名圖片文件
 * @param x
 *            x坐標
 * @param y
 *            y坐標
 * @return
 */
public static byte[] sign(string password, string keystorepath, string signpdfsrc, string signimage,
        float x, float y) {
    file signpdfsrcfile = new file(signpdfsrc);
    pdfreader reader = null;
    bytearrayoutputstream signpdfdata = null;
    pdfstamper stp = null;
    fileinputstream fos = null;
    try {
        bouncycastleprovider provider = new bouncycastleprovider();
        security.addprovider(provider);
        keystore ks = keystore.getinstance("pkcs12", new bouncycastleprovider());
        fos = new fileinputstream(keystorepath);
        // 私鑰密碼 為pkcs生成證書是的私鑰密碼 123456
        ks.load(fos, password.tochararray());
        string alias = (string) ks.aliases().nextelement();
        privatekey key = (privatekey) ks.getkey(alias, password.tochararray());
        certificate[] chain = ks.getcertificatechain(alias);
        reader = new pdfreader(signpdfsrc);
        signpdfdata = new bytearrayoutputstream();
        // 臨時pdf文件
        file temp = new file(signpdfsrcfile.getparent(), system.currenttimemillis() + ".pdf");
        stp = pdfstamper.createsignature(reader, signpdfdata, '\0', temp, true);
         stp.setfullcompression();
        pdfsignatureappearance sap = stp.getsignatureappearance();
        sap.setreason("數字簽名,不可改變");
        // 使用png格式透明圖片
        image image = image.getinstance(signimage);
        sap.setimagescale(0);
        sap.setsignaturegraphic(image);
        sap.setrenderingmode(renderingmode.graphic);
        // 是對應x軸和y軸坐標
        sap.setvisiblesignature(new rectangle(x, y, x + 185, y + 68), 1,
                uuid.randomuuid().tostring().replaceall("-", ""));
        stp.getwriter().setcompressionlevel(5);
        externaldigest digest = new bouncycastledigest();
        externalsignature signature = new privatekeysignature(key, digestalgorithms.sha512, provider.getname());
        makesignature.signdetached(sap, digest, signature, chain, null, null, null, 0, cryptostandard.cades);
        stp.close();
        reader.close();
        return signpdfdata.tobytearray();
    } catch (exception e) {
        e.printstacktrace();
    } finally {
 
        if (signpdfdata != null) {
            try {
                signpdfdata.close();
            } catch (ioexception e) {
            }
        }
 
        if (fos != null) {
            try {
                fos.close();
            } catch (ioexception e) {
            }
        }
    }
    return null;
}
 
public static void main(string[] args) throws exception {
    byte[] filedata = sign("123456", "c:\\users\\zhilin\\desktop\\chat\\keystore.p12", //
            "c:\\users\\zhilin\\desktop\\chat\\filled.pdf",//
            "c:\\users\\zhilin\\desktop\\chat\\sign.jpg", 100, 290);
    fileoutputstream f = new fileoutputstream(new file("c:\\users\\zhilin\\desktop\\chat\\signed.pdf"));
    f.write(filedata);
    f.close();
}
}

利用Java對PDF文件進行電子簽章的實戰過程

3. 高清簽章

高清簽章是通過itext的繪制功能來完成。主要直接在pdf文件中繪制簽章,代碼實現如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import java.io.file;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.security.keystore;
import java.security.privatekey;
import java.security.security;
import java.security.cert.certificate;
import org.bouncycastle.jce.provider.bouncycastleprovider;
 
import com.itextpdf.awt.asianfontmapper;
import com.itextpdf.text.basecolor;
import com.itextpdf.text.element;
import com.itextpdf.text.font;
import com.itextpdf.text.paragraph;
import com.itextpdf.text.rectangle;
import com.itextpdf.text.pdf.basefont;
import com.itextpdf.text.pdf.columntext;
import com.itextpdf.text.pdf.pdfreader;
import com.itextpdf.text.pdf.pdfsignatureappearance;
import com.itextpdf.text.pdf.pdfstamper;
import com.itextpdf.text.pdf.pdfstream;
import com.itextpdf.text.pdf.pdftemplate;
import com.itextpdf.text.pdf.security.bouncycastledigest;
import com.itextpdf.text.pdf.security.digestalgorithms;
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.privatekeysignature;
 
 
public class signhighpdf {
 
/**
 * @param password
 *            秘鑰密碼
 * @param keystorepath
 *            秘鑰文件路徑
 * @param signpdfsrc
 *            簽名的pdf文件
 * @param x
 *
 * @param y
 * @return
 */
public static byte[] sign(string password, string keystorepath, string signpdfsrc,
        float x, float y,
        string signtext) {
    file signpdfsrcfile = new file(signpdfsrc);
    pdfreader reader = null;
    bytearrayoutputstream signpdfdata = null;
    pdfstamper stp = null;
    fileinputstream fos = null;
    try {
        bouncycastleprovider provider = new bouncycastleprovider();
        security.addprovider(provider);
        keystore ks = keystore.getinstance("pkcs12", new bouncycastleprovider());
        fos = new fileinputstream(keystorepath);
        ks.load(fos, password.tochararray()); // 私鑰密碼
        string alias = (string) ks.aliases().nextelement();
        privatekey key = (privatekey) ks.getkey(alias, password.tochararray());
        certificate[] chain = ks.getcertificatechain(alias);
        reader = new pdfreader(signpdfsrc);
        signpdfdata = new bytearrayoutputstream();
        // 臨時pdf文件
        file temp = new file(signpdfsrcfile.getparent(), system.currenttimemillis() + ".pdf");
        stp = pdfstamper.createsignature(reader, signpdfdata, '\0', temp, true);
        pdfsignatureappearance sap = stp.getsignatureappearance();
        sap.setreason("數字簽名,不可改變");
        // 是對應x軸和y軸坐標
        sap.setvisiblesignature(new rectangle(x, y, x + 150, y + 65), 1,
                "sr"+string.valueof(system.nanotime()));
        /layer 0 creating the appearance for layer 0
        pdftemplate n0 = sap.getlayer(0);
        n0.reset();
        float lx = n0.getboundingbox().getleft();
        float by = n0.getboundingbox().getbottom();
        float width = n0.getboundingbox().getwidth();
        float height = n0.getboundingbox().getheight();
        n0.setrgbcolorfill(255, 0, 0);
        n0.rectangle(lx, by, 5, height);
        n0.rectangle(lx, by, width, 5);
        n0.rectangle(lx, by+height-5, width, 5);
        n0.rectangle(lx+width-5, by, 5, height);
        n0.fill();
        ///layer 2
        pdftemplate n2 = sap.getlayer(2);
        n2.setcharacterspacing(0.0f);
        columntext ct = new columntext(n2);
        ct.setsimplecolumn(n2.getboundingbox());
        n2.setrgbcolorfill(255, 0, 0);
        //做一個占位的動作
        paragraph p1 = new paragraph(" ");
        basefont bf = basefont.createfont(asianfontmapper.chinesesimplifiedfont, asianfontmapper.chinesesimplifiedencoding_h,
                basefont.not_embedded);
        font font1 = new font(bf, 5, font.bold, basecolor.red);
        font font2 = new font(bf, 13, font.bold, basecolor.red);
        p1.setfont(font1);
        ct.addelement(p1);
        paragraph p = new paragraph(signtext);
        p.setalignment(element.align_center);
        p.setfont(font2);
        ct.addelement(p);
        ct.go();
        stp.getwriter().setcompressionlevel(pdfstream.best_compression);
        externaldigest digest = new bouncycastledigest();
        externalsignature signature = new privatekeysignature(key, digestalgorithms.sha512, provider.getname());
        makesignature.signdetached(sap, digest, signature, chain, null, null, null, 0, cryptostandard.cades);
        stp.close();
        reader.close();
        return signpdfdata.tobytearray();
    } catch (exception e) {
        e.printstacktrace();
    } finally {
        if (signpdfdata != null) {
            try {
                signpdfdata.close();
            } catch (ioexception e) {
            }
        }
        if (fos != null) {
            try {
                fos.close();
            } catch (ioexception e) {
            }
        }
    }
    return null;
}
 
public static void main(string[] args) throws exception {
    //對已經簽章的signed.pdf文件再次簽章,這次是高清簽章
    byte[] filedata = sign("123456", "c:\\users\\zhilin\\desktop\\chat\\keystore.p12",//
            "c:\\users\\zhilin\\desktop\\chat\\signed.pdf", 350, 290, "華佗\n2017-12-20");
    fileoutputstream f = new fileoutputstream(new file("c:\\users\\zhilin\\desktop\\chat\\signed2.pdf"));
    f.write(filedata);
    f.close();
}
 
}

可以分析下下面這兩個簽章的區別,發現左邊的簽章很模糊,右邊的特別清晰。

利用Java對PDF文件進行電子簽章的實戰過程

七、 如何進行多次pdf簽名

生成多個簽章重點代碼,已在signpdf.java類進行標注說明;如果想進行多次簽名,就只需對已經進行過簽名的pdf文件再次調用sign方法進行再次簽名即可(第六點有張圖片就有兩個簽章,這就是多次簽名的結果)。

?
1
pdfstamper.createsignature(reader, signpdfdata, '\0', temp, true);

八、 總結

分享中sign.jpg文件的白色背景需要做透明化處理才能達到正確電子簽章的效果(不覆蓋pdf文件中已有的內容,真實的電子簽章也是這樣做的),大家回去可以思考下怎么把一個jpg文件白色背景透明化(高清簽章就已經實現透明化,可以試著把signpdf.java和signhighpdf.java簽章到有文字的pdf上面看看效果)。

大家見到的公司公章都是圓形的;這個也是可以做到的大家想想怎樣生成一個圓形的圖片簽章;然后進行電子簽名。這里主要是講解代碼實現,所有代碼非常多。大家回去好好研讀代碼。真正的電子簽名需要通過ca認證公司來完成,我這里只是提供參考方案讓大家學習。

到此這篇關于利用java對pdf文件進行電子簽章的文章就介紹到這了,更多相關java對pdf文件電子簽章內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/javasun608/article/details/79307845

延伸 · 閱讀

精彩推薦
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7472021-02-04
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
主站蜘蛛池模板: 精品视频第一页 | 男人的天堂亚洲 | 九九99| 亚洲黄色特级片 | 亚洲精品wwww| 国产成人免费在线 | 午夜影视免费观看 | 91精品国产综合久久久久久 | 久久在线视频 | 男女免费视频 | 无码日韩精品一区二区免费 | 亚洲色图综合 | 国产精品久久久久av | 日本不卡免费一区二区三区综合久久 | 国产在线拍揄自揄拍视频 | 中文字幕免费观看 | 中文字幕精品一区二区三区精品 | 午夜视频网 | av一区二区三区 | 国产婷婷精品av在线 | 91综合网 | 亚洲欧美高清 | 99久久国| 亚洲视频观看 | 精品国产一区二区国模嫣然 | 欧美激情免费 | 成人中文字幕在线观看 | 久久久中文字幕 | 国产精品久久久久久久浪潮网站 | 自拍偷拍在线视频 | 欧美一级全黄 | 中文字幕精品一区二区三区精品 | 亚洲国产aⅴ成人精品无吗 久久综合久久久 | 欧美成人免费在线视频 | 亚洲精品国偷拍自产在线观看 | 亚洲第一区在线 | 亚洲第1页| 国产一区二区三区欧美 | 国产精品久久久久久久 | 欧美日韩国产在线播放 | 免费看一区二区三区 |