Show Menu
TOPICS×

HTL-Java-Anwendungs-API

The HTML Template Language (HTL) Java Use-API enables an HTL file to access helper methods in a custom Java class through
data-sly-use
. Dadurch kann die gesamte komplexe Geschäftslogik im Java-Code verkapselt werden, während der HTL-Code nur die direkte Markup-Produktion verarbeiten muss.
Ein Java-Use-API-Objekt kann ein einfaches POJO sein, das von einer bestimmten Implementierung über den Standardkonstruktor des POJO instanziiert wird.
Die Use-API-POJOs können auch eine öffentliche Methode mit dem Namen init mit der folgenden Unterschrift verfügbar machen:
/** * Initializes the Use bean. * * @param bindings All bindings available to the HTL scripts. **/ public void init(javax.script.Bindings bindings);
Die
bindings
Zuordnung kann Objekte enthalten, die dem derzeit ausgeführten HTML-Skript Kontext geben, das das Use-API-Objekt für seine Verarbeitung verwenden kann.

Ein einfaches Beispiel

Wir beginnen mit einer HTL-Komponente, die über keine Anwendungsklasse verfügt. Sie besteht aus einer einzelnen Datei,
/apps/my-example/components/info.html

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

<div> <h1>${properties.title}</h1> <p>${properties.description}</p> </div>
Wir fügen zudem etwas Inhalt für diese unter
/content/my-example/
darzustellende Komponente hinzu:

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

{ "sling:resourceType": "my-example/component/info", "title": "My Example", "description": "This Is Some Example Content." }
Wenn auf diesen Inhalt zugegriffen wird, wird die HTL-Datei ausgeführt. Within the HTL code we use the context object
properties
to access the current resource's
title
and
description
and display them. Die HTML-Ausgabe lautet:

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

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

Hinzufügen einer Anwendungsklasse

Die Komponente 
info
 benötigt in ihrer gegebenen Form keine Anwendungsklasse zum Ausführen ihrer (sehr einfachen) Funktion. Es gibt Fälle, in denen Sie jedoch Aktionen vornehmen müssen, die nicht in HTL erfolgen können, und daher eine Anwendungsklasse verwenden müssen. Hinweis:
Eine Anwendungsklasse sollte nur verwendet werden, wenn eine Aktion nicht allein in HTL ausgeführt werden kann.
Angenommen, Sie möchten, dass die Komponente
info
die Eigenschaften
title
und
description
der Ressource anzeigt, jedoch komplett in Kleinschreibung. Da HTL über keine Methode zur Zeichenfolgenkleinschreibung verfügt, benötigen Sie eine Anwendungsklasse. Wir können dies vornehmen, indem eine Java-Anwendungsklasse hinzugefügt und die Datei
info.html
wie folgt geändert wird:

/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; } }
In den folgenden Abschnitten zeigen wir die unterschiedlichen Teile des Codes.

Local vs. Bundle Java Class

Die Java-Anwendungsklasse kann auf zwei Arten installiert werden: 
lokal
oder
gebündelt
. In diesem Beispiel wird eine lokale Installation verwendet.
In einer lokalen Installation wird die Java-Quelldatei zusammen mit der HTL-Datei im selben Repository-Ordner platziert. Die Quelle wird automatisch nach Bedarf kompiliert. Es ist kein separater Kompilierungs- oder Verpackungsschritt erforderlich.
In einer Bundle-Installation muss die Java-Klasse mithilfe des standardmäßigen AEM-Bundle-Bereitstellungsmechanismus (siehe Gebündelte Java-Klasse ) in einem OSGi-Bundle kompiliert und bereitgestellt werden.
Eine
lokale Java-Anwendungsklasse
wird empfohlen, wenn die Anwendungsklasse für die betroffene Komponente spezifisch ist.
Eine
gebündelte Java-Anwendungsklasse
wird empfohlen, wenn der Java-Code einen Service implementiert, auf den über mehrere HTL-Komponenten zugegriffen wird.

