Show Menu
TOPICS×

API de uso do Java do 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
. Isso permite que toda a lógica comercial complexa seja encapsulada no código Java, enquanto o código HTL trata somente da produção de marcação direta.
Um objeto Java Use-API pode ser um POJO simples, instanciado por uma implementação específica por meio do construtor padrão do POJO.
Os POJOs Use-API também podem expor um método público, chamado init, com a seguinte assinatura:
/** * Initializes the Use bean. * * @param bindings All bindings available to the HTL scripts. **/ public void init(javax.script.Bindings bindings);
O
bindings
mapa pode conter objetos que fornecem contexto para o script HTL executado no momento que o objeto Use-API pode usar para seu processamento.

Um exemplo simples

Vamos start com um componente HTL que não tem uma classe de uso. Consiste num único ficheiro.
/apps/my-example/components/info.html

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

<div> <h1>${properties.title}</h1> <p>${properties.description}</p> </div>
Também adicionamos algum conteúdo para este componente para renderizar em
/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 esse conteúdo é acessado, o arquivo HTL é executado. No código HTL, usamos o objeto de contexto
properties
para acessar os recursos atuais
title
e exibi-los
description
. O HTML de saída será:

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

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

Adicionar uma classe de uso

O componente
info
na sua versão atual não precisa de uma classe use para executar sua função (muito simples). Há casos, no entanto, em que você precisa fazer coisas que não podem ser feitas em HTL e, portanto, você precisa de uma classe de uso. Mas lembre-se do seguinte:
Uma classe use só deve ser usada quando algo não pode ser feito somente em HTL.
Por exemplo, suponha que você deseja que o
info
componente exiba as
title
e
description
propriedades do recurso, mas tudo em minúsculas. Como o HTL não tem um método para sequências de caracteres em minúsculas, você precisará de uma classe de uso. Podemos fazer isso adicionando uma classe de uso Java e alterando a
info.html
seguinte maneira:

/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; } }
Nas seções a seguir, percorremos as diferentes partes do código.

Classe Java Local vs. Pacote

A classe de uso do Java pode ser instalada de duas formas:
local
ou
pacote
. Este exemplo usa uma instalação local.
Em uma instalação local, o arquivo de origem Java é colocado junto ao arquivo HTL, na mesma pasta do repositório. A fonte é compilada automaticamente sob demanda. Não é necessária nenhuma etapa separada de compilação ou embalagem.
Em uma instalação de pacote, a classe Java deve ser compilada e implantada em um pacote OSGi usando o mecanismo de implantação de conjunto AEM padrão (consulte Classe Classe Java embutida Java embutida).
Uma classe
​local de uso do Java é recomendada quando a classe de uso é específica para o componente em questão.
Uma classe
de uso do Java de
pacote é recomendada quando o código Java implementa um serviço que é acessado de vários componentes HTL.

O pacote Java é o caminho do repositório

Quando uma instalação local é usada, o nome do pacote da classe use deve corresponder ao do local da pasta do repositório, com todos os hífens no caminho substituídos pelos sublinhados no nome do pacote.
Nesse caso, o pacote
Info.java
está localizado em
/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 { ... }
Usar hífens nos nomes de itens do repositório é uma prática recomendada no desenvolvimento do AEM. No entanto, os hífens são ilegais nos nomes dos pacotes Java. Por esse motivo,
todos os hífens no caminho do repositório devem ser convertidos em sublinhados no nome
do pacote.

Extensão
WCMUsePojo

Embora haja várias maneiras de incorporar uma classe Java a HTL (consulte Alternativas para
WCMUsePojo
), o mais simples é estender a
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 ... }

Inicializando a classe

Quando a classe use é estendida de
WCMUsePojo
, a inicialização é realizada substituindo o
activate
método:

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

Contexto

Geralmente, o método ativate é usado para pré-calcular e armazenar (em variáveis de membro) os valores necessários no código HTL, com base no contexto atual (a solicitação atual e o recurso, por exemplo).
A
WCMUsePojo
classe fornece acesso ao mesmo conjunto de objetos de contexto que estão disponíveis em um arquivo HTL (consulte Objetos globais ).
Em uma classe que se estende, objetos de contexto podem ser acessados por nome usando
WCMUsePojo
Como alternativa, os objetos de contexto comumente usados podem ser acessados diretamente pelo método
de
conveniência apropriado:

Métodos Getter

Depois que a classe use for inicializada, o arquivo HTL será executado. Durante esse estágio, o HTL normalmente obtém o estado de várias variáveis membro da classe de uso e as renderiza para apresentação.
Para fornecer acesso a esses valores a partir do arquivo HTL, é necessário definir métodos getter personalizados na classe use, de acordo com a seguinte convenção de nomenclatura:
  • Um método do formulário
    getXyz
    exporá no arquivo HTL uma propriedade de objeto chamada
    xyz
    .
No exemplo a seguir, os métodos
getTitle
e
getDescription
resultam nas propriedades do objeto
title
e
description
tornam-se acessíveis no contexto do arquivo HTL:

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

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

