カスタムコンポーネント

このチュートリアルでは、ダイアログで作成されたコンテンツを表示するカスタムAEM署名コンポーネントのエンドツーエンドの作成について説明し、Sling モデルの開発で、コンポーネントの HTL に入力するビジネスロジックをカプセル化します。

前提条件

設定に必要なツールと手順を確認します。 ローカル開発環境.

スタータープロジェクト

メモ

前の章を正常に完了した場合は、プロジェクトを再利用し、スタータープロジェクトをチェックアウトする手順をスキップできます。

チュートリアルの構築元となるベースラインコードを確認します。

  1. 以下を確認します。 tutorial/custom-component-start ~から分岐する GitHub

    $ cd aem-guides-wknd
    $ git checkout tutorial/custom-component-start
    
  2. Maven のスキルを使用して、ローカルのAEMインスタンスにコードベースをデプロイします。

    $ mvn clean install -PautoInstallSinglePackage
    
    メモ

    AEM 6.5 または 6.4 を使用している場合、 classic 任意の Maven コマンドに対するプロファイル。

    $ mvn clean install -PautoInstallSinglePackage -Pclassic
    

完成したコードは、 GitHub または、ブランチに切り替えて、コードをローカルでチェックアウトします。 tutorial/custom-component-solution.

目的

  1. カスタムAEMコンポーネントの構築方法を説明します
  2. Sling モデルを使用してビジネスロジックをカプセル化する方法を説明します
  3. HTL スクリプト内から Sling モデルを使用する方法を説明します。

作成する内容

WKND チュートリアルのこの部分では、署名コンポーネントが作成され、記事の投稿者に関する作成済み情報を表示するのに使用されます。

署名コンポーネントの例

署名コンポーネント

署名コンポーネントの実装には、署名コンテンツを収集するダイアログと、署名のを取得するカスタム Sling Model が含まれています。

  • 名前
  • 画像
  • 職業

署名コンポーネントの作成

最初に、署名コンポーネントノード構造を作成し、ダイアログを定義します。 これは、AEM のコンポーネントを表し、JCR 内のその場所によってコンポーネントのリソースタイプを暗黙的に定義します。

ダイアログは、コンテンツ作成者が提供できるインターフェイスを表示します。この実装の場合、AEM WCM コアコンポーネントの 画像 コンポーネントは、署名画像のオーサリングとレンダリングを処理するために利用されるので、コンポーネントの sling:resourceSuperType.