Java-Paket ist der Repository-Pfad

Wenn eine lokale Installation verwendet wird, muss der Paketname der Anwendungsklasse mit dem des Repository-Ordner-Speicherorts übereinstimmen, wobei alle Bindestriche im Pfad durch Unterstriche im Paketnamen ersetzt werden.
In diesem Fall befindet sich 
Info.java
unter
/apps/my-example/components/info
. Daher lautet das Paket :
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 { ... }
Die Verwendung von Bindestrichen in den Namen von Repository-Elementen ist eine empfohlene Vorgehensweise bei der AEM-Entwicklung. Bindestriche sind jedoch in Java-Paketnamen ungültig. Daher müssen
alle Bindestriche im Repository-Pfad für den Paketnamen in Unterstriche umgewandelt werden
.

Erweitern
WCMUsePojo

Es gibt zwar etliche Möglichkeiten, eine Java-Klasse mit HTL (siehe Alternativen zu
WCMUsePojo
) zu integrieren, jedoch besteht die einfachste Möglichkeit darin, die
WCMUsePojo
-Klasse zu erweitern:

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

package apps.my_example.components.info; import com.adobe.cq.sightly.WCMUsePojo; public class Info extends WCMUsePojo ... }

Initialisieren der Klasse

When the use-class is extended from
WCMUsePojo
, initialization is performed by overriding the
activate
method:

/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(); } ... }

Kontext

Typically, the activate method is used to precompute and store (in member variables) the values needed in your HTL code, based on the current context (the current request and resource, for example).
Die
WCMUsePojo
-Klasse bietet Zugriff auf denselben Satz an Kontextobjekten, die in einer HTL-Datei verfügbar sind (siehe Globale Objekte ).
In einer
WCMUsePojo
erweiternden Klasse ist der Zugriff auf Kontextobjekte nach Name möglich mit
Alternativ ist der Zugriff auf häufig verwendete Kontextobjekte direkt über die entsprechende
Convenience-Methode
möglich:

Getter-Methoden

Nach der Initialisierung der Anwendungsklasse wird die HTL-Datei ausgeführt. In dieser Phase ruft HTL für gewöhnlich den Status verschiedener Member-Variablen der Anwendungsklasse ab und rendert sie für die Darstellung.
Um den Zugriff auf diese Werte in der HTL-Datei zu ermöglichen, müssen Sie gemäß der folgenden Benennungskonvention benutzerdefinierte Getter-Methoden in der Anwendungsklasse definieren:
  • Eine Methode in der Form 
    getXyz
     stellt in der HTL-Datei eine Objekteigenschaft mit dem Namen
    xyz
    zur Verfügung.
In the following example, the methods
getTitle
and
getDescription
result in the object properties
title
and
description
becoming accessible within the context of the HTL file:

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

... public class Info extends WCMUsePojo { ... public String getLowerCaseTitle() { return lowerCaseTitle; } public String getLowerCaseDescription() { return lowerCaseDescription; } }

Attribut „data-sly-use“

Das Attribut
data-sly-use
wird verwendet, um die Anwendungsklasse innerhalb Ihres HTL-Codes zu initialisieren. In unserem Beispiel deklariert das Attribut 
data-sly-use
, dass wir die Klasse
Info
verwenden möchten. Wir können nur den lokalen Namen der Klasse verwenden, da wir eine lokale Installation verwenden (wobei die Java-Quelldatei im selben Ordner wie die HTL-Datei platziert wurde). Wenn wir eine Bundle-Installation verwenden, müssen wir den vollständig qualifizierten Klassennamen angeben.

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

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

Lokaler Bezeichner

The identifier
info
(after the dot in
data-sly-use.info
) is used within the HTL file to identify the class. Dieser Bezeichner erstreckt sich global in der Datei, nachdem er deklariert wurde. Er ist nicht auf das Element beschränkt, das die Anweisung
data-sly-use
enthält.

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

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

Abrufen von Eigenschaften

