Apache Tapestry - Componenti

Come discusso in precedenza, i componenti e le pagine sono gli stessi tranne per il fatto che la pagina è il componente principale e include uno o più componenti figlio. I componenti risiedono sempre all'interno di una pagina e svolgono quasi tutte le funzionalità dinamiche della pagina.

I componenti Tapestry rendono semplici collegamenti HTML a complesse funzionalità di griglia con interactive AJAX. Un componente può includere anche un altro componente. I componenti dell'arazzo sono costituiti dai seguenti elementi:

  • Component Class - La principale classe Java del componente.

  • XML Template- Il modello XML è simile al modello di pagina. La classe component esegue il rendering del modello come output finale. Alcuni componenti potrebbero non avere modelli. In questo caso, l'output verrà generato dalla classe del componente stessa utilizzando il fileMarkupWriter classe.

  • Body- Il componente specificato all'interno del modello di pagina può avere markup personalizzato e si chiama "Component body". Se il modello del componente ha<body />elemento, quindi l'elemento <body /> verrà sostituito dal corpo del componente. Questo è simile al layout discusso in precedenza nella sezione del modello XML.

  • Rendering - Il rendering è un processo che trasforma il modello XML e il corpo del componente nell'output effettivo del componente.

  • Parameters - Utilizzato per creare comunicazioni tra componenti e pagine e quindi trasferire dati tra di loro.

  • Events- Delega la funzionalità dai componenti al relativo contenitore / padre (pagine o un altro componente). È ampiamente utilizzato a scopo di navigazione della pagina.

Rendering

Il rendering di un componente viene eseguito in una serie di fasi predefinite. Ogni fase nel sistema dei componenti dovrebbe avere un metodo corrispondente definito per convenzione o annotazione nella classe del componente.

// Using annotaion 
@SetupRender 
void initializeValues() { 
   // initialize values 
}

// using convention 
boolean afterRender() { 
   // do logic 
   return true; 
}

Di seguito sono elencate le fasi, il nome del metodo e le annotazioni.

Annotazione Nomi dei metodi predefiniti
@SetupRender setupRender ()
@BeginRender beginRender ()
@BeforeRenderTemplate beforeRenderTemplate ()
@BeforeRenderBody beforeRenderBody ()
@AfterRenderBody afterRenderBody ()
@AfterRenderTemplate afterRenderTemplate ()
@AfterRender afterRender ()
@CleanupRender cleanupRender ()

Ogni fase ha uno scopo specifico e sono le seguenti:

SetupRender

SetupRender avvia il processo di rendering. Di solito imposta i parametri del componente.

BeginRender

BeginRender avvia il rendering del componente. Di solito esegue il rendering del tag di inizio / inizio del componente.

BeforeRenderTemplate

BeforeRenderTemplate viene utilizzato per decorare il modello XML, aggiungendo un markup speciale attorno al modello. Fornisce anche un'opzione per saltare il rendering del modello.

BeforeRenderBody

BeforeRenderTemplate fornisce un'opzione per saltare il rendering dell'elemento del corpo del componente.

AfterRenderBody

AfterRenderBody verrà chiamato dopo il rendering del corpo del componente.

AfterRenderTemplate

AfterRenderTemplate verrà chiamato dopo il rendering del modello del componente.

AfterRender

AfterRender è la controparte di BeginRender e solitamente esegue il rendering del tag di chiusura.

CleanupRender

CleanupRender è la controparte di SetupRender. Rilascia / elimina tutti gli oggetti creati durante il processo di rendering.

Il flusso delle fasi di rendering non è solo in avanti. Va avanti e indietro tra le fasi a seconda del valore di ritorno di una fase.

Ad esempio, se il metodo SetupRender restituisce false, il rendering passa alla fase CleanupRender e viceversa. Per trovare una chiara comprensione del flusso tra le diverse fasi, controllare il flusso nel diagramma riportato di seguito.

Componente semplice

Creiamo un semplice componente, Hello, che avrà il messaggio di output "Hello, Tapestry". Di seguito è riportato il codice del componente Hello e il relativo modello.

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>

Il componente Hello può essere chiamato in un modello di pagina come:

<html title = "Hello component test page" 
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
<t:hello />  
</html>

Allo stesso modo, il componente può eseguire il rendering dello stesso output utilizzando MarkupWriter invece del modello come mostrato di seguito.

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

Cambiamo il modello del componente e includiamo l'elemento <body /> come mostrato nel blocco di codice seguente.

