HTL Java Use-API

HTML範本語言(HTL)Java Use-API可讓HTL檔案透過data-sly-use存取自訂Java類別中的輔助方法。 這可讓所有複雜的商業邏輯封裝在Java程式碼中,而HTL程式碼則僅處理直接標籤製作。

Java Use-API物件可以是簡單的POJO,由特定實作透過POJO的預設建構函式執行個體化。

Use-API POJO也可以使用下列簽名來公開名為init的公用方法:

    /**
     * Initializes the Use bean.
     *
     * @param bindings All bindings available to the HTL scripts.
     **/
    public void init(javax.script.Bindings bindings);

bindings對應可包含物件,這些物件會提供目前執行的HTL指令碼,Use-API物件可用來處理該指令碼。

簡單範例

我們將從沒有use-class的HTL元件開始。 它包含一個檔案/apps/my-example/components/info.html

/apps/my-example/component/info/info.html

<div>
    <h1>${properties.title}</h1>
    <p>${properties.description}</p>
</div>

我們也會為此元件新增一些內容,以便在/content/my-example/處演算:

http://<host>:<port>/content/my-example.json

{
    "sling:resourceType": "my-example/component/info",
    "title": "My Example",
    "description": "This Is Some Example Content."
}

存取此內容時,會執行HTL檔案。 在HTL程式碼中,我們使用內容物件properties來存取目前資源的titledescription,並顯示它們。 輸出HTML將為:

view-source:http://<host>:<port>/content/my-example.html

<div>
    <h1>My Example</h1>
    <p>This Is Some Example Content.</p>
</div>

添加使用類

info​元件如其現狀,不需要use-class來執行其(非常簡單)函式。 不過,在某些情況下,您需要執行無法在HTL中完成的工作,因此您需要使用類別。 但請記住:

注意

僅當無法在HTL中單獨執行某項作業時,才應使用use-class。

例如,假設您希望info元件顯示資源的titledescription屬性,但全部以小寫表示。 由於HTL沒有用於小寫字串的方法,因此您需要use-class。 我們可以通過添加Java use-class並按如下方式更改info.html來完成此操作:

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info">
    <h1>${info.lowerCaseTitle}</h1>
    <p>${info.lowerCaseDescription}</p>
</div>

/apps/my-example/component/info/Info.java

package apps.my_example.components.info;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo {
    private String lowerCaseTitle;
    private String lowerCaseDescription;

    @Override
    public void activate() throws Exception {
        lowerCaseTitle = getProperties().get("title", "").toLowerCase();
        lowerCaseDescription = getProperties().get("description", "").toLowerCase();
    }

    public String getLowerCaseTitle() {
        return lowerCaseTitle;
    }

    public String getLowerCaseDescription() {
        return lowerCaseDescription;
    }
}

在以下幾節中,我們將逐一介紹程式碼的不同部分。

本地與捆綁Java類

Java use-class可以用兩種方式安裝:local​或​bundle。 此示例使用本地安裝。

在本機安裝中,Java來源檔案會放在HTL檔案旁,位於相同的儲存庫檔案夾中。 系統會根據需求自動編譯來源。 不需要個別編譯或封裝步驟。

在套件安裝中,Java類別必須使用標準AEM套件部署機制,編譯並部署在OSGi套件中(請參閱套件Java類別)。

注意

當use-class是相關元件專屬時,建議使用​本機Java use-class

當Java代碼實施從多個HTL元件訪問的服務時,建議使用​捆綁Java use-class

Java包是儲存庫路徑

使用本地安裝時,use-class的軟體包名稱必須與儲存庫資料夾位置的軟體包名稱匹配,路徑中的任何連字元都由軟體包名稱中的下划線替換。

在這種情況下,Info.java位於/apps/my-example/components/info ,因此軟體包是apps.my_example.components.info :

/apps/my-example/component/info/Info.java

package apps.my_example.components.info;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo {

   ...

}
注意

在AEM開發中,建議在儲存庫項目名稱中使用連字型大小。 但是,連字型大小在Java包名稱中是非法的。 因此,儲存庫路徑中的​所有連字元都必須轉換為軟體包名稱​中的下划線。

擴展WCMUsePojo

雖然有許多將Java類與HTL結合的方法(請參閱WCMUsePojo的替代方案),但最簡單的方式是擴充WCMUsePojo類別:

/apps/my-example/component/info/Info.java

package apps.my_example.components.info;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo

    ...
}

初始化類

WCMUsePojo擴展use-class時,通過覆蓋activate方法來執行初始化:

/apps/my-example/component/info/Info.java