Der Bezeichner
info
wird anschließend verwendet, um auf die Objekteigenschaften
title
und
description
 zuzugreifen, die mithilfe der Getter-Methoden
Info.getTitle
 und
Info.getDescription
zur Verfügung gestellt wurden.

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

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

Ausgabe

Wenn wir nun auf
/content/my-example.html
zugreifen, wird die folgende HTML zurückgegeben:

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

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

Über die Grundlagen hinaus

In diesem Abschnitt werden wir einige weitere Funktionen vorstellen, die über das einfache Beispiel oben hinausgehen:
  • Weitergeben von Parametern an eine Anwendungsklasse
  • Gebündelte Java-Anwendungsklasse
  • Alternativen zu
    WCMUsePojo

Weitergeben von Parametern

Parameter können bei der Initialisierung an eine Anwendungsklasse weitergegeben werden. Zum Beispiel können wir Folgendes vornehmen:

/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>
Hier geben wir einen Parameter mit dem Namen
text
weiter. Die Anwendungsklasse setzt die Zeichenfolge, die wir abrufen, dann in Großbuchstaben und zeigt das Ergebnis mit
info.upperCaseText
an. Hier finden Sie die angepasste Anwendungsklasse:

/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; } ... }
Der Zugriff auf den Parameter erfolgt über die Methode
WCMUsePojo
<T> T get(String paramName, Class<T> type)
In unserem Fall ist dies die Anweisung:
get("text", String.class)
Die Zeichenfolge wird dann umgekehrt und zur Verfügung gestellt über die Methode:
getReverseText()

Parameter nur aus der data-sly-template weitergeben

Auch wenn das obige Beispiel aus technischer Sicht richtig ist, ist es in Wirklichkeit nicht sehr sinnvoll, einen Wert aus HTL zum Initialisieren einer Anwendungsklasse weiterzugeben, wenn der entsprechende Wert im Ausführungskontext des HTL-Codes verfügbar ist (oder der Wert ist trivialerweise statisch, wie oben).
Der Grund besteht darin, dass die Anwendungsklasse immer auf denselben Ausführungskontext wie der HTL-Code zugreifen kann. Dies bringt einen wichtigen Best-Practice-Punkt ans Licht:
Das Weitergeben eines Parameters an eine Anwendungsklasse sollte nur dann erfolgen, wenn die Anwendungsklasse in einer
data-sly-template
-Datei verwendet wird, die wiederum über eine andere HTL-Datei mit Parametern abgerufen wird, die weitergegeben werden müssen.
Lassen Sie uns beispielsweise eine separate
data-sly-template
-Datei neben unserem vorhandenen Beispiel erstellen. Wir nennen die neue Datei
extra.html
. Sie enthält einen
data-sly-template
-Block mit dem Namen
extra
:

/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>
Die Vorlage
extra
verwendet einen einzelnen Parameter
text
. Anschließend initialisiert sie die Java-Anwendungsklasse
ExtraHelper
mit dem lokalen Namen
extraHelper
und gibt den Wert des Vorlagenparameters
text
als den Anwendungsklassenparameter
text
weiter.
Der Text der Vorlage erhält die Eigenschaft
extraHelper.reversedText
(die im Hintergrund
ExtraHelper.getReversedText()
aufruft) und zeigt diesen Wert an.
Wir passen auch unsere vorhandene
info.html
für die Verwendung dieser neuen Vorlage an:

/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>
Die Datei
info.html
enthält nun zwei
data-sly-use
-Anweisungen: die ursprüngliche, die die Java-Anwendungsklasse
Info
importiert, und eine neue, die die Vorlagendatei unter dem lokalen Namen
extra
importiert.
Beachten Sie, dass wir den Vorlagenblock in der Datei
info.html
platzieren könnten, um eine zweite
data-sly-use
zu verhindern. Eine separate Vorlagendatei ist jedoch gängiger und besser wiederverwendbar.
Die
Info
-Klasse wird wie zuvor verwendet und ruft ihre Getter-Methoden
getLowerCaseTitle()
und
getLowerCaseDescription()
 durch ihre entsprechenden HTL-Eigenschaften
