Show Menu
ARGOMENTI×

API di utilizzo Java HTL

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 . Questo consente di incorporare nel codice Java tutte le logiche aziendali complesse, mentre il codice HTL si occupa solo della produzione di markup diretti.
Un oggetto Java Use-API può essere un semplice POJO, istanziato da una particolare implementazione tramite il costruttore predefinito di POJO.
I POJO Use-API possono inoltre esporre un metodo pubblico, denominato init, con la seguente firma:
    /**
     * Initializes the Use bean.
     *
     * @param bindings All bindings available to the HTL scripts.
     **/
    public void init(javax.script.Bindings bindings);

La bindings mappa può contenere oggetti che forniscono contesto allo script HTL attualmente eseguito che l'oggetto Use-API può utilizzare per la relativa elaborazione.

Esempio semplice

Inizieremo con un componente HTL che non dispone di una classe use. È costituito da un unico file, /apps/my-example/components/info.html

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

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

Per eseguire il rendering di questo componente è inoltre necessario aggiungere del contenuto in /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."
}

Quando si accede a questo contenuto, viene eseguito il file HTL. All'interno del codice HTL utilizziamo l'oggetto contestuale properties per accedere alla risorsa corrente title description e visualizzarla. L'HTML di output sarà:

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

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

Aggiunta di una classe d'uso

Il componente info così com'è non ha bisogno di una classe use per eseguire la sua funzione (molto semplice). Ci sono tuttavia dei casi in cui è necessario fare cose che non possono essere fatte in HTL e quindi è necessario un use-class. Tenete presente quanto segue:
Utilizzare una classe use solo quando non è possibile eseguire operazioni in HTL.
Ad esempio, se desiderate che il info componente visualizzi le title e description le proprietà della risorsa, il tutto in lettere minuscole. Poiché HTL non dispone di un metodo per le stringhe di tipo minuscolo, sarà necessario utilizzare la classe. A tal fine, è possibile aggiungere una classe d'uso Java e modificare le info.html seguenti impostazioni:

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

Nelle sezioni che seguono passiamo attraverso le diverse parti del codice.

Classe Java locale e Bundle

Java use-class può essere installato in due modi: locale o bundle . In questo esempio viene utilizzata un'installazione locale.
In un’installazione locale, il file di origine Java viene posizionato accanto al file HTL, nella stessa cartella del repository. L'origine viene compilata automaticamente su richiesta. Non è richiesta alcuna fase di compilazione o di imballaggio separata.
In un’installazione bundle, la classe Java deve essere compilata e distribuita all’interno di un bundle OSGi utilizzando il meccanismo di distribuzione standard del bundle AEM (consultate Bundled Java Class ).
È consigliabile utilizzare una classe Java locale quando la classe use è specifica per il componente in questione.
È consigliabile creare un bundle Java use-class quando il codice Java implementa un servizio a cui si accede da più componenti HTL.

Il pacchetto Java è il percorso dell'archivio

Quando viene utilizzata un'installazione locale, il nome del pacchetto della classe use deve corrispondere a quello del percorso della cartella del repository, con i trattini nel percorso sostituiti da caratteri di sottolineatura nel nome del pacchetto.
In questo caso Info.java si trova in /apps/my-example/components/info modo che il pacchetto sia 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 {

   ...

}

L’utilizzo di trattini nei nomi degli elementi del repository è una pratica consigliata nello sviluppo di AEM. Tuttavia, i trattini non sono consentiti nei nomi dei pacchetti Java. Per questo motivo, tutti i trattini nel percorso dell'archivio devono essere convertiti in caratteri di sottolineatura nel nome del pacchetto.

Estensione WCMUsePojo

Mentre esistono diversi modi per incorporare una classe Java con HTL (vedere Alternative a WCMUsePojo ), il più semplice è quello di estendere la WCMUsePojo classe:

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

package apps.my_example.components.info;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo

    ...
}

