Developer Guide
ご覧のページは、お客様の利便性のために一部機械翻訳されています。また、ドキュメントは頻繁に更新が加えられており、翻訳は未完成の部分が含まれることをご了承ください。最新情報は都度公開されておりますため、必ず英語版をご参照ください。翻訳に問題がある場合は、 こちら までご連絡ください。

フォームストレージアダプターの書き込み

LPS-97208 の修正を含む Liferay DXP 7.3 および Liferay DXP 7.2 バージョン (Liferay DXP 7.2 SP3 で予定)

デフォルトでは、フォームはLiferay DXPのデータベースにJSONとして保存されます。 この例では、フォームレコードの永続化イベントにカスタムロジックを挿入するために、新しいストレージアダプターを実装する方法を紹介します。

DDMストレージアダプターを使用して、フォームアプリケーションにストレージタイプを追加します。

デフォルトのストレージアダプタ は、フォームレコードを Liferay DXP データベースに JSON コンテンツとして保存します。 次に、各フォーム レコードをファイル システムに保存するロジックを追加します。

実行中のDDMストレージアダプターを調べる

ストレージアダプターの動作を確認するために、サンプルをデプロイし、サンプルアダプターを使用していくつかのフォームデータを追加します。

サンプルをデプロイする

新しいLiferay インスタンスを起動し、以下を実行します。

docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.132-ga132

http://localhost:8080でLiferayにサインインします。 メールアドレス test@liferay.com とパスワード testを使用してください。 プロンプトが表示されたら、パスワードを learnに変更します。

次に、以下の手順に従います。

  1. DDM ストレージ アダプタ プロジェクトをダウンロードして解凍します

    curl https://resources.learn.liferay.com/examples/liferay-r2f1.zip -O
    
    unzip liferay-r2f1.zip
    
  2. モジュールのルートから、ビルドおよびデプロイします。

    ./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    
    ヒント

    このコマンドは、デプロイされたjarをDockerコンテナ上の /opt/liferay/osgi/modules にコピーするのと同じです。

  3. Liferay Dockerコンテナコンソールでデプロイを確認します。

    STARTED com.acme.r2f1.impl_1.0.0 [1009]
    

デプロイされたストレージアダプターを使用する

  1. ブラウザを開いて http://localhost:8080にアクセスします。

  2. サイト メニューコンテンツ & データフォームでフォーム アプリケーションに移動します。

  3. 追加 (Add) をクリックして、フォーム ビルダーを開きます。

  4. フォーム ビルダー ビューで、 オプション (Options) をクリックし、 設定 ウィンドウを開きます。

  5. ストレージ タイプの選択で、 R2F1 ダイナミック データ マッピング ストレージ アダプタ タイプを選択し、 完了をクリックします。

  6. フォームに テキスト フィールド を追加し、フォームを公開して、数回送信します。

  7. フォームデータが保持されていることを確認するには、フォームのレコードに移動します。

    サイト メニューコンテンツフォームから、フォームの アクション ボタン (Actions) をクリックし、次に エントリの表示をクリックします。

    フォームエントリーが追加されたことを確認します。

  8. さらに、各CRUDメソッドにロギングが提供され、サンプルのメソッドが呼び出されていることが示されています。

    WARN  [http-nio-8080-exec-5][R2F1DDMStorageAdapter:82] Acme storage adapter's save method was invoked
    

拡張ポイントを理解する

この例には、R2F1DDMStorageAdapterという1つのクラスのみが含まれています。これは、フォームエントリーを格納するためのロジックを提供するDDMStorageAdapterを実装しているサービスです。 現在デプロイされている例では、デフォルトの JSON 実装をラップするだけです: DefaultDDMStorageAdapter。 後で、既存のコードにファイル システム ストレージを追加します。

アダプタークラスをOSGiコンテナに登録する

DDMFileSystemStorageAdapterは、DDMStorageAdapterインターフェイスを実装していますが、OSGiサービスとして登録する必要があります。