...

public class Info extends WCMUsePojo {
    private String lowerCaseTitle;
    private String lowerCaseDescription;

    @Override
    public void activate() throws Exception {
        lowerCaseTitle = getProperties().get("title", "").toLowerCase();
        lowerCaseDescription = getProperties().get("description", "").toLowerCase();
    }

...

}

上下文

通常,activate方法會用於根據目前的上下文(例如,目前的請求和資源)預先計算並儲存(在成員變數中)HTL程式碼中所需的值。

WCMUsePojo類提供對HTL檔案中可用的同一組上下文對象的訪問(請參閱全局對象)。

在擴展WCMUsePojo的類中,可通過名稱訪問上下文對象,使用

<T> T get(String name, Class<T> type)

或者,常用的上下文物件可由適當的​便利性方法​直接存取:

PageManager getPageManager()
頁面 getCurrentPage()
頁面 getResourcePage()
ValueMap getPageProperties()
ValueMap getProperties()
設計人員 getDesigner()
設計 getCurrentDesign()
樣式 getCurrentStyle()
元件 getComponent()
ValueMap getInheritedProperties()
資源 getResource()
資源解析器 getResourceResolver()
SlingHttpServletRequest getRequest()
SlingHttpServletResponse getResponse()
SlingScriptHelper getSlingScriptHelper()

Getter方法

在use-class初始化後,就會執行HTL檔案。 在此階段中,HTL通常會拉入use-class的各個成員變數的狀態,並將它們轉譯為簡報。

若要從HTL檔案中存取這些值,您必鬚根據下列命名慣例,在use-class中定義自訂getter方法:

  • getXyz格式的方法將在HTL檔案中公開名為xyz的對象屬性。

在以下示例中,getTitlegetDescription方法使對象屬性titledescription在HTL檔案的上下文中變為可訪問:

/apps/my-example/component/info/Info.java

...

public class Info extends WCMUsePojo {

    ...

    public String getLowerCaseTitle() {
        return lowerCaseTitle;
    }

    public String getLowerCaseDescription() {
        return lowerCaseDescription;
    }
}

data-slyuse屬性

data-sly-use屬性用於初始化HTL程式碼中的use-class。 在我們的示例中, data-sly-use屬性聲明我們要使用類Info。 我們只能使用類的本地名稱,因為我們使用的是本地安裝(將Java源檔案放在與HTL檔案相同的資料夾中)。 如果我們使用套件安裝,我們必須指定完全限定的類別名稱。

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info">
    <h1>${info.lowerCaseTitle}</h1>
    <p>${info.lowerCaseDescription}</p>
</div>

本機識別碼

識別碼info(位於data-sly-use.info中的點後)用於HTL檔案中以識別類別。 此標識符的範圍在檔案中是全局的,在聲明後。 它不限於包含data-sly-use語句的元素。

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info">
    <h1>${info.lowerCaseTitle}</h1>
    <p>${info.lowerCaseDescription}</p>
</div>

獲取屬性

然後,標識符info用於訪問通過getter方法Info.getTitleInfo.getDescription公開的對象屬性titledescription

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info">
    <h1>${info.lowerCaseTitle}</h1>
    <p>${info.lowerCaseDescription}</p>
</div>

輸出

現在,當我們存取/content/my-example.html時,它會傳回下列HTML:

view-source:http://<host>:<port>/content/my-example.html

<div>
    <h1>my example</h1>
    <p>this is some example content.</p>
</div>

Beyond The Basics

在本節中,我們將介紹一些超越上述簡單範例的其他功能:

  • 將參數傳遞至use-class。
  • 搭售的Java使用類別。
  • WCMUsePojo的替代方案

傳遞參數

參數可在初始化時傳遞至use-class。 例如,我們可以做這樣的事:

/content/my-example/component/info/info.html

<div data-sly-use.info="${'Info' @ text='Some text'}">
    <h1>${info.lowerCaseTitle}</h1>
    <p>${info.lowerCaseDescription}</p>
    <p>${info.upperCaseText}</p>
</div>

我們在此傳遞名為text的參數。 use-class接著將我們擷取的字串加上上,並顯示結果與info.upperCaseText。 以下是已調整的使用類別:

/apps/my-example/component/info/Info.java

package apps.my_example.components.info;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo {

    ...

    private String reverseText;

    @Override
    public void activate() throws Exception {

        ...

        String text = get("text", String.class);
        reverseText = new StringBuffer(text).reverse().toString();

    }

    public String getReverseText() {
        return reverseText;
    }

    ...
}