Inizializzazione della classe

Quando use-class viene esteso da WCMUsePojo , l'inizializzazione viene eseguita ignorando il activate metodo:

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

...

}

Contesto

In genere, il metodo activate viene utilizzato per calcolare e memorizzare (nelle variabili membro) i valori necessari nel codice HTL, in base al contesto corrente (ad esempio la richiesta e la risorsa correnti).
La WCMUsePojo classe fornisce l'accesso allo stesso set di oggetti contestuali disponibile all'interno di un file HTL (vedere Oggetti Oggetti globali di HTL globali).
In una classe che si estende, WCMUsePojo è possibile accedere agli oggetti contestuali per nome utilizzando
In alternativa, è possibile accedere direttamente agli oggetti contestuali di uso comune tramite il metodo ​comodità appropriato:

Metodi Getter

Una volta inizializzata la classe use, il file HTL viene eseguito. In questa fase HTL esegue in genere il pulling dello stato di varie variabili membro della classe use ed eseguirà il rendering per la presentazione.
Per consentire l’accesso a questi valori dall’interno del file HTL, è necessario definire metodi getter personalizzati nella classe use in base alla seguente convenzione di denominazione:
  • Un metodo del modulo getXyz espone nel file HTL una proprietà oggetto denominata xyz .
Nell'esempio seguente, i metodi getTitle e getDescription i risultati ottenuti rendono le proprietà dell'oggetto title e description diventano accessibili nel contesto del file HTL:

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

...

public class Info extends WCMUsePojo {

    ...

    public String getLowerCaseTitle() {
        return lowerCaseTitle;
    }

    public String getLowerCaseDescription() {
        return lowerCaseDescription;
    }
}

attributo di utilizzo semplice dei dati

L’ data-sly-use attributo viene utilizzato per inizializzare la classe use all’interno del codice HTL. Nel nostro esempio, l' data-sly-use attributo dichiara che si desidera utilizzare la classe Info . Possiamo usare solo il nome locale della classe perché stiamo utilizzando un'installazione locale (dopo aver inserito il file di origine Java si trova nella stessa cartella del file HTL). Se utilizzassimo un'installazione bundle, dovremmo specificare il nome completo della classe.

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

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

Identificatore locale

L’identificatore info (dopo il punto in data-sly-use.info ) viene utilizzato nel file HTL per identificare la classe. L'ambito di questo identificatore è globale all'interno del file, dopo che è stato dichiarato. Non è limitato all'elemento che contiene l' data-sly-use istruzione.

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

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

Ottenimento delle proprietà

L'identificatore info viene quindi utilizzato per accedere alle proprietà dell'oggetto title e description che sono state esposte tramite i metodi getter Info.getTitle e Info.getDescription .

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

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

Output

Ora, quando accediamo, /content/my-example.html restituirà il seguente HTML:

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

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

Oltre Le Nozioni Di Base

In questa sezione presenteremo alcune ulteriori funzioni che vanno oltre il semplice esempio precedente:
  • Trasmissione di parametri a una classe use.
  • Classe di utilizzo Java in bundle.
  • Alternative a WCMUsePojo

Trasmissione parametri

I parametri possono essere passati a una classe use al momento dell'inizializzazione. Per esempio, potremmo fare qualcosa del genere:

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

Qui stiamo passando un parametro chiamato text . use-class quindi aggiorna la stringa recuperata e visualizza il risultato con info.upperCaseText . Di seguito è riportata la classe d'uso corretta:

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

    ...
}

Il parametro è accessibile tramite il WCMUsePojo metodo <T> T get(String paramName, Class<T> type)
Nel nostro caso, la dichiarazione:
get("text", String.class)
La stringa viene quindi invertita ed esposta tramite il metodo:
getReverseText()

Passa solo parametri da un modello basato su dati