@Component(
	property = "ddm.storage.adapter.type=r2f1-ddm-storage-adapter",
	service = DDMStorageAdapter.class
)
public class R2F1DDMStorageAdapter implements DDMStorageAdapter {

r2f1-ddm-storage-adapter キーは、 src/main/resources/content/Language.properties ファイルと bnd.bnd ファイル内の Provide-Capability ヘッダーによって値 R2F1 Dynamic Data Mapping Storage Adapter にローカライズされます。

serviceコンポーネントプロパティは、実装をDDMStorageAdapterサービスとして登録します。

プロパティddm.storage.adapter.typeは識別子を提供し、サービスが一意のDDMStorageAdapterの実装として登録されるようにします。 他のサービスでも次のように参照できるようになりました。

@Reference(target = "(ddm.storage.adapter.type=r2f1-ddm-storage-adapter)")
private DDMStorageAdapter defaultWrapperDDMStorageAdapter;

DDMStorageAdapterインターフェイスを理解する

このインターフェイスでは、フォームレコードのCRUD操作を処理するために、deletegetsaveの3つのメソッドが必要です(更新ロジックも処理します)。

public DDMStorageAdapterDeleteResponse delete(
        DDMStorageAdapterDeleteRequest ddmStorageAdapterDeleteRequest)
    throws StorageException;
public DDMStorageAdapterGetResponse get(
        DDMStorageAdapterGetRequest ddmStorageAdapterGetRequest)
    throws StorageException;
public DDMStorageAdapterSaveResponse save(
        DDMStorageAdapterSaveRequest ddmStorageAdapterSaveRequest)
    throws StorageException;

各メソッドは、静的な内部 Builder クラスの newBuilder メソッドを使用して構築された DDMStorageAdapter[Save/Get/Delete]Response オブジェクトを返す必要があります。

すべてのメソッドにDDMStorageAdapter[Save/Delete/Get]Requestが渡されます。 リクエストオブジェクトには、有用なコンテキスト情報を返すgetterメソッドが含まれています。

ファイルシステムストレージを実装する

この例では、必要なメソッドをすでに上書きしています。 機能用のプライベート ユーティリティ メソッドを作成し、オーバーライドされたメソッドからそれらを呼び出します。

サービスの依存関係を宣言する

このコードは、OSGiコンテナにデプロイされた2つのサービスに依存しています。 org.osgi.service.component.annotations.Referenceによって提供されるDeclarative Services @Referenceアノテーションを使用して、クラスの最後にこれらの宣言を追加します。

@Reference
private DDMContentLocalService _ddmContentLocalService;

@Reference
private DDMFormValuesSerializerTracker _ddmFormValuesSerializerTracker;

com.liferay.dynamic.data.mapping.service.DDMContentLocalServiceおよびcom.liferay.dynamic.data.mapping.io.DDMFormValuesSerializerTrackerをインポートします。

ロガーを作成する

クラスのロガーを作成し、_log変数に設定します。

private static final Log _log = LogFactoryUtil.getLog(
    R2F1DDMStorageAdapter.class);

これは、CRUD メソッドの 1 つが呼び出されるたびにログ メッセージを追加するために使用されます。

ファイル削除を実装する

  1. プライベート変数 _PATHNAME を設定することで、ファイルの保存先をコントロールすることができます。 ここでのパスは、Dockerコンテナ内のLiferayのインストール場所を指しています。

    private static final String _PATHNAME = "/opt/liferay/form-records";
    
  2. _deleteFileユーティリティメソッドを作成します(java.io.Fileクラスをインポート)。

    private void _deleteFile(long fileId) {
       File file = new File(_PATHNAME + "/" + fileId);
    
       file.delete();
    
       if (_log.isWarnEnabled()) {
       _log.warn("Deleted file with the ID " + fileId);
       }
    }
    
  3. 上書きされた delete メソッドを探します。 return ステートメントの直前に以下を追加します。

     long fileId = ddmStorageAdapterDeleteRequest.getPrimaryKey();
    
     _deleteFile(fileId);
    

これで、このコードは、データベース内のコピーを削除する前に、まずファイルシステムからファイルを削除します。

ファイル取得を実装する

get メソッドについても同じ手順に従います。つまり、プライベート ユーティリティ メソッドを作成して、それを呼び出します。

  1. _getFileユーティリティメソッドを追加します。

    	private void _getFile(long fileId) throws IOException {
    		try {
    			if (_log.isWarnEnabled()) {
    				_log.warn(
    					"Reading the file with the ID " + fileId + ": " +
    						FileUtil.read(_PATHNAME + "/" + fileId));
    			}
    		}
    		catch (IOException e) {
    			throw new IOException(e);
    		}
    	}
    

    com.liferay.portal.kernel.util.FileUtilおよびjava.io.IOExceptionをインポートします。

  2. オーバーライドされた get メソッド ( try ブロック内) で、次のコードを return ステートメントの直前に挿入し、 storageId ( ddmStorageAdapterGetRequest.getPrimaryKey()によって取得) を fileId として設定し、取得したコンテンツを Liferay ログに出力する _getFile ユーティリティ メソッドを呼び出します。

    long fileId = ddmStorageAdapterGetRequest.getPrimaryKey();
    