此參數是透過WCMUsePojo方法<T> T get(String paramName, Class<T> type)存取

就我們而言,聲明是:

get("text", String.class)

然後,該字串會通過以下方法被反轉和公開:

getReverseText()

僅從data-sly-template傳遞參數

雖然上述範例在技術上是正確的,但是當相關值在HTL程式碼的執行內容中可用時,從HTL傳遞值來初始化使用類別實際上並不有意義(或者,實際上,如上所述,該值是靜態的)。

原因是use-class將永遠擁有與HTL程式碼相同執行內容的存取權。 這就引出了最佳實踐的匯入點:

注意

只有當use-class用於data-sly-template檔案時,才應將參數傳入use-class,而此檔案本身是從另一個HTL檔案呼叫,且需要傳入參數。

例如,讓我們在現有範例旁建立個別的data-sly-template檔案。 我們將調用新檔案extra.html。 它包含一個名為extradata-sly-template塊:

/apps/my-example/component/info/extra.html

<template data-sly-template.extra="${@ text}"
          data-sly-use.extraHelper="${'ExtraHelper' @ text=text}">
  <p>${extraHelper.reversedText}</p>
</template>

範本extra採用單一參數text。 然後,它以本地名稱extraHelper初始化Java use-class ExtraHelper,並將模板參數text的值作為use-class參數text傳遞給它。

範本的內文會取得屬性extraHelper.reversedText(在外罩下方,實際呼叫ExtraHelper.getReversedText()),並顯示該值。

我們也會調整現有的info.html,以使用此新範本:

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info"
     data-sly-use.extra="extra.html">

  <h1>${info.lowerCaseTitle}</h1>
  <p>${info.lowerCaseDescription}</p>

  <div data-sly-call="${extra.extra @ text=properties.description}"></div>

</div>

檔案info.html現在包含兩個data-sly-use語句,其中原始語句導入Info Java use-class,新語句導入模板檔案,其本地名稱為extra

請注意,我們可將範本區塊放在info.html檔案中,以避免第二個data-sly-use,但是個別範本檔案較常見,而且可重複使用。

Info類與以前一樣,通過其相應的HTL屬性info.lowerCaseTitleinfo.lowerCaseDescription調用其getter方法getLowerCaseTitle()getLowerCaseDescription()

然後,我們對模板extra執行data-sly-call,並將值properties.description作為參數text傳遞。

Java use-class Info.java已更改為處理新文本參數:

/apps/my-example/component/info/ExtraHelper.java

package apps.my_example.components.info;

import com.adobe.cq.sightly.WCMUsePojo;

public class ExtraHelper extends WCMUsePojo {
    private String reversedText;
    ...

    @Override
    public void activate() throws Exception {
        String text = get("text", String.class);
        reversedText = new StringBuilder(text).reverse().toString();

        ...
    }

    public String getReversedText() {
        return reversedText;
    }
}

使用get("text", String.class)檢索text參數,該值會反轉,並通過getter getReversedText()作為HTL對象reversedText使用。

捆綁的Java類

使用Bundle use-class,必須使用標準OSGi Bundle部署機制,在AEM中編譯、封裝和部署類別。 與本地安裝不同,use-class package declaration​應正常命名:

/apps/my-example/component/info/Info.java

package org.example.app.components;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo {
    ...
}

和, data-sly-use語句必須引用完全限定的類名,而不只是本地類名:

/apps/my-example/component/info/info.html

<div data-sly-use.info="org.example.app.components.info.Info">
  <h1>${info.title}</h1>
  <p>${info.description}</p>
</div>

WCMUsePojo的替代方案

建立Java use-class的最常見方法是擴展WCMUsePojo。 但是,還有許多其他選擇。 要瞭解這些變體,瞭解HTL data-sly-use陳述式在引擎蓋下的運作方式會有所幫助。

假設您有下列data-sly-use陳述式:

<div data-sly-use. localName="UseClass">

系統將按以下方式處理語句:

(1)

  • 如果與HTL檔案位於同一目錄中存在本地檔案UseClass.java,請嘗試編譯並載入該類。 如果成功轉到(2)。
  • 否則,請將UseClass解譯為完全限定的類名,並嘗試從OSGi環境載入它。 如果成功轉到(2)。
  • 否則,請將UseClass解譯為HTL或JavaScript檔案的路徑,並載入該檔案。 如果goto(4)成功,

(2)

  • 嘗試將當前Resource調整為UseClass。 如果成功,請轉至(3)。
  • 否則,請嘗試將當前Request調整為UseClass。 如果成功,請轉至(3)。
  • 否則,請嘗試使用零參數建構函式實例化UseClass。 如果成功,請轉至(3)。