<html>  
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   
   <div> 
      <t:body /> 
   </div> 
</html>

Ora, il modello di pagina può includere il corpo nel markup del componente come mostrato di seguito.

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

L'output sarà il seguente:

<html> 
   <div> 
      <p>Hello, Tapestry (from page).</p> 
   </div> 
</html>

Parametri

Lo scopo principale di questi parametri è creare una connessione tra un campo del componente e una proprietà / risorsa della pagina. Utilizzando i parametri, il componente e la pagina corrispondente comunicano e trasferiscono i dati tra loro. Questo è chiamatoTwo Way Data Binding.

Ad esempio, un componente casella di testo utilizzato per rappresentare l'età in una pagina di gestione utenti ottiene il suo valore iniziale (disponibile nel database) tramite il parametro. Ancora una volta, dopo che l'età dell'utente è stata aggiornata e reinviata, il componente invierà indietro l'età aggiornata tramite lo stesso parametro.

Per creare un nuovo parametro nella classe del componente, dichiarare un campo e specificare un file @Parameterannotazione. Questo @Parameter ha due argomenti opzionali, che sono:

  • required- rende il parametro obbligatorio. Tapestry solleva un'eccezione se non viene fornita.

  • value - specifica il valore predefinito del parametro.

Il parametro deve essere specificato nel modello di pagina come attributi del tag del componente. Il valore degli attributi dovrebbe essere specificato usando Binding Expression / Expansion, che abbiamo discusso nei capitoli precedenti. Alcune delle espansioni che abbiamo appreso in precedenza sono:

  • Property expansion (prop:«val») - Ottieni i dati dalla proprietà della classe della pagina.

  • Message expansion (message:«val») - Ottieni i dati dalla chiave definita nel file index.properties.

  • Context expansion (context:«val») - Ottieni i dati dalla cartella del contesto web / src / main / webapp.

  • Asset expansion (asset:«val») - Ottieni i dati dalle risorse incorporate nel file jar, / META-INF / assets.

  • Symbol expansion (symbol:«val») - Ottieni i dati dai simboli definiti in AppModule.javafile.

Tapestry ha molte altre utili espansioni, alcune delle quali sono fornite di seguito:

  • Literal expansion (literal:«val») - Una stringa letterale.

  • Var expansion (var:«val») - Consenti la lettura o l'aggiornamento di una variabile di rendering del componente.

  • Validate expansion (validate:«val»)- Una stringa specializzata utilizzata per specificare la regola di convalida di un oggetto. Ad esempio, validate: required, minLength = 5.

  • Translate (translate:«val») - Utilizzato per specificare la classe Translator (conversione della rappresentazione lato client in lato server) nella convalida dell'input.

  • Block (block:«val») - L'id dell'elemento di blocco all'interno del modello.

  • Component (component:«val») - L'id dell'altro componente all'interno del modello.

Tutte le espansioni di cui sopra sono di sola lettura tranne l'espansione della proprietà e l'espansione Var. Sono utilizzati dal componente per scambiare dati con la pagina. Quando si utilizza l'espansione come valori di attributo,${...}non dovrebbe essere utilizzato. Utilizza invece l'espansione senza simboli di dollaro e parentesi graffe.

Componente che utilizza il parametro

Creiamo un nuovo componente, HelloWithParameter, modificando il componente Hello per eseguire il rendering dinamico del messaggio aggiungendo un name parametro nella classe del componente e modificando di conseguenza il modello del componente e il modello di pagina.

  • Crea una nuova classe di componenti HelloWithParameter.java.

  • Aggiungi un campo privato e assegnagli un nome con @Parameterannotazione. Usa l'argomento richiesto per renderlo obbligatorio.

@Parameter(required = true) 
private String name;
  • Aggiungi un campo privato, risultato con @Properyannotazione. La proprietà del risultato verrà utilizzata nel modello del componente. Il modello del componente non ha accesso ai campi annotati con@Parameter e solo in grado di accedere ai campi annotati con @Property. Le variabili disponibili nei modelli dei componenti sono chiamate Variabili di rendering.

@Property 
 private String result;
  • Aggiungi un metodo RenderBody e copia il valore dal parametro name alla proprietà result.

@BeginRender 
void initializeValues() { 
   result = name; 
}
  • Aggiungi un nuovo modello di componente HelloWithParamter.tml e utilizzare la proprietà result per eseguire il rendering del messaggio.

<div> Hello, ${result} </div>
  • Aggiungi una nuova proprietà, nome utente nella pagina di test (testhello.java).