    _getFile(fileId);
    

ファイル作成ロジックを実装する

保存リクエストには、新しいレコードが追加される場合と既存のレコードが更新される場合の2つのタイプがあります。 保存するたびに、 update メソッドは、現在の ddmFormValues コンテンツを使用して既存のファイルを上書きします。

  1. _saveFileユーティリティメソッドを作成します。

    private void _saveFile(long fileId, DDMFormValues formValues)
       throws IOException {
    
       try {
          String serializedDDMFormValues = _serialize(formValues);
    
          File abstractFile = new File(String.valueOf(fileId));
    
          FileUtil.write(
             _PATHNAME, abstractFile.getName(), serializedDDMFormValues);
    
          if (_log.isWarnEnabled()) {
             _log.warn("Saved a file with the ID" + fileId);
          }
       }
       catch (IOException e) {
          throw new IOException(e);
       }
    }
    

    com.liferay.dynamic.data.mapping.storage.DDMFormValuesおよびjava.io.Fileをインポートします。

  2. _serializeユーティリティメソッドを作成し、DDMFormValuesオブジェクトをJSONに変換します。

    	private String _serialize(DDMFormValues ddmFormValues) {
    		DDMFormValuesSerializer ddmFormValuesSerializer =
    			_ddmFormValuesSerializerTracker.getDDMFormValuesSerializer("json");
    
    		DDMFormValuesSerializerSerializeRequest.Builder builder =
    			DDMFormValuesSerializerSerializeRequest.Builder.newBuilder(
    				ddmFormValues);
    
    		DDMFormValuesSerializerSerializeResponse
    			ddmFormValuesSerializerSerializeResponse =
    				ddmFormValuesSerializer.serialize(builder.build());
    
    		return ddmFormValuesSerializerSerializeResponse.getContent();
    	}
    

    com.liferay.dynamic.data.mapping.io.DDMFormValuesSerializercom.liferay.dynamic.data.mapping.io.DDMFormValuesSerializerSerializeRequest、およびcom.liferay.dynamic.data.mapping.io.DDMFormValuesSerializerSerializeResponseをインポートします。

  3. このロジックと_saveFileへの呼び出しを、既存のreturnステートメントを置き換えてsaveメソッドに追加します。

    DDMStorageAdapterSaveResponse defaultStorageAdapterSaveResponse =
       _defaultStorageAdapter.save(ddmStorageAdapterSaveRequest);
    
    long fileId = defaultStorageAdapterSaveResponse.getPrimaryKey();
    
    _saveFile(fileId, ddmStorageAdapterSaveRequest.getDDMFormValues());
    
    return defaultStorageAdapterSaveResponse;
    

    最初に _defaultStorageAdapter.save 呼び出しが行われ、新しいフォーム エントリの主キーが作成されます。 このプライマリーキーは、fielIdを作成するためにResponseオブジェクトから取得されます。

ストレージアダプターをデプロイしてテストする

先ほどと同じdeployコマンドを使用してストレージアダプターをデプロイします。 モジュールルートから、以下を実行します。

./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)

以下のように動作を確認します。

  1. サイト メニューコンテンツフォームでフォーム アプリケーションに移動します。

  2. 追加 Add をクリックしてフォーム ビルダーを開きます。

  3. フォーム ビルダー ビューで、 オプション (Options) をクリックし、 設定 ウィンドウを開きます。

  4. リストを選択フィールド[ストレージの種類を選択する]から、[R2F1 Dynamic Data Mapping Storage Adapter]タイプを選択し、[完了]をクリックします。

  5. フォームに テキスト フィールド を追加し、フォームを公開して、数回送信します。

  6. フォームレコードがコンテナのファイルシステムに書き込まれたことを確認するには、ログを確認します。 メッセージは次のようになります。

    WARN  [http-nio-8080-exec-5][R2F1DDMStorageAdapter:82] Acme storage adapter's save method was invoked
    WARN  [http-nio-8080-exec-5][R2F1DDMStorageAdapter:134] Saved a file with the ID42088
    WARN  [http-nio-8080-exec-5][R2F1DDMStorageAdapter:61] Acme storage adapter's get method was invoked
    WARN  [http-nio-8080-exec-5][R2F1DDMStorageAdapter:112] Reading the file with the ID 42088: {"availableLanguageIds":["en_US"],"defaultLanguageId":"en_US","fieldValues":[{"instanceId":"EJ5UglA1","name":"Field51665758","value":{"en_US":"Stretched limousine"}}]}
    

さいごに

DDMStorageAdapterを実装することで、フォームレコードを任意のストレージ形式で保存することができます。