Sebbene l'esempio di cui sopra sia tecnicamente corretto, in realtà non ha molto senso trasmettere un valore da HTL per inizializzare una classe use, quando il valore in questione è disponibile nel contesto di esecuzione del codice HTL (o, in modo banale, il valore è statico, come sopra).
Il motivo è che la classe use avrà sempre accesso allo stesso contesto di esecuzione del codice HTL. Questo fornisce un punto di partenza per l'importazione delle best practice:
Il passaggio di un parametro a una classe use deve essere eseguito solo quando la classe use viene utilizzata in un data-sly-template file che viene chiamato da un altro file HTL con parametri che devono essere trasmessi.
Ad esempio, creiamo un data-sly-template file separato con il nostro esempio esistente. Chiameremo il nuovo file extra.html . Contiene un data-sly-template blocco denominato 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>

Il modello extra , prende un singolo parametro, text . Inizializza quindi Java use-class ExtraHelper con il nome locale extraHelper e gli passa il valore del parametro template text come parametro use-class text .
Il corpo del modello ottiene la proprietà extraHelper.reversedText (che, sotto il cofano, chiama effettivamente ExtraHelper.getReversedText() ) e visualizza quel valore.
Inoltre adattiamo le nostre esistenti info.html per utilizzare questo nuovo modello:

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

Il file info.html ora contiene due data-sly-use istruzioni, quella originale che importa la classe d'uso Info Java e una nuova che importa il file modello con il nome locale extra .
Si noti che avremmo potuto inserire il blocco modello all'interno del info.html file per evitare il secondo data-sly-use , ma un file modello separato è più comune e riutilizzabile.
La Info classe viene utilizzata come precedente, chiamando i relativi metodi getter getLowerCaseTitle() e getLowerCaseDescription() attraverso le proprietà HTL corrispondenti info.lowerCaseTitle e info.lowerCaseDescription .
Quindi eseguiamo una data-sly-call operazione sul modello extra e trasmettiamo il valore properties.description come parametro text .
Java use-class Info.java viene modificato per gestire il nuovo parametro di testo:

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

Il text parametro viene recuperato con get("text", String.class) , il valore viene invertito e reso disponibile come oggetto HTL reversedText attraverso il getter getReversedText() .

Classe Java Bundle

Con una classe d’uso bundle, la classe deve essere compilata, inclusa in pacchetti e distribuita in AEM tramite il meccanismo di distribuzione standard OSGi. A differenza di un'installazione locale, la dichiarazione del pacchetto use-class deve essere denominata normalmente:

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

package org.example.app.components;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo {
    ...
}

e, l' data-sly-use istruzione deve fare riferimento al nome di classe completo, anziché al solo nome della classe locale:

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

Alternative a WCMUsePojo

Il modo più comune per creare una classe d'uso Java è quello di estendere WCMUsePojo . Esistono tuttavia diverse altre opzioni. Per capire queste varianti aiuta a capire come funziona l' data-sly-use istruzione HTL sotto la cappa.
Si supponga di disporre della seguente data-sly-use istruzione:
<div data-sly-use. localName =" UseClass ">
Il sistema elabora l'istruzione come segue:
(1)
  • Se esiste un file locale UseClass.java nella stessa directory del file HTL, provate a compilarlo e caricarlo. In caso di esito positivo, passare a (2).
  • In caso contrario, interpretate UseClass come nome di classe completo e provate a caricarlo dall’ambiente OSGi. In caso di esito positivo, passare a (2).
  • In caso contrario, interpretate UseClass come percorso di un file HTL o JavaScript e caricate il file. Se il risultato è positivo (4).
(2)
  • Prova ad adattare la corrente Resource a UseClass . In caso di esito positivo, passare a (3).
  • In caso contrario, provare ad adattare la corrente Request a UseClass . In caso di esito positivo, passare a (3).
  • In caso contrario, provare a creare un'istanza UseClass con un costruttore a argomenti zero. In caso di esito positivo, passare a (3).