info.lowerCaseTitle
und
info.lowerCaseDescription
auf.
Anschließend führen wir einen
data-sly-call
zur Vorlage
extra
aus und geben ihr den Wert
properties.description
als den Parameter
text
weiter.
Die Java-Anwendungsklasse
Info.java
wird geändert, um den neuen Textparameter zu verarbeiten:

/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; } }
Der Parameter
text
wird mit 
get("text", String.class)
abgerufen, der Wert wird umgekehrt und über den Getter
reversedText
als HTL-Objekt
getReversedText()
 zur Verfügung gestellt.

Gebündelte Java-Klasse

Bei einer Bundle-Anwendungsklasse muss die Klasse mithilfe der standardmäßigen OSGi-Bundle-Bereitstellungsmethode kompiliert, verpackt und in AEM bereitgestellt werden. Im Gegensatz zu einer lokalen Installation sollte die Anwendungsklassen-
Paketdeklaration
normal benannt werden:

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

package org.example.app.components; import com.adobe.cq.sightly.WCMUsePojo; public class Info extends WCMUsePojo { ... }
Zudem muss die Anweisung
data-sly-use
auf den vollqualifizierten Klassennamen verweisen und nicht nur auf den lokalen Klassennamen:

/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>

Alternativen zu
WCMUsePojo

Die gängigste Möglichkeit, eine Java-Anwendungsklasse zu erstellen, besteht darin,
WCMUsePojo
zu erweitern. Es gibt jedoch einige andere Optionen. Für das Verständnis dieser Varianten ist es hilfreich zu wissen, wie die HTL-Anweisung
data-sly-use
im Hintergrund funktioniert.
Angenommen, Sie verfügen über die folgende
data-sly-use
-Anweisung:
<div data-sly-use.
localName
="
UseClass
">
Das System verarbeitet die Anweisung wie folgt:
(1)
  • Wenn eine lokale 
    UseClass.java
    -Datei im selben Verzeichnis wie die HTL-Datei vorhanden ist, versuchen Sie, diese Klasse zu kompilieren und zu laden. Wechseln Sie bei Erfolg zu (2).
  • Interpretieren Sie andernfalls
    UseClass
    als einen vollqualifizierten Klassennamen und versuchen Sie, ihn über die OSGi-Umgebung zu laden. Wechseln Sie bei Erfolg zu (2).
  • Interpretieren Sie andernfalls
    UseClass
    als einen Pfad zu einer HTL- oder JavaScript-Datei und laden Sie diese Datei. Wechseln Sie bei Erfolg zu (4).
(2)
  • Try to adapt the current
    Resource
    to
    UseClass
    . If successful, go to (3).
  • Versuchen Sie andernfalls, die aktuelle
    Request
    an
    UseClass
    anzupassen. Wechseln Sie bei Erfolg zu (3).
  • Versuchen Sie andernfalls,
    UseClass
    mit einem Zero-Argument-Konstruktor zu instanziieren. Wechseln Sie bei Erfolg zu (3).
(3)
  • Verbinden Sie in HTL das neu angepasste oder erstellte Objekt mit dem Namen
    localName
    .
  • If
    UseClass
    implements
    io.sightly.java.api.Use
    then call the
    init
    method, passing the current execution context (in the form of a
    javax.scripting.Bindings
    object).
(4)
  • Wenn
    UseClass
    ein Pfad zu einer HTL-Datei ist, die eine
    data-sly-template
    enthält, sollten Sie die Vorlage vorbereiten.
  • Wenn andernfalls
    UseClass
    ein Pfad zu einer JavaScript-Anwendungsklasse ist, sollten Sie die Anwendungsklasse vorbereiten (siehe JavaScript-Anwendungs-API ).