(3)

  • 在HTL中,將新調整或建立的物件系結至名稱localName
  • 如果UseClass實作io.sightly.java.api.Use,則調用init方法,傳遞當前執行上下文(以javax.scripting.Bindings對象的形式)。

(4)

  • 如果UseClass是包含data-sly-template之HTL檔案的路徑,請準備範本。
  • 否則,如果UseClass是JavaScript use-class的路徑,請準備use-class(請參閱JavaScript Use-API)。

上述說明的幾個要點:

  • 任何可從Resource調整、可從Request調整,或具有零參數建構函式的類別都可以是use-class。 類不必擴展WCMUsePojo甚至實現Use
  • 不過,如果use-class does​實作Use,則其init方法會自動與目前的內容一起呼叫,讓您將初始化程式碼放在該內容上。
  • 擴展WCMUsePojo的use-class只是實施Use的特殊情況。 它提供了方便的上下文方法,並自動從Use.init調用其activate方法。

直接實施介面使用

雖然建立use-class的最常見方式是擴展WCMUsePojo ,但也可以直接實施io.sightly.java.api.Use介面本身。

Use介面僅定義一種方法:

public void init(javax.script.Bindings bindings)

對於具有Bindings對象的類的初始化,將調用init方法,該對象保存所有上下文對象和傳遞到use-class中的任何參數。

必須使用javax.script.Bindings物件明確實作所有其他功能(例如WCMUsePojo.getProperties()的等值)。 例如:

Info.java

import io.sightly.java.api.Use;

public class MyComponent implements Use {
   ...
    @Override
    public void init(Bindings bindings) {

        // All standard objects/binding are available
        Resource resource = (Resource)bindings.get("resource");
        ValueMap properties = (ValueMap)bindings.get("properties");
        ...

        // Parameters passed to the use-class are also available
        String param1 = (String) bindings.get("param1");
    }
    ...
}

當您希望將現有類的子類用作use-class時,您可以自行實施Use介面,而不是擴展WCMUsePojo

從資源調整

另一個選項是使用從org.apache.sling.api.resource.Resource可調整的輔助類。

假設您需要編寫HTL指令碼,以顯示DAM資產的中型。 在本例中,您知道在呼叫HTL指令檔時,它會位於Resource的內容中,該內容會以nodetype dam:Asset包住JCR Node

您知道dam:Asset節點的結構如下:

儲存庫結構

{
  "content": {
    "dam": {
      "geometrixx": {
        "portraits": {
          "jane_doe.jpg": {
            ...
          "jcr:content": {
            ...
            "metadata": {
              ...
            },
            "renditions": {
              ...
              "original": {
                ...
                "jcr:content": {
                  "jcr:primaryType": "nt:resource",
                  "jcr:lastModifiedBy": "admin",
                  "jcr:mimeType": "image/jpeg",
                  "jcr:lastModified": "Fri Jun 13 2014 15:27:39 GMT+0200",
                  "jcr:data": ...,
                  "jcr:uuid": "22e3c598-4fa8-4c5d-8b47-8aecfb5de399"
                }
              },
              "cq5dam.thumbnail.319.319.png": {
                  ...
              },
              "cq5dam.thumbnail.48.48.png": {
                  ...
              },
              "cq5dam.thumbnail.140.100.png": {
                  ...
              }
            }
          }  
        }
      }
    }
  }
}

在這裡,我們會顯示AEM預設安裝隨附的資產(JPEG影像),做為範例專案geometrixx的一部分。 資產稱為jane_doe.jpg,其mimetype為image/jpeg

若要從HTL中存取資產,您可以將com.day.cq.dam.api.Asset宣告為data-sly-use陳述式中的類別,然後使用Asset的get方法來擷取所需資訊。 例如:

mimetype.html

<div data-sly-use.asset="com.day.cq.dam.api.Asset">
  <p>${asset.mimeType}</p>
</div>

data-sly-use陳述式會指示HTL將目前的Resource調整為Asset,並為它指定本機名稱asset。 然後,它使用HTL getter shorthand呼叫AssetgetMimeType方法:asset.mimeType

從請求調整

還可以將任何從org.apache.sling.api.SlingHttpServletRequest可適應的類作為使用類使用

與上述從Resource適應的use-class一樣,可在data-sly-use語句中指定從SlingHttpServletRequest適應的use-class。 執行時,目前的要求將會適應給定的類別,而產生的物件將可在HTL中使用。

本頁內容