Tapeçaria Apache - Componentes
Conforme discutido anteriormente, Componentes e Páginas são iguais, exceto que a Página é o componente raiz e inclui um ou mais componentes filhos. Os componentes sempre residem dentro de uma página e fazem quase todas as funcionalidades dinâmicas da página.
Os componentes Tapestry renderizam links HTML simples para funcionalidades de grade complexas com interactive AJAX. Um componente também pode incluir outro componente. Os componentes da tapeçaria consistem nos seguintes itens -
Component Class - A principal classe Java do componente.
XML Template- O modelo XML é semelhante ao modelo da página. A classe do componente renderiza o modelo como a saída final. Alguns componentes podem não ter modelos. Neste caso, a saída será gerada pela própria classe do componente usando oMarkupWriter classe.
Body- O componente especificado dentro do modelo de página pode ter marcação personalizada e é denominado “Corpo do componente”. Se o modelo de componente tiver<body />elemento, o elemento <body /> será substituído pelo corpo do componente. Isso é semelhante ao layout discutido anteriormente na seção de modelo XML.
Rendering - Renderização é um processo que transforma o modelo XML e o corpo do componente na saída real do componente.
Parameters - Usado para criar comunicação entre componentes e páginas e, assim, passar dados entre eles.
Events- Delega funcionalidade de componentes para seu contêiner / pai (páginas ou outro componente). É amplamente utilizado no propósito de navegação de página.
Renderização
A renderização de um componente é feita em uma série de fases predefinidas. Cada fase no sistema de componente deve ter um método correspondente definido por convenção ou anotação na classe de componente.
// Using annotaion
@SetupRender
void initializeValues() {
// initialize values
}
// using convention
boolean afterRender() {
// do logic
return true;
}
As fases, seu nome de método e suas anotações estão listados abaixo.
Anotação | Nomes de métodos padrão |
---|---|
@SetupRender | setupRender () |
@BeginRender | beginRender () |
@BeforeRenderTemplate | beforeRenderTemplate () |
@BeforeRenderBody | beforeRenderBody () |
@AfterRenderBody | afterRenderBody () |
@AfterRenderTemplate | afterRenderTemplate () |
@AfterRender | afterRender () |
@CleanupRender | cleanupRender () |
Cada fase tem uma finalidade específica e são as seguintes -
SetupRender
SetupRender inicia o processo de renderização. Geralmente configura os parâmetros do componente.
BeginRender
BeginRender começa a renderizar o componente. Geralmente renderiza a tag de início / início do componente.
BeforeRenderTemplate
BeforeRenderTemplate é usado para decorar o modelo XML, adicionando marcação especial ao redor do modelo. Ele também fornece uma opção para pular a renderização do modelo.
BeforeRenderBody
BeforeRenderTemplate fornece uma opção para pular a renderização do elemento do corpo do componente.
AfterRenderBody
AfterRenderBody será chamado depois que o corpo do componente for renderizado.
AfterRenderTemplate
AfterRenderTemplate será chamado depois que o modelo do componente for renderizado.
AfterRender
AfterRender é a contraparte do BeginRender e geralmente renderiza a tag de fechamento.
CleanupRender
CleanupRender é a contraparte do SetupRender. Ele libera / descarta todos os objetos criados durante o processo de renderização.
O fluxo das fases de renderização não é apenas para frente. Ele vai e volta entre as fases, dependendo do valor de retorno de uma fase.
Por exemplo, se o método SetupRender retornar falso, a renderização vai para a fase CleanupRender e vice-versa. Para encontrar uma compreensão clara do fluxo entre as diferentes fases, verifique o fluxo no diagrama abaixo.
Componente Simples
Vamos criar um componente simples, Hello, que terá a mensagem de saída “Hello, Tapestry”. A seguir está o código do componente Hello e seu modelo.
package com.example.MyFirstApplication.components;
public class Hello {
}
<html
xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p = "tapestry:parameter">
<div>
<p>Hello, Tapestry (from component).</p>
</div>
</html>
O componente Hello pode ser chamado em um modelo de página como -
<html title = "Hello component test page"
xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p = "tapestry:parameter">
<t:hello />
</html>
Da mesma forma, o componente pode renderizar a mesma saída usando MarkupWriter em vez do modelo mostrado abaixo.
package com.example.MyFirstApplication.components;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.annotations.BeginRender;
public class Hello {
@BeginRender
void renderMessage(MarkupWriter writer) {
writer.write("<p>Hello, Tapestry (from component)</p>");
}
}
Vamos mudar o template do componente e incluir o elemento <body /> como mostrado no bloco de código abaixo.
<html>
xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p = "tapestry:parameter">
<div>
<t:body />
</div>
</html>
Agora, o modelo de página pode incluir corpo na marcação do componente, conforme mostrado abaixo.
<html title = "Hello component test page"
xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p = "tapestry:parameter">
<t:hello>
<p>Hello, Tapestry (from page).</p>
</t:hello>
</html>
O resultado será o seguinte -
<html>
<div>
<p>Hello, Tapestry (from page).</p>
</div>
</html>
Parâmetros
O objetivo principal desses parâmetros é criar uma conexão entre um campo do componente e uma propriedade / recurso da página. Usando parâmetros, o componente e sua página correspondente comunicam e transferem dados entre si. Isso é chamadoTwo Way Data Binding.
Por exemplo, um componente de caixa de texto usado para representar a idade em uma página de gerenciamento de usuário obtém seu valor inicial (disponível no banco de dados) por meio do parâmetro. Novamente, depois que a idade do usuário for atualizada e enviada de volta, o componente enviará de volta a idade atualizada por meio do mesmo parâmetro.
Para criar um novo parâmetro na classe do componente, declare um campo e especifique um @Parameteranotação. Este @Parameter tem dois argumentos opcionais, que são -
required- torna o parâmetro obrigatório. A tapeçaria gera uma exceção se não for fornecida.
value - especifica o valor padrão do parâmetro.
O parâmetro deve ser especificado no modelo de página como atributos da tag do componente. O valor dos atributos deve ser especificado usando Binding Expression / Expansion, que discutimos nos capítulos anteriores. Algumas das expansões que aprendemos anteriormente são -
Property expansion (prop:«val») - Obtenha os dados da propriedade da classe da página.
Message expansion (message:«val») - Obtenha os dados da chave definida no arquivo index.properties.
Context expansion (context:«val») - Obtenha os dados da pasta de contexto da web / src / main / webapp.
Asset expansion (asset:«val») - Obtenha os dados dos recursos incorporados no arquivo jar, / META-INF / assets.
Symbol expansion (symbol:«val») - Obtenha os dados dos símbolos definidos em AppModule.javafile.
A tapeçaria tem muitas expansões mais úteis, algumas das quais são fornecidas abaixo -
Literal expansion (literal:«val») - Uma string literal.
Var expansion (var:«val») - Permite que uma variável renderizada do componente seja lida ou atualizada.
Validate expansion (validate:«val»)- Uma string especializada usada para especificar a regra de validação de um objeto. Por exemplo, valide: obrigatório, minLength = 5.
Translate (translate:«val») - Usado para especificar a classe Conversor (conversão da representação do lado do cliente em representação do lado do servidor) na validação de entrada.
Block (block:«val») - O id do elemento de bloco dentro do modelo.
Component (component:«val») - O id de outro componente no modelo.
Todas as expansões acima são somente leitura, exceto expansão de propriedade e expansão de Var. Eles são usados pelo componente para trocar dados com a página. Ao usar a expansão como valores de atributo,${...}não deve ser usado. Em vez disso, use a expansão sem os símbolos de dólar e colchetes.
Componente Usando Parâmetro
Vamos criar um novo componente, HelloWithParameter, modificando o componente Hello para renderizar dinamicamente a mensagem adicionando um name parâmetro na classe de componente e alterando o modelo de componente e modelo de página de acordo.
Crie uma nova classe de componente HelloWithParameter.java.
Adicione um campo privado e nomeie-o com o @Parameteranotação. Use o argumento necessário para torná-lo obrigatório.
@Parameter(required = true)
private String name;
Adicione um campo privado, o resultado com @Properyanotação. A propriedade do resultado será usada no modelo do componente. O modelo de componente não tem acesso aos campos anotados com@Parameter e só pode acessar os campos anotados com @Property. As variáveis disponíveis nos modelos de componentes são chamadas de variáveis de renderização.
@Property
private String result;
Adicione um método RenderBody e copie o valor do parâmetro name para a propriedade result.
@BeginRender
void initializeValues() {
result = name;
}
Adicionar um novo modelo de componente HelloWithParamter.tml e use a propriedade result para renderizar a mensagem.
<div> Hello, ${result} </div>
Adicione uma nova propriedade, Nome de usuário na página de teste (testhello.java).
public String getUsername() {
return "User1";
}
Use o componente recém-criado no modelo de página e defina a propriedade Username no parâmetro name de HelloWithParameter componente.
<t:helloWithParameter name = "username" />
A lista completa é a seguinte -
package com.example.MyFirstApplication.components;
import org.apache.tapestry5.annotations.*;
public class HelloWithParameter {
@Parameter(required = true)
private String name;
@Property
private String result;
@BeginRender
void initializeValues() {
result = name;
}
}
<html
xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p = "tapestry:parameter">
<div> Hello, ${result} </div>
</html>
package com.example.MyFirstApplication.pages;
import org.apache.tapestry5.annotations.*;
public class TestHello {
public String getUsername() {
return "User1";
}
}
<html title = "Hello component test page"
xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p = "tapestry:parameter">
<t:helloWithParameter name = "username" />
</html>
O resultado será o seguinte -
<div> Hello, User1 </div>
Parâmetro Avançado
Nos capítulos anteriores, analisamos como criar e usar um parâmetro simples em um componente personalizado. Um parâmetro avançado também pode conter marcação completa. Nesse caso, a marcação deve ser especificada dentro da tag do componente, como a subseção no modelo de página. O componente if embutido tem marcação para condição de sucesso e falha. A marcação de sucesso é especificada como o corpo da tag do componente e a marcação de falha é especificada usando umelseparameter.
Vamos ver como usar o ifcomponente. O componente if tem dois parâmetros -
test - Parâmetro baseado em propriedade simples.
Else - Parâmetro avançado usado para especificar marcação alternativa, se a condição falhar
Tapestry verificará o valor da propriedade de teste usando a seguinte lógica e retornará verdadeiro ou falso. Isso é chamadoType Coercion, uma maneira de converter um objeto de um tipo em outro com o mesmo conteúdo.
Se o tipo de dados for String, “True” se não estiver em branco e não for a string literal “False” (não diferencia maiúsculas de minúsculas).
Se o tipo de dados for Number, Verdadeiro se diferente de zero.
Se o tipo de dados for Collection, Verdadeiro se não estiver vazio.
Se o tipo de dados for Object, True (desde que não seja nulo).
Se a condição for aprovada, o componente renderizará seu corpo; caso contrário, ele renderiza o corpo do parâmetro else.
A lista completa é a seguinte -
package com.example.MyFirstApplication.pages;
public class TestIf {
public String getUser() {
return "User1";
}
}
<html title = "If Test Page"
xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p = "tapestry:parameter">
<body>
<h1>Welcome!</h1>
<t:if test = "user">
Welcome back, ${user}
<p:else>
Please <t:pagelink page = "login">Login</t:pagelink>
</p:else>
</t:if>
</body>
</html>
Eventos de componente / navegação de página
O aplicativo Tapestry é um collection of Pagesinteragindo uns com os outros. Até agora, aprendemos como criar páginas individuais sem qualquer comunicação entre elas. O objetivo principal de um evento de componente é fornecer interação entre as páginas (dentro das páginas também) usando eventos do lado do servidor. A maioria dos eventos de componentes se origina de eventos do lado do cliente.
Por exemplo, quando um usuário clica em um link em uma página, Tapestry chama a própria página com informações de destino em vez de chamar a página de destino e gera um evento do lado do servidor. A página de tapeçaria irá capturar o evento, processar as informações de destino e fazer um redirecionamento do lado do servidor para a página de destino.
A tapeçaria segue um Post/Redirect/Get (RPG) design patternpara navegação na página. No RPG, quando um usuário faz uma solicitação de postagem enviando um formulário, o servidor processa os dados postados, mas não retorna a resposta diretamente. Em vez disso, ele fará um redirecionamento do lado do cliente para outra página, que produzirá o resultado. Um padrão RPG é usado para evitar envios de formulários duplicados por meio do botão Voltar do navegador, botão de atualização do navegador, etc., Tapestry fornece um padrão RPG fornecendo os dois tipos de solicitação a seguir.
Component Event Request- Esse tipo de solicitação tem como alvo um componente específico em uma página e gera eventos dentro do componente. Essa solicitação faz apenas um redirecionamento e não produz a resposta.
Render Request - Esses tipos de solicitações direcionam uma página e transmitem a resposta de volta para o cliente.
Para entender os eventos do componente e a navegação da página, precisamos saber o padrão de URL da solicitação de tapeçaria. O padrão de URL para ambos os tipos de solicitação é o seguinte -
Component Event Requests -
/<<page_name_with_path>>.<<component_id|event_id>>/<<context_information>>
Render Request -
/<<page_name_with_path>>/<<context_information>>
Alguns dos exemplos de padrões de URL são -
A página de índice pode ser solicitada por https://«domain»/«app»/index.
Se a página de índice estiver disponível em uma subpasta admin, ela pode ser solicitada por https://«domain»/«app»/admin/index.
Se o usuário clicar no ActionLink component com id test na página de índice, o URL será https://«domain»/«app»/index.test.
Eventos
Por padrão, Tapestry aumenta OnPassivate e OnActivateeventos para todos os pedidos. Para o tipo de solicitação de evento de componente, a tapeçaria gera um ou mais eventos adicionais, dependendo do componente. O componente ActionLink gera um evento Action, enquanto um componente Form gera vários eventos, comoValidate, Success, etc.,
Os eventos podem ser manipulados na classe de página usando o manipulador de método correspondente. O manipulador de método é criado por meio de uma convenção de nomenclatura de método ou por meio do@OnEventanotação. O formato da convenção de nomenclatura do método éOn«EventName»From«ComponentId».
Um evento de ação do componente ActionLink com id test pode ser tratado por um dos seguintes métodos -
void OnActionFromTest() {
}
@OnEvent(component = "test", name = "action")
void CustomFunctionName() {
}
Se o nome do método não tiver nenhum componente específico, o método será chamado para todos os componentes com eventos correspondentes.
void OnAction() {
}
OnPassivate e OnActivate Event
OnPassivate é usado para fornecer informações de contexto para um manipulador de eventos OnActivate. Em geral, Tapestry fornece as informações de contexto e pode ser usado como um argumento no manipulador OnActivateevent.
Por exemplo, se as informações de contexto forem 3 do tipo int, o evento OnActivate pode ser chamado de -
void OnActivate(int id) {
}
Em alguns cenários, as informações de contexto podem não estar disponíveis. Nessa situação, podemos fornecer as informações de contexto ao manipulador de eventos OnActivate por meio do manipulador de eventos OnPassivate. O tipo de retorno do manipulador de eventos OnPassivate deve ser usado como argumento do manipulador de eventos OnActivate.
int OnPassivate() {
int id = 3;
return id;
}
void OnActivate(int id) {
}
Valores de retorno do manipulador de eventos
A tapeçaria emite o redirecionamento da página com base nos valores de retorno do manipulador de eventos. O manipulador de eventos deve retornar qualquer um dos seguintes valores.
Null Response- Retorna um valor nulo. Tapestry construirá o URL da página atual e enviará ao cliente como redirecionamento.
public Object onAction() {
return null;
}
String Response- Retorna o valor da string. Tapestry construirá a URL da página que corresponde ao valor e enviará ao cliente como redirecionamento.
public String onAction() {
return "Index";
}
Class Response- Retorna uma classe de página. Tapestry construirá o URL da classe de página retornada e enviará ao cliente como redirecionamento.
public Object onAction() {
return Index.class
}
Page Response- Retorna um campo anotado com @InjectPage. Tapestry construirá o URL da página injetada e enviará ao cliente como redirecionamento.
@InjectPage
private Index index;
public Object onAction(){
return index;
}
HttpError- Retorna o objeto HTTPError. Tapestry emitirá um erro HTTP do lado do cliente.
public Object onAction(){
return new HttpError(302, "The Error message);
}
Link Response- Retorna uma instância de link diretamente. Tapestry construirá a URL do objeto Link e enviará ao cliente como redirecionamento.
Stream Response - Retorna o StreamResponseobjeto. Tapestry enviará o stream como resposta diretamente ao navegador do cliente. É utilizado para gerar relatórios e imagens diretamente e enviar para o cliente.
Url Response - Retorna o java.net.URLobjeto. Tapestry obterá o URL correspondente do objeto e enviará ao cliente como redirecionamento.
Object Response- Retorna qualquer valor diferente dos valores especificados acima. A tapeçaria gerará um erro.
Contexto do Evento
Em geral, o manipulador de eventos pode obter as informações de contexto usando argumentos. Por exemplo, se as informações de contexto forem 3 do tipo int, o manipulador de eventos será -
Object onActionFromTest(int id) {
}
Tapestry trata adequadamente as informações de contexto e as fornece aos métodos por meio de argumentos. Às vezes, Tapestry pode não ser capaz de lidar com isso corretamente devido à complexidade da programação. Nesse momento, podemos obter as informações de contexto completas e processar nós mesmos.
Object onActionFromEdit(EventContext context) {
if (context.getCount() > 0) {
this.selectedId = context.get(0);
} else {
alertManager.warn("Please select a document.");
return null;
}
}