Im Folgenden finden Sie einige wichtige Punkte zur obigen Beschreibung:
  • Jede Klasse, die aus einer
    Resource
    oder einer
    Request
    angepasst werden kann oder einen Zero-Argument-Konstruktor aufweist, kann eine Anwendungsklasse sein. Die Klasse muss
    WCMUsePojo
    nicht erweitern oder gar
    Use
    implementieren.
  • Wenn die Anwendungsklasse
    jedoch
    Use
    implementiert, wird die zugehörige
    init
    -Methode im aktuellen Kontext automatisch abgerufen, wodurch Sie dort kontextbasierten Initialisierungscode platzieren können.
  • Eine
    WCMUsePojo
    erweiternde Anwendungsklasse ist nur ein Sonderfall der Implementierung von
    Use
    . Sie bietet praktische Kontextmethoden und ihre
    activate
    -Methode wird automatisch über
    Use.init
    abgerufen.

Direkte Implementierung der Schnittstellenverwendung

Auch wenn die einfachste Möglichkeit für die Erstellung einer Anwendungsklasse darin besteht,
WCMUsePojo
zu erweitern, ist es auch möglich, die
io.sightly.java.api.Use
Die Schnittstelle
Use
definiert nur eine Methode:
Die
init
-Methode wird beim Initialisieren der Klasse mit einem
Bindings
-Objekt abgerufen, das alle Kontextobjekte und die an die Anwendungsklasse weitergegebenen Parameter enthält.
All additional functionality (such as the equivalent of
WCMUsePojo.getProperties()
) must be implemented explicitly using the
javax.script.Bindings
object. Beispiel:

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"); } ... }
Die Hauptursache für das eigenständige Implementieren der Schnittstelle
Use
anstelle der Erweiterung von
WCMUsePojo
besteht in der gewünschten Verwendung einer Unterklasse einer bereits als die Anwendungsklasse verwendeten vorhandenen Klasse.

Aus Ressource anpassbar

Eine weitere Option besteht in der Verwendung einer Hilfsklasse, die über
org.apache.sling.api.resource.Resource
angepasst werden kann.
Angenommen, Sie müssen ein HTL-Skript schreiben, dass den mimetyp eines DAM-Assets anzeigt. In diesem Fall wissen Sie, dass sich Ihr HTL-Skript, wenn es abgerufen wird, im Kontext einer
Resource
befindet, die einen JCR-
Node
 mit Knotentyp
dam:Asset
umbricht.
Sie wissen, dass ein Knoten vom Typ
dam:Asset
über eine derartige Struktur verfügt:

Repository-Struktur

{ "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": { ... } } } } } } } }
Hier zeigen wir das Asset (ein JPEG-Bild), das bei einer Standardinstallation von AEM als Bestandteil des Beispielprojekts geometrixx integriert ist. Das Asset heißt
jane_doe.jpg
 und der zugehörige mimetype lautet
image/jpeg
.
To access the asset from within HTL, you can declare
com.day.cq.dam.api.Asset
as the class in the
data-sly-use
statement and then use a get method of
Asset
to retrieve the desired information. Beispiel:

mimetype.html

<div data-sly-use.asset="com.day.cq.dam.api.Asset"> <p>${asset.mimeType}</p> </div>
Die Anweisung
data-sly-use``Resource
fordert die HTL auf, die aktuelle für ein
Asset
anzupassen, und gibt ihr den lokalen Namen
asset
. Anschließend ruft sie die Methode
getMimeType
des
Asset
mithilfe der HTL-Getter-Kurzschreibweise auf:
asset.mimeType
.

Aus Anforderung anpassbar

It is also possible to employ as a use-class any class that is adaptable from
org.apache.sling.api.SlingHttpServletRequest
As with the above case of a use-class adaptable from
Resource
, a use-class adaptable from
SlingHttpServletRequest
can be specified in the
data-sly-use
statement. Bei der Ausführung wird die aktuelle Anforderung an die gegebene Klasse angepasst und das daraus resultierende Objekt wird in HTL zur Verfügung gestellt.