コンポーネント定義を作成

  1. ui.apps モジュール、に移動します。 /apps/wknd/components をクリックし、 byline.

  2. byline フォルダを追加する新しいファイルの名前: .content.xml

    ノードを作成するためのダイアログ

  3. 次の項目に .content.xml ファイルには以下の情報が含まれます。

    <?xml version="1.0" encoding="UTF-8"?>
        <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
        jcr:primaryType="cq:Component"
        jcr:title="Byline"
        jcr:description="Displays a contributor's byline."
        componentGroup="WKND Sites Project - Content"
        sling:resourceSuperType="core/wcm/components/image/v2/image"/>
    

    上記の XML ファイルは、タイトル、説明、グループなど、コンポーネントの定義を提供します。 この sling:resourceSuperType ポイント core/wcm/components/image/v2/image( これは コア画像コンポーネント.

HTL スクリプトの作成

  1. byline フォルダー、新しいファイルを追加 byline.html:コンポーネントのHTML表示を担当します。 ファイルにフォルダーと同じ名前を付けることは重要です。これは、Sling がこのリソースタイプをレンダリングする際に使用するデフォルトのスクリプトになるからです。

  2. 以下のコードを byline.html に追加します。

    <!--/* byline.html */-->
    <div data-sly-use.placeholderTemplate="core/wcm/components/commons/v1/templates.html">
    </div>
    <sly data-sly-call="${placeholderTemplate.placeholder @ isEmpty=true}"></sly>
    

byline.html後で再び行うSling モデルが作成されたら、 HTL ファイルの現在の状態を使用すると、コンポーネントをページにドラッグ&ドロップしたときに、AEM Sites のページエディターで空の状態で表示できます。

ダイアログ定義の作成

次に、以下のフィールドを含む、署名コンポーネント用のダイアログを定義します。

  • 名前:寄稿者の名前のテキストフィールド。
  • 画像:寄稿者の自己紹介写真への参照。
  • 職業:寄稿者に起因する職業のリスト。職業は、アルファベットの昇順(a~z)で並べ替えられる必要があります。
  1. byline フォルダー、新しいフォルダーを作成します。 _cq_dialog.

  2. の下 byline/_cq_dialog という名前の新しいファイルを追加します。 .content.xml. これは、ダイアログの XML 定義です。 次の XML を追加します。

    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
            jcr:primaryType="nt:unstructured"
            jcr:title="Byline"
            sling:resourceType="cq/gui/components/authoring/dialog">
        <content
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/container">
            <items jcr:primaryType="nt:unstructured">
                <tabs
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/tabs"
                        maximized="{Boolean}false">
                    <items jcr:primaryType="nt:unstructured">
                        <asset
                                jcr:primaryType="nt:unstructured"
                                sling:hideResource="{Boolean}false"/>
                        <metadata
                                jcr:primaryType="nt:unstructured"
                                sling:hideResource="{Boolean}true"/>
                        <properties
                                jcr:primaryType="nt:unstructured"
                                jcr:title="Properties"
                                sling:resourceType="granite/ui/components/coral/foundation/container"
                                margin="{Boolean}true">
                            <items jcr:primaryType="nt:unstructured">
                                <columns
                                        jcr:primaryType="nt:unstructured"
                                        sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
                                        margin="{Boolean}true">
                                    <items jcr:primaryType="nt:unstructured">
                                        <column
                                                jcr:primaryType="nt:unstructured"
                                                sling:resourceType="granite/ui/components/coral/foundation/container">
                                            <items jcr:primaryType="nt:unstructured">
                                                <name
                                                        jcr:primaryType="nt:unstructured"
                                                        sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                        emptyText="Enter the contributor's name to display."
                                                        fieldDescription="The contributor's name to display."
                                                        fieldLabel="Name"
                                                        name="./name"
                                                        required="{Boolean}true"/>
                                                <occupations
                                                        jcr:primaryType="nt:unstructured"
                                                        sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                                                        fieldDescription="A list of the contributor's occupations."
                                                        fieldLabel="Occupations"
                                                        required="{Boolean}false">
                                                    <field
                                                            jcr:primaryType="nt:unstructured"
                                                            sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                            emptyText="Enter an occupation"
                                                            name="./occupations"/>
                                                </occupations>
                                            </items>
                                        </column>
                                    </items>
                                </columns>
                            </items>
                        </properties>
                    </items>
                </tabs>
            </items>
        </content>
    </jcr:root>
    

    これらのダイアログノード定義では、 Sling Resource Merger どのダイアログタブが sling:resourceSuperType コンポーネント(この場合は) コアコンポーネントの画像コンポーネント.

    署名用の完了済みダイアログ

ポリシーダイアログの作成

ダイアログ作成と同じ方法でポリシーダイアログ(以前のデザインダイアログ)を作成して、コアコンポーネントの画像コンポーネントから継承されたポリシー設定の不要なフィールドを非表示にします。

  1. byline フォルダー、新しいフォルダーを作成します。 _cq_design_dialog.

  2. の下 byline/_cq_design_dialog という名前の新しいファイルを作成します。 .content.xml. ファイルを次のように更新します。を次の XML に置き換えます。 を開くのが最も簡単です。 .content.xml をクリックし、その中に以下の XML をコピー&ペーストします。

    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
        jcr:primaryType="nt:unstructured"
        jcr:title="Byline"
        sling:resourceType="cq/gui/components/authoring/dialog">
        <content
                jcr:primaryType="nt:unstructured">
            <items jcr:primaryType="nt:unstructured">
                <tabs
                        jcr:primaryType="nt:unstructured">
                    <items jcr:primaryType="nt:unstructured">
                        <properties
                                jcr:primaryType="nt:unstructured">
                            <items jcr:primaryType="nt:unstructured">
                                <content
                                        jcr:primaryType="nt:unstructured">
                                    <items jcr:primaryType="nt:unstructured">
                                        <decorative
                                                jcr:primaryType="nt:unstructured"
                                                sling:hideResource="{Boolean}true"/>
                                        <altValueFromDAM
                                                jcr:primaryType="nt:unstructured"
                                                sling:hideResource="{Boolean}true"/>
                                        <titleValueFromDAM
                                                jcr:primaryType="nt:unstructured"
                                                sling:hideResource="{Boolean}true"/>
                                        <displayCaptionPopup
                                                jcr:primaryType="nt:unstructured"
                                                sling:hideResource="{Boolean}true"/>
                                        <disableUuidTracking
                                                jcr:primaryType="nt:unstructured"
                                                sling:hideResource="{Boolean}true"/>
                                    </items>
                                </content>
                            </items>
                        </properties>
                        <features
                                jcr:primaryType="nt:unstructured">
                            <items jcr:primaryType="nt:unstructured">
                                <content
                                        jcr:primaryType="nt:unstructured">
                                    <items jcr:primaryType="nt:unstructured">
                                        <accordion
                                                jcr:primaryType="nt:unstructured">
                                            <items jcr:primaryType="nt:unstructured">
                                                <orientation
                                                        jcr:primaryType="nt:unstructured"
                                                        sling:hideResource="{Boolean}true"/>
                                                <crop
                                                        jcr:primaryType="nt:unstructured"
                                                        sling:hideResource="{Boolean}true"/>
                                            </items>
                                        </accordion>
                                    </items>
                                </content>
                            </items>
                        </features>
                    </items>
                </tabs>
            </items>
        </content>
    </jcr:root>
    

    前の基準 ポリシーダイアログ XML は コアコンポーネントの画像コンポーネント.

    ダイアログ設定のと同様に、 Sling Resource Merger を使用して、無関係なフィールドを非表示にします。これ以外の場合は、 sling:resourceSuperTypeを使用して、 sling:hideResource="{Boolean}true" プロパティ。

コードのデプロイ

  1. 変更を同期 ui.apps IDE または Maven スキルを使用して、

    AEMサーバーの署名コンポーネントに書き出し

ページへのコンポーネントの追加

AEMコンポーネントの開発に重点を置いたシンプルな作業を維持するために、署名コンポーネントを現在の状態で記事ページに追加し、 cq:Component ノード定義がデプロイされ、正しく設定されている場合、AEMは新しいコンポーネント定義を認識し、コンポーネントのダイアログがオーサリングに機能します。

AEM Assetsへの画像の追加

まず、サンプルのヘッドショットをAEM Assetsにアップロードして、署名コンポーネントに画像を設定する際に使用します。

  1. AEM Assetsの LA Skateparks フォルダーに移動します。 http://localhost:4502/assets.html/content/dam/wknd/en/magazine/la-skateparks.

  2. のヘッドショットをアップロード stacey-roswells.jpg をフォルダーに追加します。

    ヘッドショットがAEM Assetsにアップロードされました

コンポーネントの作成

次に、署名コンポーネントをAEMのページに追加します。 署名コンポーネントを WKND Sites プロジェクト — コンテンツ コンポーネントグループ(経由) ui.apps/src/main/content/jcr_root/apps/wknd/components/byline/.content.xml 定義を使用する場合、任意のユーザーが自動的に使用できます コンテナ その ポリシー 許可 WKND Sites プロジェクト — コンテンツ コンポーネントグループに割り当てられます。このグループには、記事ページのレイアウトコンテナが含まれます。

  1. LA Skatepark の記事 ( ) に移動します。 http://localhost:4502/editor.html/content/wknd/us/en/magazine/guide-la-skateparks.html

  2. 左側のサイドバーから、 署名コンポーネント 次に bottom をクリックします。

    署名コンポーネントをページに追加

  3. 左側のサイドバーが開いて​表示されたことと、アセットファインダー​が選択されていることを確認します。

  4. を選択します。 署名コンポーネントのプレースホルダー​をクリックし、次にアクションバーを表示して、 レンチ アイコンをクリックしてダイアログを開きます。

  5. ダイアログが開き、最初のタブ(アセット)がアクティブな状態で、左側のサイドバーを開き、アセットファインダーから画像を画像ドロップゾーンにドラッグします。 WKND ui.content パッケージに含まれる Stacey Roswells のバイオ画像を検索するには、「stacey」を検索します。

    ダイアログに画像を追加

  6. 画像を追加したら、「プロパティ」タブをクリックして「名前」および「職業」に入力します。

    職業を入力する場合は、次の場所に入力します。 逆アルファベット Sling Model で実装する英文化化ビジネスロジックが見やすいように、順序を指定します。

    次をタップします。 完了 ボタンをクリックして変更を保存します。

    署名コンポーネントのプロパティの設定

    AEM作成者は、ダイアログを使用してコンポーネントを設定および作成します。 署名コンポーネントの開発のこの時点では、データの収集用のダイアログが含まれますが、作成したコンテンツをレンダリングするロジックはまだ追加されていません。 したがって、プレースホルダーのみが表示されます。

  7. ダイアログを保存したら、に移動します。 CRXDE Lite およびは、コンポーネントのコンテンツがAEMページの署名コンポーネントコンテンツノードに格納される方法を確認します。

    LA Skate Parks ページの下に、署名コンポーネントのコンテンツノードを見つけます。 /content/wknd/us/en/magazine/guide-la-skateparks/jcr:content/root/container/container/byline.

    プロパティ名に注意してください name, occupations、および fileReference署名ノード.

    また、 sling:resourceTypewknd/components/content/byline これは、このコンテンツノードを署名コンポーネントの実装にバインドするものです。

    CRXDE の署名プロパティ

署名 Sling モデルを作成

次に、データモデルとして機能し、署名コンポーネントのビジネスロジックを格納する Sling Model を作成します。

Sling モデルは、JCR から Java 変数へのデータのマッピングを容易にし、AEMのコンテキストで開発する際に他の多くの点を提供する注釈駆動型の Java「POJO」(Plain Old Java Objects) です。

Maven の依存関係の確認

署名 Sling モデルは、AEMが提供する複数の Java API に依存します。 これらの API は、 dependencies 次に示す core モジュールの POM ファイル。 このチュートリアルに使用するプロジェクトは、AEM as a Cloud Service用に構築されています。 ただし、AEM 6.5/6.4 との下位互換性がある点は一意です。そのため、Cloud ServiceとAEM 6.x の両方の依存関係が含まれます。

  1. を開きます。 pom.xml の下のファイル <src>/aem-guides-wknd/core/pom.xml.

  2. 依存関係を検索 aem-sdk-api - AEMas a Cloud Serviceのみ

    <dependency>
        <groupId>com.adobe.aem</groupId>
        <artifactId>aem-sdk-api</artifactId>
    </dependency>
    

    この aem-sdk-api には、AEMで公開されるすべてのパブリック Java API が含まれています。 この aem-sdk-api は、このプロジェクトを構築する際にデフォルトで使用されます。 バージョンは、次の場所にあるプロジェクトのルートにある親リアクター POM に保持されます。 aem-guides-wknd/pom.xml.

  3. の依存関係を検索 uber-jar - AEM 6.5/6.4 のみ

    ...
        <dependency>
            <groupId>com.adobe.aem</groupId>
            <artifactId>uber-jar</artifactId>
            <classifier>apis</classifier>
        </dependency>
    ...
    

    この uber-jar が含まれるのは、 classic プロファイルが呼び出されました。 mvn clean install -PautoInstallSinglePackage -Pclassic. これもこのプロジェクトに固有のものです。 AEMプロジェクトアーキタイプから生成される、実際のプロジェクトでは、 uber-jar 指定したAEMのバージョンが 6.5 または 6.4 の場合、がデフォルトになります。

    この uber-jar には、AEM 6.x で公開されているすべてのパブリック Java API が含まれています。バージョンは、プロジェクトのルートにある親リアクター POM に保持されます aem-guides-wknd/pom.xml.

  4. 依存関係を検索 core.wcm.components.core:

     <!-- Core Component Dependency -->
        <dependency>
            <groupId>com.adobe.cq</groupId>
            <artifactId>core.wcm.components.core</artifactId>
        </dependency>
    

    これは、AEMコアコンポーネントによって公開されるすべてのパブリック Java API です。 AEMコアコンポーネントは、AEMの外部で管理されるプロジェクトなので、別のリリースサイクルがあります。 このため、依存関係は別々に含める必要があり、 not 次に含まれる uber-jar または aem-sdk-api.

    uber-jar と同様に、この依存関係のバージョンは、次の場所にある親リアクター pom ファイルに保持されます。 aem-guides-wknd/pom.xml.

    このチュートリアルの後半では、コアコンポーネントの画像クラスを使用して、署名コンポーネントに画像を表示します。 Sling モデルを構築してコンパイルするには、コアコンポーネントの依存関係が必要です。

Byline インターフェイス

署名用のパブリック Java インターフェイスを作成します。 Byline.java は、 byline.html HTL スクリプト。

  1. aem-guides-wknd.core 下のモジュール core/src/main/java/com/adobe/aem/guides/wknd/core/models という名前の新しいファイルを作成します。 Byline.java

    署名インターフェイスを作成

  2. 以下のメソッドで Byline.java を更新します。

    package com.adobe.aem.guides.wknd.core.models;
    
    import java.util.List;
    
    /**
    * Represents the Byline AEM Component for the WKND Site project.
    **/
    public interface Byline {
        /***
        * @return a string to display as the name.
        */
        String getName();
    
        /***
        * Occupations are to be sorted alphabetically in a descending order.
        *
        * @return a list of occupations.
        */
        List<String> getOccupations();
    
        /***
        * @return a boolean if the component has enough content to display.
        */
        boolean isEmpty();
    }
    

    最初の 2 つのメソッドは、 名前 および 職業 署名コンポーネント用の

    この isEmpty() メソッドは、コンポーネントにレンダリングするコンテンツがあるかどうか、または設定を待っているかどうかを判断するために使用されます。

    画像に対するメソッドがないことに注意してください。 その理由を後で見てみましょう.

  3. パブリック Java クラス(この場合は Sling モデル)を含む Java パッケージは、パッケージの package-info.java ファイル。

    WKND ソースの Java パッケージ以降 com.adobe.aem.guides.wknd.core.models を宣言すると、のバージョンが 1.0.0を追加し、新しい公開インターフェイスおよびメソッドを追加する場合は、バージョンを 1.1.0. 次の場所にあるファイルを開きます。 core/src/main/java/com/adobe/aem/guides/wknd/core/models/package-info.java および更新 @Version("1.0.0") から @Version("1.1.0").

    &quot;&#39;
    @Version(&quot;2.1.0&quot;)
    package com.adobe.aem.guides.wknd.core.models;
    
    import org.osgi.annotation.versioning.Version;
    &quot;&#39;
    

    このパッケージ内のファイルに変更が加えられると、 パッケージのバージョンは、意味的に調整する必要があります. そうでない場合、Maven プロジェクトの bnd-baseline-maven-plugin は無効なパッケージバージョンを検出し、ビルドを中断します。 幸運なことに、Maven プラグインが失敗すると、無効な Java パッケージのバージョンと、そのバージョンが表示されるはずです。 更新されたばかりの @Version("...") Java パッケージの宣言 package-info.java を、プラグインで推奨される修正用のバージョンに追加する。

署名実装

BylineImpl.java は、 Byline.java 以前に定義されたインターフェイス。 BylineImpl.java の完全なコードは、この節の最後に記載しています。

  1. という名前の新しいフォルダーを作成します。 implcore/src/main/java/com/adobe/aem/guides/core/models.

  2. impl フォルダー新規ファイルを作成 BylineImpl.java.

    署名 Impl ファイル

  3. 次を開きます: BylineImpl.java. これによって Byline インターフェイス。 IDE のオートコンプリート機能を使用するか、手動でファイルを更新して、 Byline インターフェイス:

    package com.adobe.aem.guides.wknd.core.models.impl;
    import java.util.List;
    import com.adobe.aem.guides.wknd.core.models.Byline;
    
    public class BylineImpl implements Byline {
    
        @Override
        public String getName() {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public List<String> getOccupations() {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public boolean isEmpty() {
            // TODO Auto-generated method stub
            return false;
        }
    }
    
  4. 以下のクラスレベルの注釈で BylineImpl.java を更新して、Sling Model 注釈を追加します。この @Model(..)注釈は、クラスを Sling モデルに変換するものです。

    import org.apache.sling.api.SlingHttpServletRequest;
    import org.apache.sling.models.annotations.Model;
    import org.apache.sling.models.annotations.DefaultInjectionStrategy;
    ...
    @Model(
            adaptables = {SlingHttpServletRequest.class},
            adapters = {Byline.class},
            resourceType = {BylineImpl.RESOURCE_TYPE},
            defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
    )
    public class BylineImpl implements Byline {
        protected static final String RESOURCE_TYPE = "wknd/components/byline";
        ...
    }
    

    この注釈とそのパラメーターを確認してみましょう:

    • この @Model annotation は、BylineImpl をAEMにデプロイする際に Sling Model として登録します。
    • この adaptables パラメーターは、このモデルがリクエストで適応できることを指定します。
    • この adapters パラメーターを使用すると、実装クラスを Byline インターフェイスに登録できます。 これにより、HTL スクリプトは(impl ではなく)インターフェイスを介して Sling Model を呼び出すことができます。 adapters について詳しくは、こちらを参照してください。
    • この resourceType は署名コンポーネントのリソースタイプ(以前に作成した)を指し、複数の実装がある場合に正しいモデルの解決に役立ちます。 モデルクラスのリソースタイプとの関連付けについて詳しくは、こちらを参照してください。

Sling Model メソッドの実装

getName()

最初に取り組む方法は getName() これは、プロパティの下の署名の JCR コンテンツノードに保存された値を返します。 name.

この場合、 @ValueMapValue Sling Model 注釈は、リクエストのリソースの ValueMap を使用して Java フィールドに値を挿入するために使用されます。

import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;

public class BylineImpl implements Byline {
    ...
    @ValueMapValue
    private String name;

    ...
    @Override
    public String getName() {
        return name;
    }
    ...
}

JCR プロパティは Java フィールドと同じ名前(両方とも「name」)を持つので、 @ValueMapValue はこの関連付けを自動的に解決し、プロパティの値を Java フィールドに挿入します。

getOccupations()

次に実装する方法は次のとおりです。 getOccupations(). このメソッドは、JCR プロパティに保存されているすべての職業を収集します occupations 並べ替えられた(アルファベット順の)コレクションを返します。

に示したのと同じ方法の使用 getName() プロパティ値は、Sling モデルのフィールドに挿入できます。

挿入された Java フィールドを介して JCR プロパティ値を Sling モデルで使用できるようになったら、 occupationsを指定しない場合、並べ替えビジネスロジックは getOccupations() メソッド。

import java.util.ArrayList;
import java.util.Collections;
  ...

public class BylineImpl implements Byline {
    ...
    @ValueMapValue
    private List<String> occupations;
    ...
    @Override
    public List<String> getOccupations() {
        if (occupations != null) {
            Collections.sort(occupations);
            return new ArrayList<String>(occupations);
        } else {
            return Collections.emptyList();
        }
    }
    ...
}
  ...

isEmpty()

最後のパブリックメソッドは、 isEmpty() これにより、コンポーネントがレンダリングに十分な作成を行ったと見なすタイミングが決まります。

このコンポーネントには、名前、画像および職業の 3 つのフィールドをすべて入力する必要があるというビジネス要件があります コンポーネントはレンダリングできます。

import org.apache.commons.lang3.StringUtils;
  ...
public class BylineImpl implements Byline {
    ...
    @Override
    public boolean isEmpty() {
        if (StringUtils.isBlank(name)) {
            // Name is missing, but required
            return true;
        } else if (occupations == null || occupations.isEmpty()) {
            // At least one occupation is required
            return true;
        } else if (/* image is not null, logic to be determined */) {
            // A valid image is required
            return true;
        } else {
            // Everything is populated, so this component is not considered empty
            return false;
        }
    }
    ...
}

「画像の問題」への対処

名前と職業の条件を確認することは簡単です ( そして Apache Commons Lang3 は常に便利です StringUtils (クラス)が、 画像の存在 は、コアコンポーネントの画像コンポーネントを画像の表示に使用するので、検証できます。

これに対処するには、2 つの方法があります。

をチェックします。 fileReference JCR プロパティがアセットに解決されます。 または このリソースをコアコンポーネントの画像 Sling モデルに変換し、 getSrc() メソッドが空ではありません。

次を選択します。 アプローチ。 第 1 のアプローチで十分である可能性が高いですが、このチュートリアルでは、Sling モデルの他の機能を調べるために後者を使用します。

  1. 画像を取得するプライベートメソッドを作成します。 このメソッドをプライベートにしておくのは、HTL 自体の画像オブジェクトを公開する必要がなく、isEmpty(). () を実行するためにのみ使用するからです。

    次のプライベートメソッドを getImage():

    import com.adobe.cq.wcm.core.components.models.Image;
    ...
    private Image getImage() {
        Image image = null;
        // Figure out how to populate the image variable!
        return image;
    }
    

    上記のように、 Image Sling Model:

    1 つ目は、 @Self 注釈 ( 現在のリクエストをコアコンポーネントの Image.class

    2 つ目は、 Apache Sling ModelFactory OSGi サービスは非常に便利なサービスで、Java コードで他のタイプの Sling モデルを作成するのに役立ちます。

    第 2 のアプローチを選択します。

    メモ

    実際の実装では、次を使用して「1」にアプローチします。 @Self よりシンプルでエレガントなソリューションなので、をお勧めします。 このチュートリアルでは、2 つ目の方法を使用します。非常に役立つ Sling モデルのより多くのファセットを調査する必要があるので、2 つ目の方法を使用します。より複雑なコンポーネントです。

    Sling モデルは OSGi サービスではなく Java POJO なので、通常の OSGi 挿入注釈です @Reference できません を使用する代わりに、Sling Model は特別な @OSGiService 類似の機能を提供する注釈。

  2. 更新 BylineImpl.java を含めるには OSGiService 挿入する注釈 ModelFactory:

    import org.apache.sling.models.factory.ModelFactory;
    import org.apache.sling.models.annotations.injectorspecific.OSGiService;
    ...
    public class BylineImpl implements Byline {
        ...
        @OSGiService
        private ModelFactory modelFactory;
    }
    

    を使用 ModelFactory 使用可能なコアコンポーネントの画像 Sling モデルは、次のものを使用して作成できます。

    modelFactory.getModelFromWrappedRequest(SlingHttpServletRequest request, Resource resource, java.lang.Class<T> targetClass)
    

    ただし、このメソッドにはリクエストとリソースの両方が必要で、Sling モデルではまだ使用できません。 これらを取得するには、より多くの Sling Model 注釈が使用されます。

    現在のリクエストを取得するには、 @Self 注釈を使用して、 adaptable ( @Model(..) as SlingHttpServletRequest.classを Java クラスフィールドに追加します。

  3. @Self 注釈を使用して SlingHttpServletRequest リクエスト:

    import org.apache.sling.models.annotations.injectorspecific.Self;
    ...
    @Self
    private SlingHttpServletRequest request;
    

    注意:を使用 @Self Image image コアコンポーネントの画像 Sling モデルを挿入することは、上記のオプションでした。 @Self annotation は、適応可能なオブジェクト(この例では SlingHttpServletRequest)の挿入を試み、注釈フィールドタイプに合わせます。 コアコンポーネントの画像 Sling Model は SlingHttpServletRequest オブジェクトから適応可能なので、これなら機能したはずです。また、説明的な 2 番目の方法よりも少ないコードで済みます。

    これで、ModelFactory API で画像モデルをインスタンス化するために必要な変数を挿入できました。次に、Sling Model の @PostConstruct 注釈を使用して、Sling Model をインスタンス化した後、このオブジェクトを取得します。

    @PostConstruct は非常に役に立ち、コンストラクターと同様の能力で動作しますが、クラスがインスタンス化され、注釈が付けられたすべての Java フィールドが挿入された後に呼び出されます。 他の Sling モデルの注釈は Java クラスフィールド(変数)に注釈を付けます。 @PostConstruct は、通常、 init() (ただし、任意の名前を付けることができます)。

  4. 追加 @PostConstruct メソッド:

    import javax.annotation.PostConstruct;
    ...
    public class BylineImpl implements Byline {
        ...
        private Image image;
    
        @PostConstruct
        private void init() {
            image = modelFactory.getModelFromWrappedRequest(request,
                                                            request.getResource(),
                                                            Image.class);
        }
        ...
    }
    

    Sling Model は OSGi サービス​ではない​ので、クラスの状態を安全に管理できます。頻繁 @PostConstruct プレーンコンストラクターと同様に、後で使用するために Sling Model クラスの状態を派生および設定します。

    なお、 @PostConstruct メソッドで例外がスローされ、Sling モデルはインスタンス化されません(null になります)。

  5. getImage() を更新して、画像オブジェクトを返すだけで済むようになりました。

    /**
        * @return the Image Sling Model of this resource, or null if the resource cannot create a valid Image Sling Model.
    */
    private Image getImage() {
        return image;
    }
    
  6. 次に戻ろう isEmpty() 実装を完了します。

    @Override
    public boolean isEmpty() {
       final Image componentImage = getImage();
    
        if (StringUtils.isBlank(name)) {
            // Name is missing, but required
            return true;
        } else if (occupations == null || occupations.isEmpty()) {
            // At least one occupation is required
            return true;
        } else if (componentImage == null || StringUtils.isBlank(componentImage.getSrc())) {
            // A valid image is required
            return true;
        } else {
            // Everything is populated, so this component is not considered empty
            return false;
        }
    }
    

    複数の getImage() は初期化されたを返すので、問題ありません image クラス変数で、を呼び出さない modelFactory.getModelFromWrappedRequest(...) それは過度に費用がかかるわけではなく、不必要に呼び出すのを避ける価値がある。

  7. 最終 BylineImpl.java は次のようになります。

    package com.adobe.aem.guides.wknd.core.models.impl;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import javax.annotation.PostConstruct;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.sling.api.SlingHttpServletRequest;
    import org.apache.sling.models.annotations.DefaultInjectionStrategy;
    import org.apache.sling.models.annotations.Model;
    import org.apache.sling.models.annotations.injectorspecific.OSGiService;
    import org.apache.sling.models.annotations.injectorspecific.Self;
    import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
    import org.apache.sling.models.factory.ModelFactory;
    import com.adobe.aem.guides.wknd.core.models.Byline;
    import com.adobe.cq.wcm.core.components.models.Image;
    
    @Model(
            adaptables = {SlingHttpServletRequest.class},
            adapters = {Byline.class},
            resourceType = {BylineImpl.RESOURCE_TYPE},
            defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
    )
    public class BylineImpl implements Byline {
        protected static final String RESOURCE_TYPE = "wknd/components/byline";
    
        @Self
        private SlingHttpServletRequest request;
    
        @OSGiService
        private ModelFactory modelFactory;
    
        @ValueMapValue
        private String name;
    
        @ValueMapValue
        private List<String> occupations;
    
        private Image image;
    
        /**
        * @PostConstruct is immediately called after the class has been initialized
        * but BEFORE any of the other public methods.
        * It is a good method to initialize variables that will be used by methods in the rest of the model
        *
        */
        @PostConstruct
        private void init() {
            // set the image object
            image = modelFactory.getModelFromWrappedRequest(request, request.getResource(), Image.class);
        }
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public List<String> getOccupations() {
            if (occupations != null) {
                Collections.sort(occupations);
                return new ArrayList<String>(occupations);
            } else {
                return Collections.emptyList();
            }
        }
    
        @Override
        public boolean isEmpty() {
            final Image componentImage = getImage();
    
            if (StringUtils.isBlank(name)) {
                // Name is missing, but required
                return true;
            } else if (occupations == null || occupations.isEmpty()) {
                // At least one occupation is required
                return true;
            } else if (componentImage == null || StringUtils.isBlank(componentImage.getSrc())) {
                // A valid image is required
                return true;
            } else {
                // Everything is populated, so this component is not considered empty
                return false;
            }
        }
    
        /**
        * @return the Image Sling Model of this resource, or null if the resource cannot create a valid Image Sling Model.
        */
        private Image getImage() {
            return image;
        }
    }
    

署名 HTL

ui.apps モジュール、開く /apps/wknd/components/byline/byline.html 以前のAEMコンポーネントの設定で作成しました。

<div data-sly-use.placeholderTemplate="core/wcm/components/commons/v1/templates.html">
</div>
<sly data-sly-call="${placeholderTemplate.placeholder @ isEmpty=false}"></sly>

この HTL スクリプトでおこなうことを確認しましょう。

  • この placeholderTemplate は、コアコンポーネントのプレースホルダーを指しています。このプレースホルダーは、コンポーネントが完全に設定されていない場合に表示されます。 これは、AEM Sitesページエディターで、上で説明したように、コンポーネントタイトルを持つボックスとしてレンダリングされます ( cq:Component's jcr:title プロパティ。

  • この data-sly-call="${placeholderTemplate.placeholder @ isEmpty=false} は、 placeholderTemplate 上で定義され、ブール値で渡されます ( 現在、次のようにハードコードされています: false) をプレースホルダーテンプレートに追加します。 条件 isEmpty が true の場合、プレースホルダテンプレートはグレーのボックスをレンダリングし、そうでない場合は何もレンダリングされません。

署名 HTL を更新

  1. 以下のスケルタル HTML 構造で byline.html を更新します。

    <div data-sly-use.placeholderTemplate="core/wcm/components/commons/v1/templates.html"
        class="cmp-byline">
            <div class="cmp-byline__image">
                <!--/* Include the Core Components Image Component */-->
            </div>
            <h2 class="cmp-byline__name"><!--/* Include the name */--></h2>
            <p class="cmp-byline__occupations"><!--/* Include the occupations */--></p>
    </div>
    <sly data-sly-call="${placeholderTemplate.placeholder @ isEmpty=true}"></sly>
    

    CSS クラスは BEM 命名規則に従うことに注意してください。BEM 規則の使用は必須ではありませんが、コアコンポーネント CSS クラスで使用され、一般的にクリーンで読みやすい CSS ルールになるので、BEM をお勧めします。

HTL での Sling Model オブジェクトのインスタンス化

この ブロックステートメントを使用 は、Sling モデルオブジェクトを HTL スクリプトでインスタンス化し、HTL 変数に割り当てるために使用されます。

data-sly-use.byline="com.adobe.aem.guides.wknd.models.Byline" は、BylineImpl で実装された署名インターフェイス (com.adobe.aem.guides.wknd.models.Byline) を使用して、現在の SlingHttpServletRequest をそのインターフェイスに適応し、結果を HTL 変数名のバイライン ( data-sly-use.<variable-name>) をクリックします。

  1. 外部を更新 div を参照する 署名 Sling Model by its public interface:

    <div data-sly-use.byline="com.adobe.aem.guides.wknd.core.models.Byline"
        data-sly-use.placeholderTemplate="core/wcm/components/commons/v1/templates.html"
        class="cmp-byline">
        ...
    </div>
    

Sling Model メソッドへのアクセス

HTL は、 JSTL およびは、Java ゲッターメソッド名と同じ短縮形を使用します。

例えば、署名 Sling モデルのの呼び出し getName() 方法はに短縮できます byline.name同様に、 byline.isEmptyの場合は、 byline.empty. 完全なメソッド名の使用 byline.getName または byline.isEmptyでも動作します。 次の点に注意してください。 () は、HTL でメソッドを呼び出すためには使用されません(JSTL と同様)。

パラメーターが必要な Java メソッド できません を HTL で使用する。 これは、HTL のロジックをシンプルにするための設計によるものです。

  1. 署名名は、 getName() メソッドを使用します。 ${byline.name}.

    を更新します。 h2 タグ:

    <h2 class="cmp-byline__name">${byline.name}</h2>
    

HTL 式のオプションの使用

HTL 式のオプション HTL 内のコンテンツの修飾子として機能し、日付の書式設定から i18n 翻訳まで幅広く機能します。 また、式は、リストの結合や値の配列に使用でき、職業をコンマ区切り形式で表示するのに必要です。

式は @ 演算子を使用して、HTL 式に含めることができます。

  1. 職業のリストを「,」で結合するには、以下のコードを使用します。

    <p class="cmp-byline__occupations">${byline.occupations @ join=', '}</p>
    

プレースホルダーの条件付き表示

AEMコンポーネントのほとんどの HTL スクリプトでは、 プレースホルダーパラダイム 作成者に視覚的な手がかりを提供する コンポーネントが誤って作成され、AEM パブリッシュに表示されないことを示す. この判断を推進するには、コンポーネントの背後の Sling Model のメソッド(この場合 Byline.isEmpty()())を実装する必要があります。

isEmpty() 署名 Sling Model でが呼び出され、結果(またはその負の値)が ! 演算子 ) が hasContent:

  1. 外部を更新 div という名前の HTL 変数を保存するには、次のようにします。 hasContent:

     <div data-sly-use.byline="com.adobe.aem.guides.wknd.core.models.Byline"
          data-sly-use.placeholderTemplate="core/wcm/components/commons/v1/templates.html"
          data-sly-test.hasContent="${!byline.empty}"
          class="cmp-byline">
          ...
    </div>
    

    の使用に注意してください。 data-sly-test、HTL test ブロックは、HTL 変数を設定し、HTL 式の結果が真かどうかに基づいて、その変数が基にするHTML要素をレンダリング/レンダリングしないので、興味深いものです。 「真」の場合、HTML要素はレンダリングされ、そうでない場合、レンダリングされません。

    この HTL 変数 hasContent を再利用して、プレースホルダーを条件付きで表示/非表示にできるようになりました。

  2. 条件付き呼び出しを placeholderTemplate を次のように指定します。

    <sly data-sly-call="${placeholderTemplate.placeholder @ isEmpty=!hasContent}"></sly>
    

コアコンポーネントを使用した画像の表示

の HTL スクリプト byline.html がほぼ完了し、画像しか欠落していなくなりました。

コアコンポーネントの画像コンポーネント sling:resourceSuperType を使用して画像のオーサリングを提供しているので、コアコンポーネントの画像コンポーネントを使用して画像をレンダリングすることもできます。

この場合、現在の署名リソースを含める必要がありますが、リソースタイプ core/wcm/components/image/v2/image. これは、コンポーネントを再利用する際の強力なパターンです。 これに対して、HTL の data-sly-resource ブロックが使用されます。

  1. div クラスを持つ cmp-byline__image を次のように設定します。

    <div class="cmp-byline__image"
        data-sly-resource="${ '.' @ resourceType = 'core/wcm/components/image/v2/image' }"></div>
    

    この data-sly-resource(相対パスを使用して現在のリソースを含む) '.'現在のリソース(または署名コンテンツリソース)を、 core/wcm/components/image/v2/image.

    コアコンポーネントのリソースタイプは、スクリプト内で使用され、コンテンツに対して保持されないので、プロキシ経由ではなく直接使用されます。

  2. 完了 byline.html 以下:

    <!--/* byline.html */-->
    <div data-sly-use.byline="com.adobe.aem.guides.wknd.core.models.Byline"
        data-sly-use.placeholderTemplate="core/wcm/components/commons/v1/templates.html"
        data-sly-test.hasContent="${!byline.empty}"
        class="cmp-byline">
        <div class="cmp-byline__image"
            data-sly-resource="${ '.' @ resourceType = 'core/wcm/components/image/v2/image' }">
        </div>
        <h2 class="cmp-byline__name">${byline.name}</h2>
        <p class="cmp-byline__occupations">${byline.occupations @ join=', '}</p>
    </div>
    <sly data-sly-call="${placeholderTemplate.placeholder @ isEmpty=!hasContent}"></sly>
    
  3. コードベースをローカルの AEM インスタンスにデプロイします。変更が加えられたため core および ui.apps 両方のモジュールをデプロイする必要があります。

    $ cd aem-guides-wknd/ui.apps
    $ mvn clean install -PautoInstallPackage
    
    $ cd ../core
    $ mvn clean install -PautoInstallBundle
    

    AEM 6.5/6.4 にデプロイする場合は、 classic プロファイル:

    $ cd ../core
    $ mvn clean install -PautoInstallBundle -Pclassic
    
    注意

    また、Maven プロファイルを使用して、ルートからプロジェクト全体を構築することもできます autoInstallSinglePackage ただし、これにより、ページ上のコンテンツの変更が上書きされる場合があります。 これは、 ui.content/src/main/content/META-INF/vault/filter.xml は、既存のAEMコンテンツをきれいに上書きするように、チュートリアルのスターターコードを変更しました。 実際のシナリオでは、これは問題にはなりません。

スタイル設定されていない署名コンポーネントのレビュー

  1. アップデートをデプロイした後、 LA スケートパークスの究極ガイド ページ、またはこの章で既に署名コンポーネントを追加した場所。

  2. この 画像, 名前、および 職業 が表示され、スタイルが設定されていないが、Byline コンポーネントが動作している。

    スタイル設定されていない署名コンポーネント

Sling Model 登録の確認

AEM Web コンソールの Sling Models Status 表示には、AEM に登録されたすべての Sling Model が表示されます。署名 Sling Model は、このリストを確認することで、インストールされ、認識されていることを検証できます。

この BylineImpl がこのリストに表示されない場合は、Sling モデルの注釈に問題があるか、Sling モデルが登録済みの Sling モデルパッケージ (com.adobe.aem.guides.wknd.core.models) をコアプロジェクトに追加しました。

署名 Sling Model が登録されました

http://localhost:4502/system/console/status-slingmodels

署名のスタイル

署名コンポーネントは、署名コンポーネントのクリエイティブデザインに沿ってスタイルを設定する必要があります。これは、AEMが ui.frontend Maven サブプロジェクト。

デフォルトのスタイルを追加

署名コンポーネントのデフォルトスタイルを追加します。

  1. IDE とに戻ります。 ui.frontend ~の下に投影する /src/main/webpack/components:

  2. という名前の新しいファイルを作成します。 _byline.scss.

    署名プロジェクトエクスプローラー

  3. 署名実装 CSS(SCSS として書き込む)を _byline.scss:

    .cmp-byline {
        $imageSize: 60px;
    
        .cmp-byline__image {
            float: left;
    
        /* This class targets a Core Component Image CSS class */
        .cmp-image__image {
            width: $imageSize;
            height: $imageSize;
            border-radius: $imageSize / 2;
            object-fit: cover;
            }
        }
    
        .cmp-byline__name {
            font-size: $font-size-medium;
            font-family: $font-family-serif;
            padding-top: 0.5rem;
            margin-left: $imageSize + 25px;
            margin-bottom: .25rem;
            margin-top:0rem;
        }
    
        .cmp-byline__occupations {
            margin-left: $imageSize + 25px;
            color: $gray;
            font-size: $font-size-xsmall;
            text-transform: uppercase;
        }
    }
    
  4. ターミナルを開き、 ui.frontend モジュール。

  5. を開始します。 watch 次の npm コマンドを使用してプロセスを実行します。

    $ cd ui.frontend/
    $ npm run watch
    
  6. ブラウザーに戻り、 LA SkateParks 記事. コンポーネントの更新済みのスタイルが表示されます。

    署名コンポーネントの完成

    ヒント

    古い CSS が提供されないようにブラウザーのキャッシュをクリアし、署名コンポーネントでページを更新して完全なスタイルを取得する必要が生じる場合があります。

おめでとうございます。

Adobe Experience Managerを使用してカスタムコンポーネントを最初から作成しました。

次の手順

引き続き、署名 Java コードの JUnit テストを記述して、すべてが正しく開発され、実装されたビジネスロジックが正しく完了していることを確認し、AEMコンポーネントの開発について学びます。

で完成したコードを表示する GitHub または、Git ブラッチ上のローカルのにコードを確認してデプロイします。 tutorial/custom-component-solution.

  1. のクローン github.com/adobe/aem-guides-wknd リポジトリ。
  2. 以下を確認します。 tutorial/custom-component-solution 分岐

このページ