atributo de uso inteligente de dados

O
data-sly-use
atributo é usado para inicializar a classe use dentro do código HTL. Em nosso exemplo, o
data-sly-use
atributo declara que queremos usar a classe
Info
. Podemos usar apenas o nome local da classe, pois estamos usando uma instalação local (uma vez que o arquivo de origem Java foi colocado na mesma pasta do arquivo HTL). Se estivéssemos usando uma instalação de conjunto, teríamos que especificar o nome de classe totalmente qualificado.

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

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

Identificador local

O identificador
info
(após o ponto em
data-sly-use.info
) é usado no arquivo HTL para identificar a classe. O escopo desse identificador é global dentro do arquivo, depois que ele é declarado. Não está limitado ao elemento que contém a
data-sly-use
declaração.

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

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

Obter propriedades

O identificador
info
é usado para acessar as propriedades do objeto
title
e
description
que foram expostas por meio dos métodos 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>

Saída

Agora, ao acessá-lo,
/content/my-example.html
ele retornará o seguinte HTML:

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

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

Além dos fundamentos

Nesta seção, apresentaremos outros recursos que vão além do exemplo simples acima:
  • Passando parâmetros para uma classe de uso.
  • Classe de uso do Java embutida.
  • Alternativas para
    WCMUsePojo

Passar parâmetros

Os parâmetros podem ser passados para uma classe use na inicialização. Por exemplo, nós poderíamos fazer algo assim:

/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>
Aqui estamos passando um parâmetro chamado
text
. Em seguida, a classe use maiúscula a string que recuperamos e exibe o resultado com
info.upperCaseText
. Esta é a classe de uso ajustada:

/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; } ... }
O parâmetro é acessado pelo
WCMUsePojo
método
<T> T get(String paramName, Class<T> type)
No nosso caso, a declaração:
get("text", String.class)
A string é então revertida e exposta pelo método:
getReverseText()

Enviar apenas parâmetros a partir de modelo de dados

Embora o exemplo acima esteja tecnicamente correto, não faz muito sentido passar um valor de HTL para inicializar uma classe use, quando o valor em questão está disponível no contexto de execução do código HTL (ou, trivialmente, o valor é estático, como acima).
O motivo é que a classe use sempre terá acesso ao mesmo contexto de execução que o código HTL. Isto traz à tona um ponto de importação das melhores práticas:
A transmissão de um parâmetro para uma classe use só deve ser feita quando a classe use for usada em um
data-sly-template
arquivo que ela mesma é chamado de outro arquivo HTL com parâmetros que precisam ser transmitidos.
Por exemplo, vamos criar um
data-sly-template
arquivo separado junto com nosso exemplo existente. Ligaremos para o novo arquivo
extra.html
. Ele contém um
data-sly-template
bloco chamado
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>
O modelo
extra
, usa um único parâmetro,
text
. Em seguida, inicializa a classe de uso do Java
ExtraHelper
com o nome local
extraHelper
e passa o valor do parâmetro template
text
como o parâmetro use-class
text
.
O corpo do modelo obtém a propriedade
extraHelper.reversedText
(que, sob o capô, realmente chama
ExtraHelper.getReversedText()
) e exibe esse valor.
Além disso, adaptamos nosso modelo existente
info.html
para usar esse novo modelo:

/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>
O arquivo
info.html
agora contém duas
data-sly-use
declarações, a original que importa a classe de uso do
Info
Java e uma nova que importa o arquivo de modelo sob o nome local
extra
.
Observe que podíamos ter colocado o bloco de modelo dentro do
info.html
arquivo para evitar o segundo
data-sly-use
, mas um arquivo de modelo separado é mais comum e mais reutilizável.
A
Info
classe é empregada como antes, chamando seus métodos getter
getLowerCaseTitle()
e
getLowerCaseDescription()
por meio de suas propriedades HTL
info.lowerCaseTitle
e
info.lowerCaseDescription
.
Em seguida, executamos um teste
data-sly-call
para o modelo
extra
e passamos o valor
properties.description
como parâmetro
text
.
A classe de uso do Java
Info.java
foi alterada para lidar com o novo parâmetro de texto:

/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; } }
O
text
parâmetro é recuperado com
get("text", String.class)
, o valor é revertido e disponibilizado como o objeto HTL
reversedText
por meio do getter
getReversedText()
.

Classe Java embutida

Com uma classe de uso de pacote, a classe deve ser compilada, empacotada e implantada no AEM usando o mecanismo de implantação de pacotes OSGi padrão. Em contraste com uma instalação local, a declaração
do
pacote use-class deve ser chamada 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, a
data-sly-use
declaração deve mencionar o nome da classe totalmente qualificada, em vez de apenas o nome da classe local:

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

Alternativas para
WCMUsePojo