(3)
  • All'interno di HTL, vincolate l'oggetto appena adattato o creato al nome localName .
  • Se UseClass implementa io.sightly.java.api.Use allora chiama il init metodo, passando il contesto di esecuzione corrente (nel modulo di un javax.scripting.Bindings oggetto).
(4)
  • Se UseClass si tratta di un percorso a un file HTL contenente un file data-sly-template , preparate il modello.
  • In caso contrario, se UseClass si tratta di un percorso a una classe use JavaScript, preparare la classe use (vedere JavaScript Use-API ).
Alcuni punti significativi sulla descrizione di cui sopra:
  • Qualsiasi classe adattabile da Resource , adattabile da Request o con un costruttore a argomento zero può essere una classe use. La classe non deve estendere WCMUsePojo o implementare Use .
  • Tuttavia, se la classe use non viene implementata Use , il relativo init metodo verrà chiamato automaticamente con il contesto corrente, consentendo di inserire il codice di inizializzazione che dipende da tale contesto.
  • Una classe d'uso che si estende WCMUsePojo è solo un caso speciale di implementazione Use . Fornisce i metodi di contesto di convenienza e il suo activate metodo viene chiamato automaticamente da Use.init .

Implementazione diretta dell'interfaccia

Anche se il modo più comune per creare una classe d'uso è quello di estendere WCMUsePojo , è anche possibile implementare direttamente l' io.sightly.java.api.Use interfaccia stessa.
L' Use interfaccia definisce un solo metodo:
Il init metodo viene chiamato all'inizializzazione della classe con un Bindings oggetto che contiene tutti gli oggetti contestuali e tutti i parametri passati alla classe use.
Tutte le funzionalità aggiuntive (come l'equivalente di WCMUsePojo.getProperties() ) devono essere implementate esplicitamente utilizzando l' javax.script.Bindings oggetto. Ad esempio:

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

Il caso principale per implementare l' Use interfaccia in sé invece di estenderla WCMUsePojo è quando si desidera utilizzare una sottoclasse di una classe già esistente come classe use.

Adattabile dalla risorsa

Un'altra opzione consiste nell'utilizzare una classe helper adattabile da org.apache.sling.api.resource.Resource .
Supponiamo che sia necessario scrivere uno script HTL che visualizzi il tipo mimetico di una risorsa DAM. In questo caso si sa che quando viene chiamato lo script HTL, lo script sarà all'interno del contesto di un Resource che racchiude un JCR Node con un tipo di nodo dam:Asset .
È noto che un dam:Asset nodo ha una struttura come questa:

Struttura archivio

{
  "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": {
                  ...
              }
            }
          }  
        }
      }
    }
  }
}

Qui viene mostrata la risorsa (un'immagine JPEG) fornita con un'installazione predefinita di AEM come parte del progetto di esempio geometrixx. La risorsa viene chiamata jane_doe.jpg e il suo mimetismo è image/jpeg .
Per accedere alla risorsa dall'interno di HTL, potete dichiarare com.day.cq.dam.api.Asset come classe nell' data-sly-use istruzione e quindi utilizzare un metodo get per Asset recuperare le informazioni desiderate. Ad esempio:

mimetype.html

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

L' data-sly-use istruzione indirizza HTL per adattare la corrente Resource a un Asset e gli dà il nome locale asset . Quindi, chiama il getMimeType metodo di Asset utilizzo della abbreviazione getter HTL: asset.mimeType .

Adattabile da richiesta

È inoltre possibile utilizzare come classe use qualsiasi classe adattabile da org.apache.sling.api.SlingHttpServletRequest
Come nel caso precedente di un adattatore use-class da Resource , nell'istruzione SlingHttpServletRequest data-sly-use è possibile specificare un adattatore use-class da. Al momento dell'esecuzione, la richiesta corrente verrà adattata alla classe specificata e l'oggetto risultante sarà reso disponibile all'interno di HTL.