すべてのプロダクト
Search
ドキュメントセンター

Dataphin:カスタム承認システムの統合インターフェイス

最終更新日:Jun 02, 2026

このドキュメントでは、Dataphin BPMS をサードパーティの承認ワークフローと統合する方法について、利用可能なインターフェイス機能、統合プロセス、およびサンプルのユースケースを説明します。

前提条件

Dataphin システムで [承認設定] が構成済みである必要があります。手順については、「承認設定」をご参照ください。O&M テナントは、 [承認設定] > [承認システムの選択] > [その他] でこの設定を確認できます。

承認 API

重要
  • {url}:サードパーティの承認ワークフローの統合エンドポイントです。承認リクエストを送信する URL は http(s)://{url} です。

  • accessToken:サーバーサイド API コールの認証情報です。このトークンは、Dataphin ページで自動生成されるか、手動で生成して Dataphin に入力することができます。

  • 接続テスト

    リクエストメソッド: POST。

    リクエスト URL: http(s)://{url}/dataphin/bpms/check/connect。

    リクエストシーケンス図

    image

    クエリパラメーター

    パラメーター

    タイプ

    説明

    accessToken

    String

    サーバーサイド API コールの認証情報です。このトークンは、Dataphin ページで自動生成されるか、手動で生成して Dataphin に入力することができます。例: 6d1bxxxx

    Dataphin によって自動生成されるか、ユーザーが生成して入力します。例: 6d1bxxxx

    timestamp

    String

    メッセージのタイムスタンプ (ミリ秒単位)。例: 1654156836531

    ボディパラメーター

    checkEvent (String) : チェックイベント。接続テストを実行するには、これを connectivity に設定します。

    レスポンスパラメーター

    checkResult (String) : チェック結果。返される値が success の場合にのみ、接続テストが成功したことを示します。その他の値は、テストが失敗したことを示します。例: success

  • 承認の送信

    リクエストメソッド: POST。

    リクエスト URL: http(s)://{url}/dataphin/bpms/processinstance/create。

    承認リクエスト送信のシーケンス図

    image

    クエリパラメーター

    パラメーター

    タイプ

    説明

    accessToken

    String

    サーバーサイド API コールの認証情報です。このトークンは、Dataphin ページで自動生成されるか、手動で生成して Dataphin に入力することができます。例: 6d1bxxxx

    Dataphin によって自動生成されるか、ユーザーが生成して入力します。例: 6d1bxxxx

    timestamp

    String

    メッセージのタイムスタンプ (ミリ秒単位)。例: 1654156836531

    ボディパラメーター

    パラメーター

    タイプ

    説明

    applyId

    String

    Dataphin 承認フォームの ID。例: 1223

    title

    String

    Dataphin 承認フォームのタイトル。例: dataphin bpms

    content

    String

    Dataphin 承認フォームの内容。例: bpms content。「承認メッセージのコンテンツメタデータ」をご参照ください。

    type

    String

    • 承認リクエストタイプ: APPROVAL_DOC_TYPE。

    • コードレビュー: CODE_REVIEW。

    • 公開コントロール: PUBLISH。

    • ビジネスプランニング: BIZ_PLANNING。

    • 権限承認: AUTH。

    • デフォルト: DEFAULT。

    templateCode

    String

    承認テンプレートのコード。このパラメーターは空にすることができ、ページの設定に依存します。

    承認メッセージのコンテンツメタデータ

    パラメーター

    タイプ

    説明

    resourceType

    String

    承認タスクのタイプ。列挙値。有効な値は次のとおりです:

    • PhysicalTable: 物理テーブル。

    • LogicTable: 論理テーブル。

    • MetaTable: リアルタイムメタテーブル。

    • MirrorTable: ミラーテーブル。

    • Fun: 関数。

    • DataSource: データソース。

    • FeatureConfig: 機能権限設定。

    • OSAPP: データサービスアプリ。

    • OSAPI: データサービス API。

    • OSLogicUnit: データサービスユニット。

    • OSDS: データサービスデータソース。

    • SECRET_KEY: シークレットキー。

    • GLOBAL_PARAM: グローバル変数。

    grantToUsers

    List<GrantToUser>

    権限を付与するユーザーのリスト。「GrantToUser」をご参照ください。

    bpmsEnvironment

    BpmsEnvironment

    承認システムの環境。「BpmsEnvironment」をご参照ください。

    operates

    List<String>

    要求された権限タイプ。有効な値:

    • SYNC_READ: データソースからの同期読み取り。

    • SYNC_WRITE: データソースへの同期書き込み。

    • SQL_QUERY: 物理テーブルおよび論理テーブルでの SQL クエリ。

    • SQL_WRITE: 物理テーブルへの SQL 書き込み。

    • SQL_ALTER: 物理テーブルの変更。

    • SQL_DROP: 物理テーブルおよび論理テーブルの削除。

    • SELECT: データサービス API のクエリ。

    • WRITE: 書き込み権限。

    • DEV: 開発権限。

    • USE: 使用権限。

    • UPDATE: テーブルデータの更新。

    • PIPELINE_ENCRY: 統合暗号化。

    • PIPELINE_DECRY: 統合復号化。

    levels

    List<String>

    権限レベル。有効な値は HIGHMIDDLELOW です。

    operations

    List<String>

    権限タイプ。有効な値:

    • SELECT: クエリ。

    • DESCRIBE: テーブル構造の記述。

    • UPDATE: テーブルデータの更新。

    • ALTER: テーブル構造の変更。

    • DELETE: テーブルの削除。

    • COPY_TASK: コピー。

    resources

    List<BpmsResource>

    リソースの内容。「BpmsResource」をご参照ください。

    applyObject

    ApplyObject

    リクエストされたオブジェクトに関する情報。「ApplyObject」をご参照ください。

    reason

    String

    リクエストの理由。

    GrantToUser

    パラメーター

    タイプ

    説明

    account

    Account

    認可されるアカウント。「Account」をご参照ください。

    period

    Period

    有効期間。「Period」をご参照ください。

    Account

    パラメーター

    タイプ

    説明

    accountType

    String

    アカウントタイプ。有効な値は、個人アカウント本番アカウントアプリケーションアカウントです。

    • PERSONAL: 個人アカウント。

    • PRODUCTION: 本番アカウント。

    • APPLICATION: アプリケーションアカウント。

    userName

    String

    ユーザー名。

    Period

    パラメーター

    タイプ

    説明

    periodType

    String

    有効期間タイプ。長期 (LONG_TERM) のみがサポートされます。

    periodEnd

    String

    権限の有効期限。形式: yyyy-mm-dd。例: 2022-09-11

    BpmsEnvironment

    パラメーター

    タイプ

    説明

    projectName

    String

    プロジェクト名。

    bizUnitName

    String

    業務部門名。

    resourceEnv

    String

    環境。有効な値:

    • PROD: 本番環境。

    • DEV: 開発環境。

    BpmsResource

    パラメーター

    タイプ

    説明

    resourceType

    String

    承認メッセージのコンテンツメタデータ」をご参照ください。

    resourceName

    String

    リソース名。

    children

    List<Children>

    フィールドのリスト。「Children」をご参照ください。

    operations

    List<String>

    承認メッセージのコンテンツメタデータ」の operates パラメーターをご参照ください。

    authTypes

    String

    リクエストされた権限のタイプ。

    Children

    パラメーター

    タイプ

    説明

    resourceName

    String

    フィールド名。

    resourceProperties

    String

    フィールドのプロパティ。

    ResourceProperties

    パラメーター

    タイプ

    説明

    columnType

    String

    フィールドタイプ。

    columnIsPartition

    String

    フィールドがパーティションフィールドであるかを示します。

    columnIsPk

    String

    フィールドがプライマリキーであるかを示します。

    ApplyObject

    パラメーター

    タイプ

    説明

    objectName

    String

    オブジェクト名。

    codeContent

    String

    コードの内容。

    name

    String

    ビジネスアクティビティの英語名。

    bizObjectType

    String

    オブジェクトタイプ。

    bizObjectChangeType

    String

    変更タイプ。

    bizObjectPkField

    String

    コンポーネントフィールド。

    bizObjectParent

    String

    親オブジェクト。

    bizObjectChildren

    String

    ダウンストリームサブオブジェクト。

    bizProcessCn

    String

    ビジネスプロセスの中国語名。

    bizProcessType

    String

    アクティビティタイプ。

    bizProcessChangeType

    String

    変更タイプ。

    bizProcessNodes

    String

    プロセスノード。

    atomicIndexCn

    String

    メトリック名。

    dataType

    String

    データタイプ。

    unit

    String

    測定単位。

    bizProcess

    String

    ビジネスプロセス名。

    des

    String

    アクティビティのスコープ。

    derivedLogic

    String

    派生ロジック。

    protoLogics

    String

    計算ロジック。

    レスポンスパラメーター

    processInstanceId (String) : サードパーティの承認インスタンスの ID。例: 6d1bxxxx

  • 承認の取り消し

    説明

    送信した承認リクエストの内容が正しくない場合、または不要になった場合は、取り消すことができます。

    リクエストメソッド: POST。

    リクエスト URL: http(s)://{url}/dataphin/bpms/processinstance/revoke。

    クエリパラメーター

    パラメーター

    タイプ

    説明

    accessToken

    String

    サーバーサイド API コールの認証情報です。このトークンは、Dataphin ページで自動生成されるか、手動で生成して Dataphin に入力することができます。例: 6d1bxxxx

    Dataphin によって自動生成されるか、ユーザーが生成して入力します。例: 6d1bxxxx

    timestamp

    String

    メッセージのタイムスタンプ (ミリ秒単位)。例: 1654156836531

    ボディパラメーター

    パラメーター

    タイプ

    説明

    applyId

    String

    Dataphin 承認フォームの ID。例: 1223

    processInstanceId

    String

    サードパーティの承認インスタンスの ID。例: 6d1bxxxx

    operatingUserId

    String

    操作者の従業員 ID。例: 6d1bxxxx

    レスポンスパラメーター

    result (String) : 取り消しの結果。返される値が success の場合にのみ、操作が成功したことを示します。

  • インスタンス URL のクエリ

    リクエストメソッド: GET。

    リクエスト URL: http(s)://{url}/dataphin/bpms/processinstance/apply。

    クエリパラメーター

    パラメーター

    タイプ

    説明

    accessToken

    String

    サーバーサイド API コールの認証情報です。このトークンは、Dataphin ページで自動生成されるか、手動で生成して Dataphin に入力することができます。例: 6d1bxxxx

    Dataphin によって自動生成されるか、ユーザーが生成して入力します。例: 6d1bxxxx

    timestamp

    String

    メッセージのタイムスタンプ (ミリ秒単位)。例: 1654156836531

