JavaでバーコードPDFを追加 – GroupDocsで署名と検証
内部ワークフロー向けにドキュメントに高速で視覚的にタグ付けしたい場合、JavaでPDFにバーコードを追加するのが最適なソリューションです。GroupDocs.Signature を使用すれば、フルPKIベースのデジタル署名のオーバーヘッドなしに、バーコード署名の埋め込み、検証、検索、更新、削除が可能です。このチュートリアルでは、環境設定から本番環境向けのベストプラクティスまで、すべての手順を解説します。
クイック回答
- JavaでPDFにバーコードを追加するライブラリは何ですか? GroupDocs.Signature for Java。
- PDF、Word、画像に署名できますか? はい – APIは30以上の形式をサポートしています。
- 開発にライセンスは必要ですか? 30日間の一時ライセンスは無料です。製品環境ではフルライセンスが必要です。
- PDFに署名するコード行数は? たった2行です:
Signatureオブジェクトを作成し、signを呼び出すだけです。 - バーコードの検証は大文字小文字を区別しますか? はい – テキストは大文字小文字と空白を含めて完全に一致する必要があります。
add barcode pdf java とは?
add barcode pdf java は、Javaコードを使用してバーコード(Code128、QR、Data Matrix など)を PDF ファイルに埋め込むプロセスを指します。この手法により、機械が読み取れるタグが生成され、スキャンやプログラムによる検証が可能となり、内部システムでの高速な文書追跡が実現します。
フルデジタル署名ではなくバーコード署名を使用する理由は?
バーコード署名は 30‑50 % 速く生成・検証でき、印刷‑スキャンサイクル後も確実に機能します。証明書管理が不要なため、暗号的証明が必須でない大量の内部ワークフローに最適です。
前提条件
- Java Development Kit (JDK) 8+ – パフォーマンス向上のため Java 11 または 17 を推奨。
- IDE – IntelliJ IDEA または Eclipse(例は IntelliJ 構文)。
- ビルドツール – Maven または Gradle による依存関係管理。
プロジェクトへの GroupDocs.Signature の追加
最も簡単な開始方法はビルドツールでライブラリを追加することです。手順は以下の通りです。
Maven ユーザー – pom.xml に次を追加:
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-signature</artifactId>
<version>23.12</version>
</dependency>
Gradle ユーザー – build.gradle に次を追加:
implementation 'com.groupdocs:groupdocs-signature:23.12'
Direct JAR Download – 手動設定を好む場合は、GroupDocs.Signature リリース から JAR を取得し、クラスパスに追加してください。
ライセンス取得方法
GroupDocs.Signature は本番利用時に無料ではありませんが、柔軟なオプションがあります。
- Free Trial – 機能テスト用に GroupDocs ダウンロードページ からダウンロード(評価用ウォーターマークが追加されます)。
- Temporary License – コンセプト実証に最適な、30 日間のフルアクセスが可能な GroupDocs の一時ライセンスページ を取得してください。
- Full License – 本番デプロイには GroupDocs 購入オプション を確認してください。
Pro tip: 開発時は一時ライセンスで開始し、永続キーに切り替えるとウォーターマークが除去されます。
環境チェック
依存関係を追加したら、簡単なスモークテストを実行してください:
import com.groupdocs.signature.Signature;
public class SignatureTest {
public static void main(String[] args) {
try {
Signature signature = new Signature("test.pdf");
System.out.println("GroupDocs.Signature initialized successfully!");
signature.dispose();
} catch (Exception e) {
System.err.println("Setup issue: " + e.getMessage());
}
}
}
エラーが出なければ環境は整っています。問題がある場合は JDK バージョンと追加したライブラリのバージョンを確認してください。
バーコード署名を使用すべき場面
- 内部文書ワークフロー – 請求書、発注書、メモなどの承認チェーンで追跡。
- 大量処理 – 数千件の文書を高速に署名。バーコード生成はフルデジタル署名の 2× 速さです。
- 印刷‑スキャンブリッジ – バーコードは印刷‑スキャン後も残り、ハイブリッド紙‑デジタルプロセスに最適。
- レガシーシステム統合 – 既存のバーコードリーダーで追加ソフトウェア不要で読み取れます。
- 監査トレイル – 取引 ID やタイムスタンプを埋め込み、監査人が即座に検証可能。
法的契約書や高セキュリティ文書、外部パートナーとのやり取りなど、PKIベースのデジタル署名が必要なケースではバーコード署名は使用しないでください。
GroupDocs.Signature for Java の設定
コアクラス定義
Signature クラスは GroupDocs.Signature のすべての署名、検証、検索、更新、削除操作のエントリーポイントです。
import com.groupdocs.signature.Signature;
基本的な初期化
対象ファイルを指す Signature オブジェクトを作成します。
Signature signature = new Signature("path/to/your/document.pdf");
重要な注意点
- パスは絶対でも相対でも可。クロスプラットフォーム互換性のために
System.getProperty("user.home")を使用してください。 - GroupDocs は 30+ の入力・出力形式をサポートし、PDF、DOCX、XLSX、PPTX、PNG などが対象です。
signature.dispose()または try‑with‑resources ブロックで必ずリソースを解放してください:
try (Signature signature = new Signature("path/to/your/document.pdf")) {
// Your signing operations here
} catch (Exception e) {
System.err.println("Error working with document: " + e.getMessage());
}
これでバーコード追加の準備が整いました。
JavaでPDFにバーコードを追加する方法は?
new Signature("input.pdf") でソース PDF を読み込み、BarcodeSignature オブジェクト(例: Code128、テキスト “John Smith”)を設定し、sign を呼び出すだけで署名済みファイルが生成されます。3 行のコードで機械可読タグを埋め込み、元のレイアウトを保持しつつ、PDF だけでなくすべての対応形式で利用可能です。
手順実装
1. ファイルパスの定義
ソースと出力ファイルの場所を設定します:
String filePath = "YOUR_DOCUMENT_DIRECTORY/sample.docx";
String outputFilePath = "YOUR_OUTPUT_DIRECTORY/signed_sample.docx";
2. 署名ハンドラの作成
ソース文書でハンドラを初期化します:
Signature signature = new Signature(filePath);
3. バーコードオプションの設定
BarcodeSignature オブジェクトでバーコードの視覚的・データ的プロパティを定義します。タイプ、エンコード文字列、位置、サイズ、色、任意のヒューマンリーダブルフォントを設定してください:
BarcodeSignOptions signOptions = new BarcodeSignOptions("John Smith", BarcodeTypes.Code128);
signOptions.setVerticalAlignment(VerticalAlignment.Top);
signOptions.setHorizontalAlignment(HorizontalAlignment.Center);
signOptions.setWidth(100);
signOptions.setHeight(40);
signOptions.setMargin(new java.awt.Rectangle(20, 20, 0, 0));
signOptions.setForeColor(Color.RED);
SignatureFont signatureFont = new SignatureFont();
signatureFont.setSize(12);
signatureFont.setFamilyName("Comic Sans MS");
signOptions.setFont(signatureFont);
Pro tip: エンコード文字列が 20 文字を超える場合は、スキャンエラー防止のためバーコード幅を広げてください。
4. 署名の適用
署名操作を実行し、出力ファイルを生成します:
signature.sign(outputFilePath, signOptions);
5. 実例
請求書承認システムで承認者の社員 ID とタイムスタンプを埋め込む例です:
String invoiceId = "INV-2025-0042";
String approver = "john.smith@company.com";
String timestamp = LocalDateTime.now().toString();
// Combine into barcode data
String barcodeData = invoiceId + "|" + approver + "|" + timestamp;
BarcodeSignOptions signOptions = new BarcodeSignOptions(barcodeData, BarcodeTypes.QR);
signOptions.setVerticalAlignment(VerticalAlignment.Bottom);
signOptions.setHorizontalAlignment(HorizontalAlignment.Right);
signature.sign(outputFilePath, signOptions);
これにより、PDF は必要な承認メタデータをエンコードしたスキャン可能なバーコードを保持します。
Javaドキュメントでバーコード署名を検証する方法は?
Signature.verify メソッドは、提供されたオプションに基づき文書内の一致するバーコード署名をチェックし、期待するバーコードが存在するかを示すブール値を返します。自動化ワークフローで、正しい担当者が処理したかを確認する際に有用です。
検証手順
1. 署名済みドキュメントの読み込み
Signature signature = new Signature("YOUR_OUTPUT_DIRECTORY/signed_sample.docx");
2. 検証基準の設定
期待するテキスト、バーコード形式、ページ番号を定義します:
BarcodeVerifyOptions verifyOptions = new BarcodeVerifyOptions();
verifyOptions.setAllPages(false); // Only check the first page
verifyOptions.setPageNumber(1);
verifyOptions.setEncodeType(BarcodeTypes.Code128);
verifyOptions.setText("John Smith");
3. 検証の実行
チェックを実行し、結果を処理します:
boolean isValid = signature.verify(verifyOptions) != null;
if (isValid) {
System.out.println("Document signature verified successfully!");
} else {
System.out.println("Warning: Signature verification failed!");
}
共通パターン: 特定タイプのバーコードが存在すれば良い場合は setText フィルタを省略します:
BarcodeVerifyOptions flexibleOptions = new BarcodeVerifyOptions();
flexibleOptions.setAllPages(true);
flexibleOptions.setEncodeType(BarcodeTypes.Code128);
// No setText() call = accept any text with this barcode type
boolean hasAnySignature = signature.verify(flexibleOptions) != null;
またはコンテンツを気にせず形式だけを検証する場合:
BarcodeVerifyOptions formatOnly = new BarcodeVerifyOptions();
formatOnly.setEncodeType(BarcodeTypes.QR);
// Confirms a QR code exists, regardless of content
Warning: 検証は大文字小文字と空白に敏感です。署名前に必ずトリムと正規化を行ってください。
ドキュメント内のバーコード署名を検索する方法は?
Signature.search メソッドは、提供された BarcodeSearchOptions に一致するバーコード署名をスキャンし、各バーコードの位置、ページ番号、エンコード値を含むコレクションを返します。ファイルを手動で開かずにメタデータを一括抽出できます。
検索ワークフロー
1. 検索の初期化
Signature signature = new Signature("YOUR_OUTPUT_DIRECTORY/signed_sample.docx");
2. 検索パラメータの設定
ページ範囲、バーコードタイプ、テキストフィルタなどを指定します:
BarcodeSearchOptions searchOptions = new BarcodeSearchOptions();
searchOptions.setAllPages(true); // Search the entire document
必要に応じて検索範囲を絞り、パフォーマンスを向上させます:
BarcodeSearchOptions narrowSearch = new BarcodeSearchOptions();
narrowSearch.setAllPages(false);
narrowSearch.setPageNumber(1); // Only search page 1
narrowSearch.setEncodeType(BarcodeTypes.Code128); // Only find Code128 barcodes
3. 検索の実行
java.util.List<BarcodeSignature> signatures = signature.search(BarcodeSignature.class, searchOptions);
System.out.println("Found " + signatures.size() + " barcode signature(s)");
for (BarcodeSignature bcSignature : signatures) {
System.out.println("Barcode Type: " + bcSignature.getEncodeType().getTypeName());
System.out.println("Text: " + bcSignature.getText());
System.out.println("Position: (" + bcSignature.getLeft() + ", " + bcSignature.getTop() + ")");
System.out.println("Size: " + bcSignature.getWidth() + "x" + bcSignature.getHeight());
System.out.println("---");
}
4. データ抽出例
請求書バッチのすべてのバーコードから承認データを取得します:
List<BarcodeSignature> foundSignatures = signature.search(BarcodeSignature.class, searchOptions);
for (BarcodeSignature sig : foundSignatures) {
String barcodeData = sig.getText();
// Parse your custom format (remember our invoice example?)
String[] parts = barcodeData.split("\\|");
if (parts.length == 3) {
String invoiceId = parts[0];
String approver = parts[1];
String timestamp = parts[2];
System.out.println("Invoice " + invoiceId + " approved by " + approver + " at " + timestamp);
}
}
Performance tip: 100 ページ超の文書では、バーコードが実際に存在するページだけを対象に検索を限定すると、実行時間が最大 70 % 短縮できます。
既存のバーコード署名を更新する方法は?
Signature.update メソッドは、エンコードデータを保持したまま既存バーコード署名の視覚属性(位置、サイズ、色など)を変更できます。文書がすでに署名されている場合のレイアウト変更に便利です。
更新手順
1. 更新対象の署名を検索
Signature signature = new Signature("YOUR_OUTPUT_DIRECTORY/signed_sample.docx");
BarcodeSearchOptions searchOptions = new BarcodeSearchOptions();
searchOptions.setAllPages(true);
List<BarcodeSignature> signatures = signature.search(BarcodeSignature.class, searchOptions);
2. 目的のプロパティを変更
List<BarcodeSignature> signaturesToUpdate = new ArrayList<>();
if (!signatures.isEmpty()) {
BarcodeSignature bcSignature = signatures.get(0); // Update the first found signature
// Move it 100px right and 100px down
bcSignature.setLeft(bcSignature.getLeft() + 100);
bcSignature.setTop(bcSignature.getTop() + 100);
// Make it bigger
bcSignature.setWidth(200);
bcSignature.setHeight(50);
signaturesToUpdate.add(bcSignature);
}
複数属性を同時に変更することも可能です:
bcSignature.setLeft(50);
bcSignature.setTop(50);
bcSignature.setWidth(150);
bcSignature.setHeight(45);
// Note: You can't change the encoded text or barcode type with update
// For that, you'd need to delete and re-sign
3. 変更の保存
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
signature.update(outputStream, signaturesToUpdate);
// If you want to save to a file instead:
// signature.update("path/to/updated_document.docx", signaturesToUpdate);
4. 実務シナリオ
新たに追加した会社ロゴと重ならないよう、すべての署名を再配置します:
List<BarcodeSignature> allSignatures = signature.search(BarcodeSignature.class, searchOptions);
List<BarcodeSignature> toUpdate = new ArrayList<>();
for (BarcodeSignature sig : allSignatures) {
// Move all signatures down by 50px to clear space for new logo
if (sig.getTop() < 100) {
sig.setTop(sig.getTop() + 50);
toUpdate.add(sig);
}
}
if (!toUpdate.isEmpty()) {
signature.update(outputStream, toUpdate);
System.out.println("Repositioned " + toUpdate.size() + " signature(s)");
}
Limitation: エンコードされたテキストを変更するには、署名を削除して新規に挿入し直す必要があります。
ドキュメントからバーコード署名を削除する方法は?
Signature.delete メソッドは、選択したバーコード署名を文書から完全に除去し、視覚要素とエンコードデータの両方を削除します。テスト署名のクリーンアップや、不要になったバーコードの除去に使用します。
削除手順
1. 署名の検索
Signature signature = new Signature("YOUR_OUTPUT_DIRECTORY/signed_sample.docx");
BarcodeSearchOptions searchOptions = new BarcodeSearchOptions();
searchOptions.setAllPages(true);
List<BarcodeSignature> signatures = signature.search(BarcodeSignature.class, searchOptions);
2. 選択した署名の削除
List<BarcodeSignature> signaturesToDelete = new ArrayList<>();
// Delete all Code128 signatures (for example)
for (BarcodeSignature sig : signatures) {
if (sig.getEncodeType().equals(BarcodeTypes.Code128)) {
signaturesToDelete.add(sig);
}
}
if (!signaturesToDelete.isEmpty()) {
boolean result = signature.delete(signaturesToDelete);
if (result) {
System.out.println("Successfully deleted " + signaturesToDelete.size() + " signature(s)");
} else {
System.err.println("Failed to delete signatures");
}
}
3. 条件付き削除例
エンコードテキストにタイムスタンプが含まれる場合のみ、古いバーコードを削除します:
LocalDateTime cutoffDate = LocalDateTime.now().minusDays(30);
List<BarcodeSignature> outdatedSignatures = new ArrayList<>();
for (BarcodeSignature sig : signatures) {
try {
String text = sig.getText();
// Assuming format like "data|timestamp"
String[] parts = text.split("\\|");
if (parts.length > 1) {
LocalDateTime sigDate = LocalDateTime.parse(parts[1]);
if (sigDate.isBefore(cutoffDate)) {
outdatedSignatures.add(sig);
}
}
} catch (Exception e) {
// Skip signatures that don't match our format
continue;
}
}
if (!outdatedSignatures.isEmpty()) {
signature.delete(outdatedSignatures);
System.out.println("Removed " + outdatedSignatures.size() + " outdated signature(s)");
}
Caution: 削除は取り消せません。テスト時は必ずコピーしたファイルで操作してください。
4. バッチ削除パターン
リリース前にテスト署名を一括でクリーンアップします:
// Remove all signatures containing "TEST" in their text
List<BarcodeSignature> testSignatures = signatures.stream()
.filter(sig -> sig.getText().toUpperCase().contains("TEST"))
.collect(Collectors.toList());
if (!testSignatures.isEmpty()) {
signature.delete(testSignatures);
System.out.println("Cleaned up " + testSignatures.size() + " test signature(s)");
}
バーコードタイプ:実用ガイド
適切なバーコードを選択することで、スキャン信頼性、データ容量、プリンタ互換性が左右されます。
Code128(最も一般的な選択)
- 使用シーン: 英数字データ、高密度、印刷文書。
- 長所: コンパクトで標準スキャナに対応、小サイズでも鮮明に印刷可能。
- 短所: ASCII のみ、2‑D コードほどエラー耐性は低い。
例:
BarcodeSignOptions code128 = new BarcodeSignOptions("INV-2025-042", BarcodeTypes.Code128);
QRコード(モバイル向けベスト)
- 使用シーン: モバイルスキャン、大容量データ(URL、JSON など)、損傷しやすい文書。
- 長所: 最大 4 000 文字、組み込みエラー訂正、スマホフレンドリー。
- 短所: 視覚的フットプリントが大きく、小サイズでは高解像度が必要。
例:
String jsonData = "{\"invoice\":\"INV-042\",\"amount\":1500.00,\"approver\":\"john@company.com\"}";
BarcodeSignOptions qrCode = new BarcodeSignOptions(jsonData, BarcodeTypes.QR);
Code39(古くからの信頼)
- 使用シーン: レガシー スキャナ環境、ヒューマンリーダブルテキストが必要な場合。
- 長所: 幅広いレガシーサポート、シンプル形式、チェックサム不要。
- 短所: データ密度が低く、文字セットが限定的で、占有面積が大きい。
Data Matrix(コンパクトな高性能)
- 使用シーン: 極小スペース、微小部品のマーキング、高密度データ。
- 長所: 非常にコンパクト、強力なエラー訂正、曲面でも使用可。
- 短所: 高品質印刷が必須、スキャナ対応が限定的。
クイック比較
| バーコードタイプ | データ容量 | 適した用途 | 典型的なサイズ |
|---|---|---|---|
| Code128 | ~100 chars | 一般的なタグ付け | 小 |
| QR Code | ~4 000 chars | モバイルスキャン、リッチデータ | 中 |
| Code39 | ~43 chars | レガシーハードウェア | 大 |
| Data Matrix | ~3 000 chars | 小さなスペース、産業用タグ | 非常に小 |
Recommendation: シンプルな ID には Code128 が最適です。URL や大容量データが必要な場合は QR に切り替えます。レガシー統合が必要なときだけ Code39 を使用してください。
よくある問題と解決策
問題: 「検証時にバーコードが見つからない」
症状: バーコードが目視できても検証が false を返す。
典型的な原因
- 大文字小文字の不一致(例: “John Smith” vs. “john smith”)。
- エンコード文字列に余分な空白が含まれる。
- 検証オプションで誤ったバーコードタイプを指定。
- 誤ったページ番号で検索。
解決策: 署名・検証前にテキストを正規化し、setEncodeType が元のタイプと一致していることを確認してください。
// Always normalize your data
String signatureText = originalText.trim().toLowerCase();
// When signing:
BarcodeSignOptions signOptions = new BarcodeSignOptions(signatureText, BarcodeTypes.Code128);
// When verifying:
BarcodeVerifyOptions verifyOptions = new BarcodeVerifyOptions();
verifyOptions.setText(signatureText); // Use the same normalized text
verifyOptions.setEncodeType(BarcodeTypes.Code128);
問題: 「バーコードがぼやけて読めない」
症状: 印刷されたバーコードがスキャンできない。
原因
- エンコードデータに対してバーコード寸法が小さすぎる。
- 低解像度のプリンタ設定。
- バーコード色と背景のコントラストが不十分。
解決策: バーコードの幅・高さを拡大し、黒 on 白など高コントラスト色を使用し、プリンタ DPI を最低 300 dpi に設定してください。
// Increase size for longer strings
int dataLength = barcodeText.length();
int minWidth = Math.max(100, dataLength * 10); // 10px per character minimum
BarcodeSignOptions signOptions = new BarcodeSignOptions(barcodeText, BarcodeTypes.Code128);
signOptions.setWidth(minWidth);
signOptions.setHeight(60); // Taller = easier to scan
// Use high-contrast colors
signOptions.setForeColor(Color.BLACK); // Black on white is most reliable
signOptions.setBackColor(Color.WHITE);
問題: 「大きなドキュメントで OutOfMemoryError」
症状: 数百ページの PDF を処理するとアプリがクラッシュ。
原因: ライブラリが文書全体をメモリにロードする。
解決策: ストリーミングモードを有効にし、ページ単位でインクリメンタルに処理してください。
// Process pages in batches instead of all at once
BarcodeSearchOptions searchOptions = new BarcodeSearchOptions();
searchOptions.setAllPages(false);
List<BarcodeSignature> allSignatures = new ArrayList<>();
for (int page = 1; page <= totalPages; page++) {
searchOptions.setPageNumber(page);
List<BarcodeSignature> pageSignatures = signature.search(BarcodeSignature.class, searchOptions);
allSignatures.addAll(pageSignatures);
// Process and clear as you go
if (page % 10 == 0) {
System.gc(); // Suggest garbage collection every 10 pages
}
}
問題: 「ドキュメントタイプ間で署名位置が不一致」
症状: PDF と Word で署名位置が異なる。
原因: PDF は左下原点、Word は左上原点を使用。
解決策: ドキュメントタイプを検出し、座標変換を適用してください。
// Use relative positioning instead of absolute
signOptions.setVerticalAlignment(VerticalAlignment.Bottom);
signOptions.setHorizontalAlignment(HorizontalAlignment.Right);
// Then use margins for fine-tuning
Padding margin = new Padding();
margin.setRight(50); // 50px from right edge
margin.setBottom(50); // 50px from bottom
signOptions.setMargin(margin);
// This works consistently across PDF, DOCX, XLSX, etc.
問題: 「更新後の署名が書式を失う」
症状: update 呼び出し後にバーコードの色やフォントが予期せず変わる。
原因: すべての視覚プロパティが更新時に保持されない。
解決策: 更新後に必要な視覚設定を再適用してください。
// When updating, explicitly set all visual properties
bcSignature.setLeft(newLeft);
bcSignature.setTop(newTop);
bcSignature.setWidth(originalWidth); // Don't forget these!
bcSignature.setHeight(originalHeight);
// Note: Color and font can't be updated - you'd need to delete and re-sign
本番環境でのベストプラクティス
パフォーマンス最適化
- Reuse Signature Instances – 文書ごとに
Signatureオブジェクトを一つ作成し、複数操作で再利用します。
// Bad - Creates new instance each time
public void processDocument(String path) {
Signature sig1 = new Signature(path);
sig1.search(/* ... */);
Signature sig2 = new Signature(path); // Unnecessary reload
sig2.verify(/* ... */);
}
// Good - Reuse the same instance
public void processDocument(String path) {
try (Signature signature = new Signature(path)) {
signature.search(/* ... */);
signature.verify(/* ... */);
signature.update(/* ... */);
}
}
- Search Specific Pages Only – バーコードが期待されるページ範囲に限定してください。
// Slow for 100+ page documents
BarcodeSearchOptions slowSearch = new BarcodeSearchOptions();
slowSearch.setAllPages(true);
// Fast - only check where signatures actually are
BarcodeSearchOptions fastSearch = new BarcodeSearchOptions();
fastSearch.setAllPages(false);
fastSearch.setPageNumber(1); // Only check cover page
- Choose the Simplest Barcode Type – シンプルなバーコードほど生成が速いです。QR や Data Matrix は本当に必要なときだけ使用してください。
// Overkill for simple IDs
BarcodeSignOptions slow = new BarcodeSignOptions("12345", BarcodeTypes.QR);
// Faster and more appropriate
BarcodeSignOptions fast = new BarcodeSignOptions("12345", BarcodeTypes.Code128);
セキュリティ考慮事項
- Never Encode Sensitive Personal Data – バーコードは容易に読み取れるため、SSN やパスワードなどの個人情報は避けてください。
// Bad - exposes sensitive data
String barcodeData = "SSN:123-45-6789|Password:hunter2";
// Good - use reference IDs
String barcodeData = "USER-REF-7721X"; // Look up sensitive data server-side
- Validate Server‑Side – クライアント側の検証だけに依存せず、必ず信頼できるバックエンドで再検証してください。
// Client scans barcode and extracts "APPROVED-BY-ADMIN"
// Always verify server-side:
public boolean verifyApproval(String documentId, String scannedData) {
// Load document from secure storage
Signature signature = new Signature(getSecureDocument(documentId));
BarcodeVerifyOptions verifyOptions = new BarcodeVerifyOptions();
verifyOptions.setText(scannedData);
boolean isValid = signature.verify(verifyOptions) != null;
// Also check against your database
boolean isInDatabase = checkApprovalDatabase(documentId, scannedData);
return isValid && isInDatabase;
}
- Add Timestamps – 再利用攻撃防止のため、ペイロードにタイムスタンプを含めます。
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
String timestamp = LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS).toString();
String barcodeData = "APPROVAL|" + userId + "|" + timestamp;
// When verifying, check the timestamp isn't too old
public boolean isSignatureRecent(String barcodeData, int maxAgeHours) {
String[] parts = barcodeData.split("\\|");
if (parts.length < 3) return false;
LocalDateTime signatureTime = LocalDateTime.parse(parts[2]);
LocalDateTime now = LocalDateTime.now();
long hoursSince = ChronoUnit.HOURS.between(signatureTime, now);
return hoursSince <= maxAgeHours;
}
エラーハンドリングパターン
- Always Use Try‑With‑Resources で
Signatureオブジェクトの破棄を保証。
try (Signature signature = new Signature(documentPath)) {
// Your operations here
signature.sign(outputPath, signOptions);
} catch (Exception e) {
logger.error("Failed to sign document: " + documentPath, e);
throw new DocumentSigningException("Could not process document", e);
}
- Validate File Access してから署名処理を開始。
public void signDocument(String inputPath, String outputPath) {
File inputFile = new File(inputPath);
if (!inputFile.exists()) {
throw new IllegalArgumentException("Input file not found: " + inputPath);
}
if (!inputFile.canRead()) {
throw new SecurityException("Cannot read input file: " + inputPath);
}
File outputDir = new File(outputPath).getParentFile();
if (outputDir != null && !outputDir.exists()) {
outputDir.mkdirs();
}
try (Signature signature = new Signature(inputPath)) {
signature.sign(outputPath, signOptions);
}
}
- Synchronize Access 複数スレッドが同一ファイルにアクセスする可能性がある場合は同期化してください。
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ConcurrentHashMap;
public class SignatureManager {
private final ConcurrentHashMap<String, ReentrantLock> documentLocks = new ConcurrentHashMap<>();
public void signDocument(String documentPath, BarcodeSignOptions options) {
ReentrantLock lock = documentLocks.computeIfAbsent(documentPath, k -> new ReentrantLock());
lock.lock();
try (Signature signature = new Signature(documentPath)) {
signature.sign(documentPath + ".signed", options);
} finally {
lock.unlock();
}
}
}
実装のテスト
ユニットテストテンプレート
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import static org.junit.jupiter.api.Assertions.*;
public class BarcodeSignatureTest {
@TempDir
Path tempDir;
@Test
public void testSignAndVerify() throws Exception {
// Setup
String testDoc = "test-document.pdf";
String outputDoc = tempDir.resolve("signed-test.pdf").toString();
String testData = "TEST-USER-12345";
// Sign
try (Signature signature = new Signature(testDoc)) {
BarcodeSignOptions signOptions = new BarcodeSignOptions(testData, BarcodeTypes.Code128);
signature.sign(outputDoc, signOptions);
}
// Verify
try (Signature signature = new Signature(outputDoc)) {
BarcodeVerifyOptions verifyOptions = new BarcodeVerifyOptions();
verifyOptions.setText(testData);
verifyOptions.setEncodeType(BarcodeTypes.Code128);
boolean isValid = signature.verify(verifyOptions) != null;
assertTrue(isValid, "Signature should be valid");
}
}
@Test
public void testSearchFindsSignature() throws Exception {
String signedDoc = "signed-document.pdf";
try (Signature signature = new Signature(signedDoc)) {
BarcodeSearchOptions searchOptions = new BarcodeSearchOptions();
searchOptions.setAllPages(true);
List<BarcodeSignature> signatures = signature.search(BarcodeSignature.class, searchOptions);
assertFalse(signatures.isEmpty(), "Should find at least one signature");
assertEquals("TEST-USER-12345", signatures.get(0).getText());
}
}
}
統合チェックリスト
- ✅ すべてのサポート形式 (PDF, DOCX, XLSX, PPTX, PNG) をテスト。
- ✅ バーコードが印刷‑スキャンサイクル後も残ることを確認。
- ✅ 最大長データ文字列でストレステスト。
- ✅ A4、Letter、カスタムページサイズでの位置確認。
- ✅ 複数文書で同時署名を実行。
- ✅ 500 ページ超ドキュメントのメモリ使用量を監視。
- ✅ バーコードリーダーが出力を確実に読み取れることを保証。
ロギングとモニタリング
各操作の前後に意味のあるログを追加してください:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DocumentSigningService {
private static final Logger logger = LoggerFactory.getLogger(DocumentSigningService.class);
public void signDocument(String docPath, String barcodeData) {
logger.info("Starting signature process for document: {}", docPath);
logger.debug("Barcode data length: {} characters", barcodeData.length());
try (Signature signature = new Signature(docPath)) {
BarcodeSignOptions options = new BarcodeSignOptions(barcodeData, BarcodeTypes.Code128);
long startTime = System.currentTimeMillis();
signature.sign(docPath + ".signed", options);
long duration = System.currentTimeMillis() - startTime;
logger.info("Successfully signed document in {}ms", duration);
} catch (Exception e) {
logger.error("Failed to sign document: {}", docPath, e);
throw new RuntimeException("Signature operation failed", e);
}
}
}
処理時間、メモリ消費、エラー率などの主要指標を追跡します:
// Track success/failure rates
metricsService.incrementCounter("signature.sign.success");
metricsService.incrementCounter("signature.verify.failure");
// Track performance
metricsService.recordTimer("signature.sign.duration", duration);
// Track document sizes
metricsService.recordHistogram("signature.document.pages", pageCount);
実務でのプロティップス
バッチ処理戦略
数百ファイルを扱う場合はバッチ単位で処理し、進捗を報告してください:
public void signBatch(List<String> documents, String barcodePrefix) {
int total = documents.size();
int completed = 0;
int failed = 0;
for (String docPath : documents) {
try {
String barcodeData = barcodePrefix + "-" + UUID.randomUUID().toString();
signDocument(docPath, barcodeData);
completed++;
if (completed % 10 == 0) {
logger.info("Progress: {}/{} documents signed", completed, total);
}
} catch (Exception e) {
failed++;
logger.warn("Failed to sign: {}", docPath, e);
}
}
logger.info("Batch complete: {} succeeded, {} failed", completed, failed);
}
設定の外部化
バーコード設定(タイプ、サイズ、色)をプロパティファイルに保存し、再コンパイルせずに調整可能にします:
public class BarcodeConfig {
private int defaultWidth = 100;
private int defaultHeight = 40;
private String defaultBarcodeType = "Code128";
private String defaultColor = "BLACK";
// Load from properties file or environment variables
public BarcodeConfig() {
this.defaultWidth = Integer.parseInt(
System.getProperty("barcode.width", "100")
);
// ... load other properties
}
public BarcodeSignOptions createDefaultOptions(String text) {
BarcodeSignOptions options = new BarcodeSignOptions(text, getBarcodeType());
options.setWidth(defaultWidth);
options.setHeight(defaultHeight);
options.setForeColor(getColor());
return options;
}
}
バーコードペイロードの標準化
EMPID|TIMESTAMP|DOCID のような区切り形式を使用すれば、解析がシンプルで一貫します:
public class BarcodeDataBuilder {
private String userId;
private String action;
private LocalDateTime timestamp;
private String documentId;
public BarcodeDataBuilder setUserId(String userId) {
this.userId = userId;
return this;
}
public BarcodeDataBuilder setAction(String action) {
this.action = action;
return this;
}
public BarcodeDataBuilder setDocumentId(String documentId) {
this.documentId = documentId;
return this;
}
public String build() {
this.timestamp = LocalDateTime.now();
// Format: VERSION|USER|ACTION|DOC_ID|TIMESTAMP|CHECKSUM
String data = String.join("|",
"v1",
userId,
action,
documentId,
timestamp.toString()
);
// Add simple checksum
int checksum = data.hashCode();
return data + "|" + checksum;
}
public static ParsedBarcodeData parse(String barcodeData) {
String[] parts = barcodeData.split("\\|");
if (parts.length != 6 || !parts[0].equals("v1")) {
throw new IllegalArgumentException("Invalid barcode format");
}
return new ParsedBarcodeData(parts[1], parts[2], parts[3],
LocalDateTime.parse(parts[4]));
}
}
// Usage:
String barcodeData = new BarcodeDataBuilder()
.setUserId("john.smith")
.setAction("APPROVED")
.setDocumentId("INV-2025-042")
.build();
ドキュメントタイプを自動検出
対象が PDF、Word、画像のいずれかに応じてバーコード寸法を自動調整します:
public BarcodeSignOptions getOptimalOptions(String documentPath, String text) {
String extension = documentPath.substring(documentPath.lastIndexOf(".") + 1).toLowerCase();
BarcodeSignOptions options = new BarcodeSignOptions(text, BarcodeTypes.Code128);
switch (extension) {
case "pdf":
// PDFs can handle larger, detailed barcodes
options.setWidth(150);
options.setHeight(50);
break;
case "docx":
case "doc":
// Word docs need compact signatures that don't disrupt flow
options.setWidth(100);
options.setHeight(35);
options.setVerticalAlignment(VerticalAlignment.Bottom);
break;
case "xlsx":
case "xls":
// Excel needs signatures that don't obscure data
options.setWidth(80);
options.setHeight(30);
options.setHorizontalAlignment(HorizontalAlignment.Right);
break;
default:
// Safe defaults
options.setWidth(100);
options.setHeight(40);
}
return options;
}
追加リソース
- GroupDocs.Signature ドキュメント – 完全な API ガイドと使用例。
- GroupDocs サポートフォーラム – コミュニティによるヘルプとトラブルシューティング。
- API リファレンス – 詳細なメソッドシグネチャとパラメータ説明。
よくある質問
Q: Java 17 で GroupDocs.Signature を使用できますか?
A: はい – ライブラリは JDK 8、 11、 17 と完全互換です。
Q: バーコードは印刷‑スキャンサイクル後も残りますか?
A: Code128 や QR を十分なサイズとコントラストで使用すれば、印刷後のスキャンでも読み取れます。
Q: 1 文書に含められるバーコードの上限は?
A: 明確な上限はありませんが、最適なパフォーマンスを保つために 200 個未満に抑えることを推奨します。
Q: 開発ビルドにライセンスは必須ですか?
A: 一時ライセンスで評価ウォーターマークが除去されますが、本番デプロイにはフルライセンスが必須です。
Q: パスワード保護された PDF に署名できますか?
A: はい – Signature オブジェクト作成時にパスワードを渡せば、API が内部でファイルを解除します。
最終更新日: 2026-07-15
テスト環境: GroupDocs.Signature 23.9 for Java
作者: GroupDocs