A maneira mais comum de criar uma classe de uso Java é estender
WCMUsePojo
. No entanto, existem várias outras opções. Para entender essas variantes, é útil entender como a
data-sly-use
declaração HTL funciona sob o capô.
Suponha que você tenha a seguinte
data-sly-use
afirmação:
<div data-sly-use.
localName
="
UseClass
">
O sistema processa a declaração da seguinte maneira:
(1)
  • Se houver um arquivo local
    UseClass.java
    no mesmo diretório do arquivo HTL, tente compilar e carregar essa classe. Se tiver êxito, vá para (2).
  • Caso contrário, interprete
    UseClass
    como um nome de classe totalmente qualificado e tente carregá-lo do ambiente OSGi. Se tiver êxito, vá para (2).
  • Caso contrário, interprete
    UseClass
    como um caminho para um arquivo HTL ou JavaScript e carregue esse arquivo. Se o goto for bem-sucedido (4).
(2)
  • Tente adaptar a corrente
    Resource
    à
    UseClass
    . Se tiver êxito, vá para (3).
  • Caso contrário, tente adaptar a corrente
    Request
    para
    UseClass
    . Se tiver êxito, vá para (3).
  • Caso contrário, tente instanciar
    UseClass
    com um construtor de argumento zero. Se tiver êxito, vá para (3).
(3)
  • Em HTL, vincule o objeto recém-adaptado ou criado ao nome
    localName
    .
  • Se
    UseClass
    implementa
    io.sightly.java.api.Use
    então chama o
    init
    método, transmitindo o contexto de execução atual (na forma de um
    javax.scripting.Bindings
    objeto).
(4)
  • Se
    UseClass
    for um caminho para um arquivo HTL contendo um
    data-sly-template
    , prepare o modelo.
  • Caso contrário, se
    UseClass
    for um caminho para uma classe de uso do JavaScript, prepare a classe de uso (consulte JavaScript Use-API ).
Alguns pontos importantes sobre a descrição acima:
  • Qualquer classe que seja adaptável, adaptável
    Resource``Request
    ou que tenha um construtor de argumento zero pode ser uma classe use. A classe não precisa estender
    WCMUsePojo
    ou nem mesmo implementar
    Use
    .
  • No entanto, se a classe use
    não
    implementar
    Use
    , seu
    init
    método será chamado automaticamente com o contexto atual, permitindo que você coloque o código de inicialização lá que dependa desse contexto.
  • Uma classe de uso que se estende
    WCMUsePojo
    é apenas um caso especial de implementação
    Use
    . Ele fornece os métodos de contexto de conveniência e seu
    activate
    método é chamado automaticamente de
    Use.init
    .

Implementação direta do uso da interface

Embora a maneira mais comum de criar uma classe de uso seja estender
WCMUsePojo
, também é possível implementar diretamente a própria
io.sightly.java.api.Use
interface.
A
Use
interface define apenas um método:
O
init
método será chamado na inicialização da classe com um
Bindings
objeto que armazena todos os objetos de contexto e quaisquer parâmetros transmitidos para a classe use.
Toda funcionalidade adicional (como o equivalente de
WCMUsePojo.getProperties()
) deve ser implementada explicitamente usando o
javax.script.Bindings
objeto. Por exemplo:

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"); } ... }
O caso principal para implementar a
Use
interface em vez de estender
WCMUsePojo
é quando você deseja usar uma subclasse de uma classe já existente como a classe use.

Adaptável a partir do recurso

Outra opção é usar uma classe auxiliar adaptável
org.apache.sling.api.resource.Resource
.
Digamos que você precise gravar um script HTL que exiba o tipo de mimepe de um ativo DAM. Nesse caso, você sabe que quando seu script HTL for chamado, ele estará dentro do contexto de um
Resource
que envolve um JCR
Node
com um tipo de nó
dam:Asset
.
Você sabe que um
dam:Asset
nó tem uma estrutura como esta:

Estrutura do repositório

{ "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": { ... } } } } } } } }
Aqui, mostramos o ativo (uma imagem JPEG) que vem com uma instalação padrão do AEM como parte do exemplo geometrixx do projeto. O ativo é chamado
jane_doe.jpg
e seu tipo mimético é
image/jpeg
.
Para acessar o ativo de dentro do HTL, você pode declarar
com.day.cq.dam.api.Asset
como a classe na instrução
data-sly-use
e, em seguida, usar um método get de
Asset
para recuperar as informações desejadas. Por exemplo:

mimetype.html

<div data-sly-use.asset="com.day.cq.dam.api.Asset"> <p>${asset.mimeType}</p> </div>
A
data-sly-use
declaração direciona o HTL para adaptar o atual
Resource
a um
Asset
e dar-lhe o nome local
asset
. Em seguida, ele chama o
getMimeType
método de
Asset
uso do comando HTL getter shorthand:
asset.mimeType
.

Adaptável a partir da solicitação

Também é possível usar como classe de uso qualquer classe que seja adaptável de
org.apache.sling.api.SlingHttpServletRequest
Como no caso acima de um adaptador de classe de uso de
Resource
, um adaptador de classe de uso de
SlingHttpServletRequest
pode ser especificado na
data-sly-use
declaração. Após a execução, a solicitação atual será adaptada à classe fornecida e o objeto resultante será disponibilizado dentro de HTL.