コールバック API

重要
  • https://{callbackUrl} は、[Other][承認設定] で設定するコールバック URL です。

  • accessToken:サーバーサイド API を呼び出すためのアクセス トークンです。Dataphin が自動で生成するか、ユーザーが手動で生成して Dataphin に入力します。

  • callBackAesKey:認証に使用するコールバック AES キーです。Dataphin が自動で生成するか、ユーザーが手動で生成して Dataphin に入力します。

  • コールバックメソッド

    リクエストメソッド: POST

    リクエスト URL: http://{callbackUrl}/api/oa/bpms/integration/thirdparty/callback

    クエリパラメーター

    パラメーター

    タイプ

    説明

    signature

    文字列

    メッセージ認証のための署名です。 詳細については、暗号化と復号のメソッドをご参照ください。

    timestamp

    文字列

    メッセージのタイムスタンプ (ミリ秒単位) です。 例: 1654156836531

    nonce

    文字列

    一意のランダムな文字列です。 詳細については、暗号化と復号のメソッドをご参照ください。

    ボディパラメーター

    encrypt (文字列):暗号化されたメッセージです。 例: ajls384k

    レスポンスパラメーター

    encrypt (文字列):コールバックステータスを含む暗号化されたメッセージです。 例: djsl495l

  • コールバックの暗号化されたペイロード

    コールバック接続チェック

    • 受信する暗号化パラメーター:

      applyStatus (文字列):接続チェックに使用します。 例: CHECK

    • 応答の暗号化パラメーター:

      success :コールバックが成功した場合に返される値です。

    BPMS インスタンスの承認結果のコールバック

    • 受信する暗号化パラメーター:

      パラメーター

      タイプ

      説明

      applyId

      String

      Dataphin アプリケーション ID です。 例: 1223

      processInstanceId

      String

      サードパーティの承認インスタンスの ID です。 例: 6d1bxxxx

      comment

      String

      承認インスタンスのコメントです。

      applyStatus

      String

      • accept :承認済み。

      • reject :拒否済み。

      • revoke :取り消し済み。

      nodes

      List<ApplyCallBackNode>

      サードパーティの承認システムにおける承認ノードのオプションリストです。統合メソッドが [Display all nodes of the third-party approval] に設定されている場合にのみ必要です。

    • ApplyCallBackNode

      パラメーター

      タイプ

      説明

      nodeId

      String

      ノード ID です。 ノードは 1 から n の順に並んでいます。

      nodeStatus

      String

      ノードステータス (ApproveNodeStatusEnum) です。

      • APPROVING :処理中。

      • ACCEPTED :承認済み。

      • REJECTED :拒否済み。

      • REVOKED :取り消し済み。

      nodeName

      String

      ノードの名前です。

      approverRelation

      String

      承認関係 (ApproveOperatorEnum) です。

      • AND :すべての承認者がリクエストを承認する必要があります。

      • OR :いずれかの承認者がリクエストを承認できます。

      pendingApprovers

      List<ExternalApproverInfo>

      現在の保留中の承認者のリストです。 関連するすべての承認者がアクションを実行すると、このリストは空になります。

      records

      List<OperationRecord>

      承認者が実行したアクションのレコードを、時系列順に含みます。

    • ExternalApproverInfo

      パラメーター

      タイプ

      説明

      userId

      String

      サードパーティの承認システムにおけるユーザー ID です。 例: 1223

      userName

      String

      サードパーティの承認システムにおけるユーザー名です。 例: Zhang San

    • OperationRecord

      パラメーター

      タイプ

      説明

      operateUser

      ExternalApproverInfo

      オペレーターの情報です。 例: {"userId":"1111", "userName":"Zhang San"}

      action

      String

      操作タイプ (ApproveNodeActionType) です。

      • ASSIGN_APPROVE :権限リクエストの転送。

      • COUNTER_SIGN_APPROVE :権限リクエストにカウンターサインを追加。

      • REVOKE_APPLY :権限リクエストの取り消し。

      • APPROVE :権限リクエストの承認。

      comment

      String

      操作のコメントです。

      operatedTime

      String

      操作のタイムスタンプです。

      transferApprovers

      List<ExternalApproverInfo>

      転送先のオプションリストです。カウンターサインまたは転送操作を実行する場合に必要です。 例: [{"userId":"2222", "userName":"Li Si"}]

    • 応答の暗号化パラメーター

      success :コールバックが成功した場合に返される値です。

  • 承認結果のコールバックペイロード

    サードパーティの承認システムでは、2 つの統合方法 (最終的な承認結果のみを表示すべての承認ノードを表示) をサポートしています。コールバックペイロードの内容は、選択した統合方法によって異なります。

    • 最終結果のみ

      この統合方法では、承認プロセスの最終結果のみを返す必要があります。Dataphin では、開始ノードと終了ノードのみが表示されます。サードパーティシステムで承認プロセスが完了した後にのみ、コールバックインターフェイスを呼び出してください。以下はペイロード構造の例です。

      {
         "applyId": "123456",
         "applyStatus": "accept",
         "comment": "承認済み",
         "processInstanceId": "qwqwqqq"
      }
      説明
      • この統合方法では、nodes フィールドは不要です。

      • applyStatus フィールドは acceptreject、または revoke に設定できます。値 approving は、承認が進行中であることを示します。これは、サードパーティ承認用のすべてのノード統合方法において、表示にのみ使用される中間状態です。

    • すべての承認ノード

      この統合方法では、各承認ノードの詳細を返す必要があります。これにより、Dataphin はすべての承認ノードを表示して同期できます。承認者が操作を実行したら、このコールバックインターフェイスを呼び出して、現在のノード情報で Dataphin を更新してください。

      フィールド参照
      • この統合方法では、applyIdapplyStatusprocessInstanceId、および nodes フィールドを渡す必要があります。

      • 申請全体の承認ステータス (applyStatus)。有効な値:approvingacceptrejectrevoke

        • いずれかの承認ノードが最終状態でない場合は、applyStatusapproving を設定します。

        • すべての承認ノードが承認された場合は、applyStatusaccept を設定します。

        • いずれかの承認ノードが却下された場合は、applyStatusreject を設定します。

        • いずれかの承認ノードが取り消された場合は、applyStatusrevoke を設定します。

      • 承認ノードのリストは内部の nodeId に従ってソートされます。nodeId は連番 (例:1、2、3) にする必要があります。

      • ノードステータス (nodeStatus)。有効な値:APPROVINGACCEPTEDREJECTEDREVOKED

        • 現在の承認ノードが進行中の場合は、nodeStatusAPPROVING を設定します。

        • 現在の承認ノードが承認された場合は、nodeStatusACCEPTED を設定します。

        • 現在の承認ノードが却下された場合は、nodeStatusREJECTED を設定します。

        • 現在の承認ノードが取り消された場合は、nodeStatusREVOKED を設定します。

      • ノードの表示名 (nodeName)。

      • ノードの承認関係 (approverRelation)。有効な値:ORAND

        • OR:いずれか 1 人の承認者が承認すると、そのノードは承認済みになります。

        • AND:すべての承認者が承認した後にのみ、そのノードは承認済みになります。

      • 承認待ちの承認者 (pendingApprovers)。

        • まだ操作していない承認者のリストです。

        • 承認者が操作した場合は、次回のコールバックでこのリストから削除して、その操作を records リストに追加する必要があります。

      • 操作記録 (records)。

        • 操作を実行したユーザー (operateUser)。

        • 操作のコメント (comment)。

        • 操作時刻 (operatedTime)。records リストは、operatedTime の昇順にソートする必要があります。

        • 操作タイプ (action)。有効な値:ASSIGN_APPROVECOUNTER_SIGN_APPROVEREVOKE_APPLYAPPROVE

          • approverRelationOR で、承認者が承認した場合は、actionAPPROVE に設定し、nodeStatusACCEPTED に設定します。

          • approverRelationOR で、承認者が却下した場合は、actionAPPROVE に設定し、nodeStatusREJECTED に設定します。

          • approverRelationOR で、承認者が取り消した場合は、actionREVOKE_APPLY に設定し、nodeStatusREVOKED に設定します。

          • 承認者がタスクを転送した場合は、actionASSIGN_APPROVE に設定し、nodeStatusACCEPTED に設定します。

          • 承認者がカウンターサインを追加した場合は、actionCOUNTER_SIGN_APPROVE に設定し、nodeStatusACCEPTED に設定します。

          • approverRelationAND で承認者が承認した場合は、actionAPPROVE に設定します。ほかの承認者がまだ操作していない場合、nodeStatusAPPROVING のままです。すべての承認者が承認したら、nodeStatusACCEPTED に設定します。

          • approverRelationAND で承認者が却下した場合は、actionAPPROVE に設定し、nodeStatusREJECTED に設定します。

          • approverRelationAND で承認者が取り消した場合は、actionREVOKE_APPLY に設定し、nodeStatusREVOKED に設定します。

        • 転送先の承認者 (transferApprovers)。このフィールドには、承認の転送またはカウンターサインの追加を受け取るユーザーを指定します。

      承認シナリオ
      • シナリオ:OR 関係のノードが複数あり、操作が行われていない

        例:

        サードパーティシステムの承認リクエストには 2 つの承認ノードがあり、nodeId に従ってソートされます。

        1 つ目の承認ノードでは、承認待ちの承認者である田中 太郎と鈴木 一郎がまだ操作していません。pendingApprovers リストには、両ユーザーの情報が含まれます。操作が行われていないため、nodeStatusAPPROVING で、records リストは空です。

        2 つ目の承認ノードでは、承認待ちの承認者である佐藤 次郎がまだ操作していません。pendingApprovers リストには佐藤 次郎が含まれ、records リストは空です。

        いずれの承認ノードも最終状態ではないため、申請全体の applyStatusapproving になります。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "approving",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "OR",
                 "pendingApprovers": [
                    {
                       "userId": "1111",
                       "userName": "田中 太郎"
                    },
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": []
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "OR",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }
      • シナリオ:OR 関係で、1 つ目のノードが一部承認済み、2 つ目のノードが承認待ち

        例:

        承認リクエストには 2 つの承認ノードがあり、nodeId に従ってソートされます。

        1 つ目のノードでは、田中 太郎が承認済みで、鈴木 一郎はまだ操作していません。pendingApprovers リストには鈴木 一郎のみが含まれます。approverRelationOR のため、田中 太郎の承認により nodeStatusACCEPTED に変わります。records リストには田中 太郎の操作が含まれ、action フィールドは APPROVE に設定され、コメントが指定されています。

        2 つ目のノードでは、承認者が誰も操作していません。nodeStatusAPPROVING で、pendingApprovers リストには佐藤 次郎が含まれます。

        2 つ目の承認ノードが完了していないため、申請全体の applyStatus は引き続き approving になります。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "approving",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "ACCEPTED",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "OR",
                 "pendingApprovers": [
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を承認します",
                       "operatedTime": "2026-03-19 19:01:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "OR",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }
      • シナリオ:OR 関係で、両ノードが承認済み、申請が承認

        例:

        承認リクエストには 2 つの承認ノードがあり、nodeId に従ってソートされます。

        1 つ目のノードでは、approverRelationOR のため、田中 太郎の承認だけで nodeStatusACCEPTED に設定できます。pendingApprovers リストには引き続き鈴木 一郎が含まれ、records リストには田中 太郎の操作が含まれます。

        2 つ目のノードでは、唯一の承認者である佐藤 次郎が承認済みです。nodeStatusACCEPTED で、pendingApprovers リストは空になります。records リストには佐藤 次郎の操作が含まれます。

        両方の承認ノードが承認済みのため、申請全体の applyStatusaccept になります。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "accept",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "ACCEPTED",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "OR",
                 "pendingApprovers": [
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を承認します",
                       "operatedTime": "2026-03-19 19:01:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "ACCEPTED",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "OR",
                 "pendingApprovers": [],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "33333",
                          "userName": "佐藤 次郎"
                       },
                       "action": "APPROVE",
                       "comment": "佐藤 次郎が権限リクエストを承認します",
                       "operatedTime": "2026-03-19 19:07:21"
                    }
                 ]
              }
           ]
        }
      • シナリオ:OR 関係で、いずれかのノードが却下され、申請が却下

        例:

        承認リクエストには 2 つの承認ノードがあり、nodeId に従ってソートされます。

        1 つ目のノードでは、田中 太郎が承認済みのため、nodeStatusACCEPTED です。

        2 つ目のノードでは、唯一の承認者である佐藤 次郎が申請を却下しました。nodeStatusREJECTED になり、records リストには佐藤 次郎の操作が含まれます。

        1 つ目のノードは承認済みですが、2 つ目のノードの却下によりプロセスが終了するため、申請全体の applyStatusreject に設定されます。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "reject",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "ACCEPTED",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "OR",
                 "pendingApprovers": [
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を承認します",
                       "operatedTime": "2026-03-19 19:01:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "REJECTED",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "OR",
                 "pendingApprovers": [],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "33333",
                          "userName": "佐藤 次郎"
                       },
                       "action": "APPROVE",
                       "comment": "佐藤 次郎が権限リクエストを却下しました",
                       "operatedTime": "2026-03-19 19:07:21"
                    }
                 ]
              }
           ]
        }
      • シナリオ:OR 関係で、いずれかのノードが取り消され、申請が取り消し

        例:

        承認リクエストには 2 つの承認ノードがあり、nodeId に従ってソートされます。

        1 つ目のノードでは、田中 太郎が承認済みのため、nodeStatusACCEPTED です。

        2 つ目のノードでは、佐藤 次郎が承認を取り消しました。nodeStatusREVOKED になり、records リストには佐藤 次郎の操作が含まれ、action フィールドは REVOKE_APPLY に設定されます。

        2 つ目のノードが取り消されたため、申請全体の applyStatusrevoke に設定されます。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "revoke",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "ACCEPTED",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "OR",
                 "pendingApprovers": [
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を承認します",
                       "operatedTime": "2026-03-19 19:01:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "REVOKED",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "OR",
                 "pendingApprovers": [],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "33333",
                          "userName": "佐藤 次郎"
                       },
                       "action": "REVOKE_APPLY",
                       "comment": "佐藤 次郎がこの権限承認を取り消しました",
                       "operatedTime": "2026-03-19 19:07:21"
                    }
                 ]
              }
           ]
        }
      • シナリオ:AND 関係で、一部承認済み(最終状態なし)

        例:

        承認リクエストには 2 つの承認ノードがあり、nodeId に従ってソートされます。

        1 つ目のノードでは、AND 関係で、田中 太郎が承認済みですが、鈴木 一郎はまだ操作していません。pendingApprovers リストには引き続き鈴木 一郎が含まれます。すべての承認者が操作していないため、nodeStatusAPPROVING のままです。records リストには田中 太郎の操作が含まれます。

        2 つ目のノードでは、誰も操作していないため、nodeStatusAPPROVING です。

        いずれのノードも最終状態に達していないため、申請全体の applyStatusapproving です。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "approving",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を承認します",
                       "operatedTime": "2026-03-19 19:01:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }
      • シナリオ:AND 関係で、1 つ目のノードが承認済み、2 つ目のノードが承認待ち

        例:

        承認リクエストには 2 つの承認ノードがあり、nodeId に従ってソートされます。

        1 つ目のノードでは、approverRelationAND です。田中 太郎と鈴木 一郎の両方が承認済みです。pendingApprovers リストは空になります。すべての承認者が承認したため、nodeStatusACCEPTED になります。records リストには両ユーザーの操作が含まれます。

        2 つ目のノードでは、誰も操作していないため、nodeStatusAPPROVING で、pendingApprovers リストには佐藤 次郎が含まれます。

        1 つ目のノードは最終状態に達していますが、2 つ目のノードは達していません。そのため、申請全体の applyStatusapproving のままです。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "approving",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "ACCEPTED",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を承認します",
                       "operatedTime": "2026-03-19 19:01:23"
                    },
                    {
                       "operateUser": {
                          "userId": "2222",
                          "userName": "鈴木 一郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を承認します",
                       "operatedTime": "2026-03-19 19:02:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }
      • シナリオ:AND 関係で、いずれかのノードが却下され、申請が却下

        例:

        承認リクエストには 2 つの承認ノードがあり、nodeId に従ってソートされます。

        1 つ目のノードでは、approverRelationAND です。田中 太郎は承認済みですが、鈴木 一郎は却下しました。両者とも操作したため、pendingApprovers リストは空です。鈴木 一郎が却下したため、nodeStatusREJECTED になります。

        2 つ目のノードでは、誰も操作していません。nodeStatus は引き続き APPROVING です。

        ただし、1 つ目のノードの却下によりプロセス全体が終了するため、申請全体の applyStatus は直ちに reject に設定されます。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "reject",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "REJECTED",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を承認します",
                       "operatedTime": "2026-03-19 19:01:23"
                    },
                    {
                       "operateUser": {
                          "userId": "2222",
                          "userName": "鈴木 一郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を却下します",
                       "operatedTime": "2026-03-19 19:02:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }
      • シナリオ:AND 関係で、いずれかのノードが取り消され、申請が取り消し

        例:

        承認リクエストには 2 つの承認ノードがあり、nodeId に従ってソートされます。

        1 つ目のノードでは、approverRelationAND です。田中 太郎は承認済みですが、鈴木 一郎は取り消しました。両者とも操作したため、pendingApprovers リストは空です。鈴木 一郎が承認を取り消したため、nodeStatusREVOKED に設定されます。records リストにある鈴木 一郎の操作では、actionREVOKE_APPLY に設定されます。

        2 つ目のノードでは、誰も操作していません。nodeStatus は引き続き APPROVING です。

        1 つ目のノードの取り消しによりプロセス全体が終了するため、申請全体の applyStatus は直ちに revoke に設定されます。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "revoke",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "REVOKED",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "APPROVE",
                       "comment": "このテーブルの権限を承認します",
                       "operatedTime": "2026-03-19 19:01:23"
                    },
                    {
                       "operateUser": {
                          "userId": "2222",
                          "userName": "鈴木 一郎"
                       },
                       "action": "REVOKE_APPLY",
                       "comment": "このテーブルの権限を取り消します",
                       "operatedTime": "2026-03-19 19:02:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }
      • シナリオ:AND 関係で、承認の転送

        当初、承認リクエストには 2 つのノードがあります。1 つ目のノードは田中 太郎と鈴木 一郎の承認が必要で、2 つ目のノードは佐藤 次郎の承認が必要です。両方のノードは承認待ちです。

        承認リクエストには当初 2 つの承認ノードがあります。1 つ目の承認ノードの承認者は田中 太郎と鈴木 一郎で、2 つ目の承認ノードの承認者は佐藤 次郎です。両方のノードは承認待ちの状態です。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "approving",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "1111",
                       "userName": "田中 太郎"
                    },
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": []
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }

        1 つ目のノードの田中 太郎が承認を伊藤 三郎に転送すると、システムは、転送を表す新しいノードをワークフローに挿入します。この新しいノードの records には、田中 太郎が伊藤 三郎に対して転送 (ASSIGN_APPROVE) を実行したことが記録されます。この新しい転送ノードの nodeStatusACCEPTED です。

        転送後、元の 1 つ目のノードの pendingApprovers リストは、鈴木 一郎と新しい承認者である伊藤 三郎を含むように更新されます。転送操作によりフローの先頭に新しいノードが挿入されたため、元の 2 つのノードの nodeId はそれぞれ 2 と 3 に繰り下がります。

        2 つ目の元のノード (現在の nodeId: 3) は変更されず、承認待ちの承認者は佐藤 次郎のままです。

        ノード 2 と 3 は最終状態に達していないため、申請全体の applyStatus は引き続き approving です。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "approving",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "ACCEPTED",
                 "nodeName": "Transfer Node Test 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "ASSIGN_APPROVE",
                       "comment": "伊藤 三郎に承認を転送",
                       "transferApprovers": {
                          "userId": "7777",
                          "userName": "伊藤 三郎"
                       },
                       "operatedTime": "2026-03-19 19:01:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "7777",
                       "userName": "伊藤 三郎"
                    },
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": []
              },
              {
                 "nodeId": "3",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }
      • シナリオ:AND 関係で、カウンターサインの追加

        当初、承認リクエストには 2 つのノードがあります。1 つ目のノードは田中 太郎と鈴木 一郎の承認が必要で、2 つ目のノードは佐藤 次郎の承認が必要です。両方のノードは承認待ちです。

        承認リクエストには当初 2 つの承認ノードがあります。1 つ目のノードの承認者は田中 太郎と鈴木 一郎で、2 つ目のノードの承認者は佐藤 次郎です。両方のノードは承認待ちの状態です。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "approving",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "1111",
                       "userName": "田中 太郎"
                    },
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": []
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }

        田中 太郎が 1 つ目のノードで伊藤 三郎を承認者としてカウンターサインを追加すると、システムは、カウンターサインのプロセスを表す 2 つの新しいノードをワークフローに挿入します。

        1 つ目の新しいノード (nodeId: 1) は、カウンターサインの追加操作そのものを表します。このノードの nodeStatusACCEPTED で、records リストには田中 太郎が COUNTER_SIGN_APPROVE を実行し、transferApprovers に伊藤 三郎を指定したことが記録されます。

        2 つ目の新しいノード (nodeId: 2) は、伊藤 三郎に割り当てられたタスクを表します。このノードの nodeStatusAPPROVING で、pendingApprovers リストに伊藤 三郎が含まれます。

        カウンターサインのフローの 2 つの新しいノードにより、元のノードはそれぞれ nodeId: 3nodeId: 4 に繰り下がります。

        ノード 3 (元の 1 つ目のノード) は、引き続き田中 太郎と鈴木 一郎の承認が必要で、APPROVING 状態のままです。

        ノード 4 (元の 2 つ目のノード) も変更されず、APPROVING 状態のままです。

        ノード 2、3、4 は最終状態に達していないため、申請全体の applyStatus は引き続き approving です。

        2 つ目、3 つ目、4 つ目の承認ノードが最終状態に達していないため、申請全体の承認ステータスは approving です。

        {
           "applyId": "123456",
           "processInstanceId": "qwqwqeqe",
           "applyStatus": "approving",
           "nodes": [
              {
                 "nodeId": "1",
                 "nodeStatus": "ACCEPTED",
                 "nodeName": "Countersign Node Test 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [],
                 "records": [
                    {
                       "operateUser": {
                          "userId": "1111",
                          "userName": "田中 太郎"
                       },
                       "action": "COUNTER_SIGN_APPROVE",
                       "comment": "伊藤 三郎に承認を求めるため、カウンターサインを追加",
                       "transferApprovers": {
                          "userId": "7777",
                          "userName": "伊藤 三郎"
                       },
                       "operatedTime": "2026-03-19 19:01:23"
                    }
                 ]
              },
              {
                 "nodeId": "2",
                 "nodeStatus": "APPROVING",
                 "nodeName": "伊藤 三郎の承認のためのカウンターサインノード",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "7777",
                       "userName": "伊藤 三郎"
                    }
                 ],
                 "records": []
              },
              {
                 "nodeId": "3",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 1",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "1111",
                       "userName": "田中 太郎"
                    },
                    {
                       "userId": "2222",
                       "userName": "鈴木 一郎"
                    }
                 ],
                 "records": []
              },
              {
                 "nodeId": "4",
                 "nodeStatus": "APPROVING",
                 "nodeName": "Approval Test Node 2",
                 "approverRelation": "AND",
                 "pendingApprovers": [
                    {
                       "userId": "33333",
                       "userName": "佐藤 次郎"
                    }
                 ],
                 "records": []
              }
           ]
        }
  • 暗号化と復号

    暗号化(例:BPMS がコールバックを受信する場合):

    Map<String, String> callBackJson = Maps.newHashMap();
    callBackJson.put("applyId", "1");
    callBackJson.put("applyStatus", "accept");
    callBackJson.put("processInstanceId", "2");
    callBackJson.put("comment", "test");
    // 統合方法として "Display all nodes of the third-party approval" を選択した場合は、nodes フィールドに値を設定します。
    String nodesJson = "[{\"approverRelation\":\"OR\",\"nodeId\":\"1\",\"nodeName\":\"Execute Pass Node Test\",\"nodeStatus\":\"ACCEPTED\",\"pendingApprovers\":[],\"records\":[{\"action\":\"APPROVE\",\"comment\":\"Approval granted\",\"operateUser\":{\"userId\":\"22222\",\"userName\":\"Zhang San\"},\"operatedTime\":\"2026-03-18 15:14:23\"}]}]";
    callBackJson.put("nodes", nodesJson)
    String callBackResult = JSON.toJSONString(callBackJson);
    
    ThirdPartyCrypto callbackCrypto = new ThirdPartyCrypto(token, aesKey);
    
    String timestamp = String.valueOf(System.currentTimeMillis());
    String nonce = ThirdPartyCrypto.Utils.getRandomStr(16);
    String encrypt = callbackCrypto.encrypt(nonce, callBackResult);
    String signature = callbackCrypto.getSignature(token, timestamp, nonce, encrypt);

    復号(例:BPMS が success メッセージを返す場合):

    String encryptMsg = encrypt;
    String decryptMsg = callbackCrypto.getDecryptMsg(signature, timestamp, nonce, encryptMsg);
    if ("success".equalsIgnoreCase(decryptMsg)) {
     log.error("call back success");
    }

    暗号化と復号のユーティリティ

    import com.alibaba.fastjson.JSON;
    import org.apache.commons.codec.binary.Base64;
    
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.io.ByteArrayOutputStream;
    import java.lang.reflect.Field;
    import java.nio.charset.Charset;
    import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    import java.security.Permission;
    import java.security.PermissionCollection;
    import java.security.Security;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Random;
    
    /**
     * Dataphin オープンプラットフォーム向けの暗号化と復号の方法です。
     */
    public class ThirdPartyCrypto {
    
     private static final Charset CHARSET = StandardCharsets.UTF_8;
     private static final Base64 BASE_64 = new Base64();
     private final byte[] AES_KEY;
     private final String TOKEN;
    
     /**
     * エンコーディング AES キーの固定長。
     **/
     private static final Integer AES_ENCODE_KEY_LENGTH = 43;
     /**
     * 暗号化に使用するランダム文字列のバイト長。
     **/
     private static final Integer RANDOM_LENGTH = 16;
    
     /**
     * コンストラクター。
     *
     * @param token 開発者が設定するトークン。
     * @param encodingAesKey 開発者が設定する EncodingAESKey。
     *
     * @throws ThirdPartyEncryptException 操作に失敗した場合にスローされます。エラーコードとメッセージについては、例外を参照してください。
     */
     public ThirdPartyCrypto(String token, String encodingAesKey) throws ThirdPartyEncryptException {
     if (null == encodingAesKey || encodingAesKey.length() != AES_ENCODE_KEY_LENGTH) {
     throw new ThirdPartyEncryptException(ThirdPartyEncryptException.AES_KEY_ILLEGAL);
     }
     this.TOKEN = token;
     AES_KEY = Base64.decodeBase64(encodingAesKey + "=");
     }
    
     public Map<String, String> getEncryptedMap(String plaintext) throws ThirdPartyEncryptException {
     return getEncryptedMap(plaintext, System.currentTimeMillis(), Utils.getRandomStr(16));
     }
    
     /**
     * Dataphin と同期するためにメッセージ本文を暗号化し、暗号化されたマップを返します。
     *
     * @param plaintext メッセージ本文のプレーンテキスト。
     * @param timeStamp リクエストのタイムスタンプ。
     * @param nonce ランダム文字列(ノンス)。
     * @return
     * @throws ThirdPartyEncryptException
     */
     public Map<String, String> getEncryptedMap(String plaintext, Long timeStamp, String nonce)
     throws ThirdPartyEncryptException {
     if (null == plaintext) {
     throw new ThirdPartyEncryptException(ThirdPartyEncryptException.ENCRYPTION_PLAINTEXT_ILLEGAL);
     }
     if (null == timeStamp) {
     throw new ThirdPartyEncryptException(ThirdPartyEncryptException.ENCRYPTION_TIMESTAMP_ILLEGAL);
     }
     if (null == nonce) {
     throw new ThirdPartyEncryptException(ThirdPartyEncryptException.ENCRYPTION_NONCE_ILLEGAL);
     }
     // 暗号化
     String encrypt = encrypt(Utils.getRandomStr(RANDOM_LENGTH), plaintext);
     String signature = getSignature(TOKEN, String.valueOf(timeStamp), nonce, encrypt);
     Map<String, String> resultMap = new HashMap<String, String>();
     resultMap.put("msg_signature", signature);
     resultMap.put("encrypt", encrypt);
     resultMap.put("timeStamp", String.valueOf(timeStamp));
     resultMap.put("nonce", nonce);
     return resultMap;
     }
    
     /**
     * 暗号文を復号します。
     *
     * @param msgSignature 署名文字列。
     * @param timeStamp タイムスタンプ。
     * @param nonce ランダム文字列。
     * @param encryptMsg Base64 エンコードされた暗号文。
     * @return 復号後のプレーンテキスト。
     * @throws ThirdPartyEncryptException
     */
     public String getDecryptMsg(String msgSignature, String timeStamp, String nonce, String encryptMsg)
     throws ThirdPartyEncryptException {
     // 署名を検証します。
     String signature = getSignature(TOKEN, timeStamp, nonce, encryptMsg);
     if (!signature.equals(msgSignature)) {
     throw new ThirdPartyEncryptException(ThirdPartyEncryptException.SIGNATURE_NOT_MATCH);
     }
     // 復号します。
     return decrypt(encryptMsg);
     }
    
     /**
     * プレーンテキストを暗号化します。
     * @param plaintext 暗号化するプレーンテキスト。
     * @return Base64 エンコードされた暗号文。
     */
     public String encrypt(String random, String plaintext) throws ThirdPartyEncryptException {
     try {
     byte[] randomBytes = random.getBytes(CHARSET);
     byte[] plainTextBytes = plaintext.getBytes(CHARSET);
     byte[] lengthByte = Utils.int2Bytes(plainTextBytes.length);
     ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
     byteStream.write(randomBytes);
     byteStream.write(lengthByte);
     byteStream.write(plainTextBytes);
     byte[] padBytes = PKCS7Padding.getPaddingBytes(byteStream.size());
     byteStream.write(padBytes);
     byte[] unencrypted = byteStream.toByteArray();
     byteStream.close();
     Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
     SecretKeySpec keySpec = new SecretKeySpec(AES_KEY, "AES");
     IvParameterSpec iv = new IvParameterSpec(AES_KEY, 0, 16);
     cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
     byte[] encrypted = cipher.doFinal(unencrypted);
     String result = BASE_64.encodeToString(encrypted);
     return result;
     } catch (Exception e) {
     throw new ThirdPartyEncryptException(ThirdPartyEncryptException.COMPUTE_ENCRYPT_TEXT_ERROR);
     }
     }
    
     /**
     * 暗号文を復号します。
     * @param text 復号する暗号文。
     * @return 復号後のプレーンテキスト。
     */
     private String decrypt(String text) throws ThirdPartyEncryptException {
     byte[] originalArr;
     try {
     // 復号モードを AES/CBC に設定します。
     Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
     SecretKeySpec keySpec = new SecretKeySpec(AES_KEY, "AES");
     IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(AES_KEY, 0, 16));
     cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
     // Base64 を使用して暗号文をデコードします。
     byte[] encrypted = Base64.decodeBase64(text);
     // 復号します。
     originalArr = cipher.doFinal(encrypted);
     } catch (Exception e) {
     throw new ThirdPartyEncryptException(ThirdPartyEncryptException.COMPUTE_DECRYPT_TEXT_ERROR);
     }
    
     String plainText;
     try {
     // パディングバイトを削除します。
     byte[] bytes = PKCS7Padding.removePaddingBytes(originalArr);
     // 16 バイトのランダム文字列とネットワークバイトオーダーを抽出します。
     byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
     int plainTextLegth = Utils.bytes2int(networkOrder);
     plainText = new String(Arrays.copyOfRange(bytes, 20, 20 + plainTextLegth), CHARSET);
     } catch (Exception e) {
     throw new ThirdPartyEncryptException(ThirdPartyEncryptException.COMPUTE_DECRYPT_TEXT_LENGTH_ERROR);
     }
    
     return plainText;
     }
    
     /**
     * 署名を計算します。
     *
     * @param token ISV トークン。
     * @param timestamp タイムスタンプ。
     * @param nonce ランダム文字列。
     * @param encrypt Base64 エンコードされた暗号文。
     * @return
     * @throws ThirdPartyEncryptException
     */
     public String getSignature(String token, String timestamp, String nonce, String encrypt)
     throws ThirdPartyEncryptException {
     try {
     String[] array = new String[] {token, timestamp, nonce, encrypt};
     Arrays.sort(array);
     System.out.println(JSON.toJSONString(array));
     StringBuffer sb = new StringBuffer();
     for (int i = 0; i < 4; i++) {
     sb.append(array[i]);
     }
     String str = sb.toString();
     System.out.println(str);
     MessageDigest md = MessageDigest.getInstance("SHA-1");
     md.update(str.getBytes());
     byte[] digest = md.digest();
    
     StringBuffer hexstr = new StringBuffer();
     String shaHex = "";
     for (int i = 0; i < digest.length; i++) {
     shaHex = Integer.toHexString(digest[i] & 0xFF);
     if (shaHex.length() < 2) {
     hexstr.append(0);
     }
     hexstr.append(shaHex);
     }
     return hexstr.toString();
     } catch (Exception e) {
     throw new ThirdPartyEncryptException(ThirdPartyEncryptException.COMPUTE_SIGNATURE_ERROR);
     }
     }
    
     public static class Utils {
     public Utils() {
     }
    
     public static String getRandomStr(int count) {
     String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
     Random random = new Random();
     StringBuffer sb = new StringBuffer();
    
     for (int i = 0; i < count; ++i) {
     int number = random.nextInt(base.length());
     sb.append(base.charAt(number));
     }
    
     return sb.toString();
     }
    
     public static byte[] int2Bytes(int count) {
     byte[] byteArr = new byte[] {(byte)(count >> 24 & 255), (byte)(count >> 16 & 255), (byte)(count >> 8 & 255),
     (byte)(count & 255)};
     return byteArr;
     }
    
     public static int bytes2int(byte[] byteArr) {
     int count = 0;
    
     for (int i = 0; i < 4; ++i) {
     count <<= 8;
     count |= byteArr[i] & 255;
     }
    
     return count;
     }
     }
    
     public static class PKCS7Padding {
     private static final Charset CHARSET = StandardCharsets.UTF_8;
     private static final int BLOCK_SIZE = 32;
    
     public PKCS7Padding() {
     }
    
     public static byte[] getPaddingBytes(int count) {
     int amountToPad = 32 - count % 32;
     if (amountToPad == 0) {
     amountToPad = 32;
     }
    
     char padChr = chr(amountToPad);
     String tmp = new String();
    
     for (int index = 0; index < amountToPad; ++index) {
     tmp = tmp + padChr;
     }
    
     return tmp.getBytes(CHARSET);
     }
    
     public static byte[] removePaddingBytes(byte[] decrypted) {
     int pad = decrypted[decrypted.length - 1];
     if (pad < 1 || pad > 32) {
     pad = 0;
     }
    
     return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
     }
    
     private static char chr(int a) {
     byte target = (byte)(a & 255);
     return (char)target;
     }
     }
    
     public static class ThirdPartyEncryptException extends Exception {
     public static final int SUCCESS = 0;
     public static final int ENCRYPTION_PLAINTEXT_ILLEGAL = 900001;
     public static final int ENCRYPTION_TIMESTAMP_ILLEGAL = 900002;
     public static final int ENCRYPTION_NONCE_ILLEGAL = 900003;
     public static final int AES_KEY_ILLEGAL = 900004;
     public static final int SIGNATURE_NOT_MATCH = 900005;
     public static final int COMPUTE_SIGNATURE_ERROR = 900006;
     public static final int COMPUTE_ENCRYPT_TEXT_ERROR = 900007;
     public static final int COMPUTE_DECRYPT_TEXT_ERROR = 900008;
     public static final int COMPUTE_DECRYPT_TEXT_LENGTH_ERROR = 900009;
     public static final int COMPUTE_DECRYPT_TEXT_CORPID_ERROR = 900010;
     private static Map<Integer, String> msgMap = new HashMap();
     private Integer code;
    
     static {
     msgMap.put(0, "Success");
     msgMap.put(900001, "Invalid plaintext for encryption");
     msgMap.put(900002, "Invalid timestamp parameter for encryption");
     msgMap.put(900003, "Invalid nonce parameter for encryption");
     msgMap.put(900005, "Signature mismatch");
     msgMap.put(900006, "Failed to compute signature");
     msgMap.put(900004, "Invalid AES key");
     msgMap.put(900007, "Failed to compute ciphertext");
     msgMap.put(900008, "Failed to decrypt text");
     msgMap.put(900009, "Plaintext length mismatch");
     msgMap.put(900010, "CorpId mismatch in decrypted plaintext");
     }
    
     public Integer getCode() {
     return this.code;
     }
    
     public ThirdPartyEncryptException(Integer exceptionCode) {
     super((String)msgMap.get(exceptionCode));
     this.code = exceptionCode;
     }
     }
     static {
     try {
     Security.setProperty("crypto.policy", "limited");
     RemoveCryptographyRestrictions();
     } catch (Exception var1) {
     }
    
     }
     private static void RemoveCryptographyRestrictions() throws Exception {
     Class<?> jceSecurity = getClazz("javax.crypto.JceSecurity");
     Class<?> cryptoPermissions = getClazz("javax.crypto.CryptoPermissions");
     Class<?> cryptoAllPermission = getClazz("javax.crypto.CryptoAllPermission");
     if (jceSecurity != null) {
     setFinalStaticValue(jceSecurity, "isRestricted", false);
     PermissionCollection defaultPolicy = (PermissionCollection)getFieldValue(jceSecurity, "defaultPolicy", (Object)null, PermissionCollection.class);
     if (cryptoPermissions != null) {
     Map<?, ?> map = (Map)getFieldValue(cryptoPermissions, "perms", defaultPolicy, Map.class);
     map.clear();
     }
    
     if (cryptoAllPermission != null) {
     Permission permission = (Permission)getFieldValue(cryptoAllPermission, "INSTANCE", (Object)null, Permission.class);
     defaultPolicy.add(permission);
     }
     }
    
     }
     private static Class<?> getClazz(String className) {
     Class clazz = null;
    
     try {
     clazz = Class.forName(className);
     } catch (Exception var3) {
     }
    
     return clazz;
     }
     private static void setFinalStaticValue(Class<?> srcClazz, String fieldName, Object newValue) throws Exception {
     Field field = srcClazz.getDeclaredField(fieldName);
     field.setAccessible(true);
     Field modifiersField = Field.class.getDeclaredField("modifiers");
     modifiersField.setAccessible(true);
     modifiersField.setInt(field, field.getModifiers() & -17);
     field.set((Object)null, newValue);
     }
     private static <T> T getFieldValue(Class<?> srcClazz, String fieldName, Object owner, Class<T> dstClazz) throws Exception {
     Field field = srcClazz.getDeclaredField(fieldName);
     field.setAccessible(true);
     return dstClazz.cast(field.get(owner));
     }
    
    }