public String getUsername() { 
   return "User1"; 
}
  • Utilizza il componente appena creato nel modello di pagina e imposta la proprietà Username nel parametro name di HelloWithParameter componente.

<t:helloWithParameter name = "username" />

L'elenco completo è il seguente:

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>

Il risultato sarà il seguente:

<div> Hello, User1 </div>

Parametro avanzato

Nei capitoli precedenti abbiamo analizzato come creare e utilizzare un semplice parametro in un componente personalizzato. Un parametro avanzato può contenere anche markup completo. In questo caso, il markup dovrebbe essere specificato all'interno del tag del componente come la sottosezione nel modello di pagina. Il componente if integrato ha markup sia per la condizione di successo che per quella di errore. Il markup per il successo viene specificato come corpo del tag del componente e il markup per il fallimento viene specificato utilizzando unelseparameter.

Vediamo come utilizzare il file ifcomponente. Il componente if ha due parametri:

  • test - Parametro basato sulla proprietà semplice.

  • Else - Parametro avanzato utilizzato per specificare markup alternativo, se la condizione non riesce

Tapestry controllerà il valore della proprietà di test utilizzando la seguente logica e restituirà vero o falso. Questo è chiamatoType Coercion, un modo per convertire un oggetto di un tipo in un altro tipo con lo stesso contenuto.

  • Se il tipo di dati è String, "True" se non è vuoto e non la stringa letterale "False" (senza distinzione tra maiuscole e minuscole).

  • Se il tipo di dati è Number, Vero se diverso da zero.

  • Se il tipo di dati è Collection, True se non è vuoto.

  • Se il tipo di dati è Object, True (purché non sia nullo).

Se la condizione passa, il componente esegue il rendering del suo corpo; in caso contrario, esegue il rendering del corpo del parametro else.

L'elenco completo è il seguente:

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>

Eventi componenti / Navigazione pagine

