You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用iText 5实现PDF多次签名仅显示最新签名的问题排查

问题分析与解决方案

代码中的问题

  1. 签名域名称冲突:调用sap.setVisibleSignature()时第三个参数传null,iText会默认生成签名域名称,多次签名时易出现域名称重复,后续签名会覆盖前一个签名的可视化区域,导致阅读器仅显示最新签名。
  2. PDF版本参数无效:PdfStamper.createSignature()的第三个参数传了'0',这是不符合规范的PDF版本标识,会干扰PDF的增量更新机制,影响多签名的兼容性。

实现多签名展示的修改方案

1. 指定唯一签名域名称

每次签名时为setVisibleSignature()的第三个参数传入不同的唯一名称(如"Signature1"、"Signature2"),确保每个签名的可视化区域独立存在,不会被覆盖。

2. 修正PDF版本参数

将PdfStamper.createSignature()的第三个参数改为'\0',表示保留原PDF的版本,避免版本冲突破坏增量签名的逻辑。

3. 保留增量签名模式

代码中最后一个参数append已设为true,这是正确的设置,增量模式会保留之前的签名数据,不会覆盖原有内容。

修改后的示例代码

public List<byte[]> addSign(List<MultipartFile> files, byte[] img, String[] certificates, SignReq signReq, HttpHeaders httpHeaders, AuthorizationReq authorizationReq, String signatureFieldName) throws IOException, DocumentException, GeneralSecurityException {
    PdfReader reader = new PdfReader(files.get(0).getBytes());
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    // 修正PDF版本参数为'\0',保留原文件版本
    PdfStamper stamper = PdfStamper.createSignature(reader, outputStream, '\0', null, true);
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    X509Certificate certificate = ((X509Certificate) cf.generateCertificate(
            new ByteArrayInputStream(Base64.getDecoder().decode(certificates[0].replaceAll("\n", "")))));
    PdfSignatureAppearance sap = stamper.getSignatureAppearance();
    sap.setReason("Hihi");
    sap.setLocation("Hanoi");
    // 传入唯一签名域名称,多次签名使用不同名称
    sap.setVisibleSignature(new Rectangle(300, 600, 630, 500), 1, signatureFieldName);
    sap.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
    ExternalDigest digest = new BouncyCastleDigest();
    ExternalSignature signature = new CustomExternalSignature(httpHeaders,signReq,authorizationReq,signatureServices); 
    MakeSignature.signDetached(sap,digest,signature,new Certificate[]{certificate},null,null,null,0, MakeSignature.CryptoStandard.CMS);
    stamper.close();
    reader.close();
    List<byte[]> result = new ArrayList<>();
    result.add(outputStream.toByteArray());
    return result;
}

调用说明

第一次签名传入signatureFieldName = "Signature1",第二次签名传入signatureFieldName = "Signature2",同时确保第二次签名的输入文件是第一次签名后的PDF文件,这样每个签名会拥有独立的可视化区域,阅读器即可展示所有签名。

内容的提问来源于stack exchange,提问作者Hoàng Trung Kiên

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 02:59:58