L'applicazione Tapestry è un file collection of Pagesinteragendo tra loro. Fino ad ora, abbiamo imparato a creare singole pagine senza alcuna comunicazione tra di loro. Lo scopo principale di un evento Component è fornire l'interazione tra le pagine (anche all'interno delle pagine) utilizzando eventi lato server. La maggior parte degli eventi dei componenti ha origine da eventi lato client.

Ad esempio, quando un utente fa clic su un collegamento in una pagina, Tapestry chiamerà la stessa pagina con le informazioni di destinazione invece di chiamare la pagina di destinazione e genererà un evento lato server. La pagina Tapestry acquisirà l'evento, elaborerà le informazioni sul target ed eseguirà un reindirizzamento lato server alla pagina target.

Tapestry segue a Post/Redirect/Get (RPG) design patternper la navigazione nelle pagine. In RPG, quando un utente effettua una richiesta di post inviando un modulo, il server elaborerà i dati pubblicati, ma non restituirà direttamente la risposta. Invece, eseguirà un reindirizzamento lato client a un'altra pagina, che produrrà il risultato. Un pattern RPG viene utilizzato per impedire l'invio di moduli duplicati tramite il pulsante Indietro del browser, il pulsante di aggiornamento del browser, ecc., Tapestry fornisce un pattern RPG fornendo i seguenti due tipi di richiesta.

  • Component Event Request- Questo tipo di richiesta ha come target un particolare componente in una pagina e genera eventi all'interno del componente. Questa richiesta esegue solo un reindirizzamento e non restituisce la risposta.

  • Render Request - Questi tipi di richieste prendono di mira una pagina e trasmettono la risposta al client.

Per comprendere gli eventi dei componenti e la navigazione tra le pagine, dobbiamo conoscere il pattern URL della richiesta di arazzo. Il pattern URL per entrambi i tipi di richiesta è il seguente:

  • Component Event Requests -

/<<page_name_with_path>>.<<component_id|event_id>>/<<context_information>>
  • Render Request -

/<<page_name_with_path>>/<<context_information>>

Alcuni degli esempi di pattern URL sono:

  • La pagina dell'indice può essere richiesta da https://«domain»/«app»/index.

  • Se la pagina Indice è disponibile in una sottocartella admin, può essere richiesta da https://«domain»/«app»/admin/index.

  • Se l'utente fa clic sul file ActionLink component con id test nella pagina dell'indice, l'URL sarà https://«domain»/«app»/index.test.

Eventi

Per impostazione predefinita, Tapestry si solleva OnPassivate e OnActivateeventi per tutte le richieste. Per il tipo di richiesta di evento Component, tapestry genera uno o più eventi aggiuntivi a seconda del componente. Il componente ActionLink genera un evento Action, mentre un componente Form genera più eventi comeValidate, Success, eccetera.,

Gli eventi possono essere gestiti nella classe della pagina utilizzando il gestore del metodo corrispondente. Il gestore del metodo viene creato tramite una convenzione di denominazione del metodo o tramite@OnEventannotazione. Il formato della convenzione di denominazione del metodo èOn«EventName»From«ComponentId».

Un evento di azione del componente ActionLink con id test può essere gestito con uno dei seguenti metodi:

void OnActionFromTest() { 
}  
@OnEvent(component = "test", name = "action") 
void CustomFunctionName() { 
}

Se il nome del metodo non ha alcun componente particolare, il metodo verrà chiamato per tutti i componenti con eventi corrispondenti.

void OnAction() { 
}

Evento OnPassivate e OnActivate

OnPassivate viene utilizzato per fornire informazioni di contesto per un gestore di eventi OnActivate. In generale, Tapestry fornisce le informazioni di contesto e può essere utilizzato come argomento nel gestore di eventi OnActivate.

Ad esempio, se le informazioni di contesto sono 3 di tipo int, l'evento OnActivate può essere chiamato come:

void OnActivate(int id) { 
}

In alcuni scenari, le informazioni di contesto potrebbero non essere disponibili. In questa situazione, possiamo fornire le informazioni di contesto al gestore di eventi OnActivate tramite il gestore di eventi OnPassivate. Il tipo restituito del gestore di eventi OnPassivate deve essere utilizzato come argomento del gestore di eventi OnActivate.

int OnPassivate() { 
   int id = 3; 
   return id; 
} 
void OnActivate(int id) { 
}

Valori restituiti dal gestore eventi

Tapestry emette il reindirizzamento della pagina in base ai valori di ritorno del gestore di eventi. Il gestore di eventi dovrebbe restituire uno dei seguenti valori.

  • Null Response- Restituisce un valore nullo. Tapestry costruirà l'URL della pagina corrente e lo invierà al client come reindirizzamento.

public Object onAction() { 
   return null; 
}
  • String Response- Restituisce il valore della stringa. Tapestry costruirà l'URL della pagina corrispondente al valore e lo invierà al client come reindirizzamento.

public String onAction() { 
   return "Index"; 
}
  • Class Response- Restituisce una classe di pagina. Tapestry costruirà l'URL della classe della pagina restituita e lo invierà al client come reindirizzamento.

public Object onAction() { 
   return Index.class 
}
  • Page Response- Restituisce un campo annotato con @InjectPage. Tapestry costruirà l'URL della pagina inserita e lo invierà al client come reindirizzamento.

@InjectPage 
private Index index;  

public Object onAction(){ 
   return index; 
}
  • HttpError- Restituisce l'oggetto HTTPError. Tapestry emetterà un errore HTTP lato client.

public Object onAction(){ 
   return new HttpError(302, "The Error message); 
}
  • Link Response- Restituisce direttamente un'istanza di collegamento. Tapestry costruirà l'URL dall'oggetto Link e lo invierà al client come reindirizzamento.

  • Stream Response - Restituisce il file StreamResponseoggetto. Tapestry invierà lo stream come risposta direttamente al browser del client. Viene utilizzato per generare report e immagini direttamente e inviarlo al cliente.

  • Url Response - Restituisce il file java.net.URLoggetto. Tapestry otterrà l'URL corrispondente dall'oggetto e lo invierà al client come reindirizzamento.

  • Object Response- Restituisce qualsiasi valore diverso dai valori sopra specificati. Tapestry genererà un errore.

Contesto dell'evento

In generale, il gestore di eventi può ottenere le informazioni sul contesto utilizzando gli argomenti. Ad esempio, se le informazioni di contesto sono 3 di tipo int, il gestore di eventi sarà:

Object onActionFromTest(int id) {  
}

Tapestry gestisce correttamente le informazioni di contesto e le fornisce ai metodi tramite argomenti. A volte, Tapestry potrebbe non essere in grado di gestirlo correttamente a causa della complessità della programmazione. A quel punto, potremmo ottenere le informazioni di contesto complete ed elaborare noi stessi.

Object onActionFromEdit(EventContext context) { 
   if (context.getCount() > 0) { 
      this.selectedId = context.get(0); 
   } else { 
      alertManager.warn("Please select a document."); 
      return null; 
   } 
}