Tapisserie Apache - Composants

Comme indiqué précédemment, les composants et les pages sont les mêmes, sauf que la page est le composant racine et comprend un ou plusieurs composants enfants. Les composants résident toujours à l'intérieur d'une page et font presque toutes les fonctionnalités dynamiques de la page.

Les composants Tapestry rendent un simple lien HTML vers une fonctionnalité de grille complexe avec interactive AJAX. Un composant peut également inclure un autre composant. Les composants de la tapisserie se composent des éléments suivants -

  • Component Class - La classe Java principale du composant.

  • XML Template- Le modèle XML est similaire au modèle de page. La classe de composant rend le modèle en tant que sortie finale. Certains composants peuvent ne pas avoir de modèles. Dans ce cas, la sortie sera générée par la classe de composant elle-même en utilisant leMarkupWriter classe.

  • Body- Le composant spécifié dans le modèle de page peut avoir un balisage personnalisé et il est appelé «Corps du composant». Si le modèle de composant a<body />élément, alors l'élément <body /> sera remplacé par le corps du composant. Ceci est similaire à la mise en page décrite précédemment dans la section des modèles XML.

  • Rendering - Le rendu est un processus qui transforme le modèle XML et le corps du composant en sortie réelle du composant.

  • Parameters - Utilisé pour créer une communication entre les composants et les pages et ainsi transmettre des données entre eux.

  • Events- Délègue la fonctionnalité des composants à son conteneur / parent (pages ou autre composant). Il est largement utilisé dans le but de navigation de page.

Le rendu

Le rendu d'un composant se fait en une série de phases prédéfinies. Chaque phase du système de composants doit avoir une méthode correspondante définie par convention ou annotation dans la classe de composants.

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

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

Les phases, son nom de méthode et ses annotations sont listés ci-dessous.

Annotation Noms de méthode par défaut
@SetupRender setupRender ()
@BeginRender beginRender ()
@BeforeRenderTemplate beforeRenderTemplate ()
@BeforeRenderBody beforeRenderBody ()
@AfterRenderBody afterRenderBody ()
@AfterRenderTemplate afterRenderTemplate ()
@AfterRender afterRender ()
@CleanupRender cleanupRender ()

Chaque phase a un objectif spécifique et ils sont les suivants -

SetupRender

SetupRender lance le processus de rendu. Il configure généralement les paramètres du composant.

BeginRender

BeginRender commence le rendu du composant. Il rend généralement la balise de début / de début du composant.

BeforeRenderTemplate

BeforeRenderTemplate est utilisé pour décorer le modèle XML, en ajoutant un balisage spécial autour du modèle. Il fournit également une option pour ignorer le rendu du modèle.

BeforeRenderBody

BeforeRenderTemplate fournit une option pour ignorer le rendu de l'élément body du composant.

AfterRenderBody

AfterRenderBody sera appelé après le rendu du corps du composant.

AfterRenderTemplate

AfterRenderTemplate sera appelé après le rendu du modèle du composant.

AfterRender

AfterRender est le pendant de BeginRender et rend généralement la balise de fermeture.

CleanupRender

CleanupRender est le pendant de SetupRender. Il libère / supprime tous les objets créés pendant le processus de rendu.

Le déroulement des phases de rendu n'est pas seulement en avant. Il va et vient entre les phases en fonction de la valeur de retour d'une phase.

Par exemple, si la méthode SetupRender renvoie false, le rendu passe à la phase CleanupRender et vice versa. Pour trouver une compréhension claire du flux entre les différentes phases, vérifiez le flux dans le diagramme ci-dessous.

Composant simple

Créons un composant simple, Hello qui aura le message de sortie comme "Hello, Tapestry". Voici le code du composant Hello et son modèle.

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>

Le composant Hello peut être appelé dans un modèle de page comme -

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

De même, le composant peut rendre la même sortie à l'aide de MarkupWriter au lieu du modèle comme indiqué ci-dessous.

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

Modifions le modèle de composant et incluons l'élément <body /> comme indiqué dans le bloc de code ci-dessous.

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

Désormais, le modèle de page peut inclure un corps dans le balisage du composant, comme indiqué ci-dessous.

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

La sortie sera la suivante -

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

Paramètres

L'objectif principal de ces paramètres est de créer une connexion entre un champ du composant et une propriété / ressource de la page. À l'aide de paramètres, le composant et sa page correspondante communiquent et transfèrent des données entre eux. C'est appeléTwo Way Data Binding.

Par exemple, un composant de zone de texte utilisé pour représenter l'âge dans une page de gestion des utilisateurs obtient sa valeur initiale (disponible dans la base de données) via le paramètre. Encore une fois, une fois l'âge de l'utilisateur mis à jour et renvoyé, le composant renverra l'âge mis à jour via le même paramètre.

Pour créer un nouveau paramètre dans la classe de composant, déclarez un champ et spécifiez un @Parameterannotation. Ce @Parameter a deux arguments optionnels, qui sont -

  • required- rend le paramètre obligatoire. Tapestry déclenche une exception si elle n'est pas fournie.

  • value - spécifie la valeur par défaut du paramètre.

Le paramètre doit être spécifié dans le modèle de page en tant qu'attributs de la balise de composant. La valeur des attributs doit être spécifiée à l'aide de l'expression / expansion de liaison, dont nous avons parlé dans les chapitres précédents. Certaines des extensions que nous avons apprises plus tôt sont -

  • Property expansion (prop:«val») - Récupère les données de la propriété de la classe de page.

  • Message expansion (message:«val») - Récupérez les données de la clé définie dans le fichier index.properties.

  • Context expansion (context:«val») - Obtenez les données du dossier de contexte Web / src / main / webapp.

  • Asset expansion (asset:«val») - Récupérez les données des ressources intégrées dans le fichier jar, / META-INF / assets.

  • Symbol expansion (symbol:«val») - Récupérez les données des symboles définis dans AppModule.javafile.

Tapestry a beaucoup plus d'extensions utiles, dont certaines sont données ci-dessous -

  • Literal expansion (literal:«val») - Une chaîne littérale.

  • Var expansion (var:«val») - Autorise la lecture ou la mise à jour d'une variable de rendu du composant.

  • Validate expansion (validate:«val»)- Une chaîne spécialisée utilisée pour spécifier la règle de validation d'un objet. Par exemple, validez: obligatoire, minLength = 5.

  • Translate (translate:«val») - Utilisé pour spécifier la classe Translator (conversion de la représentation côté client en représentation côté serveur) lors de la validation d'entrée.

  • Block (block:«val») - L'identifiant de l'élément de bloc dans le modèle.

  • Component (component:«val») - L'identifiant de l'autre composant dans le modèle.

Toutes les extensions ci-dessus sont en lecture seule, à l'exception de l'extension Property et de l'extension Var. Ils sont utilisés par le composant pour échanger des données avec la page. Lorsque vous utilisez l'expansion comme valeurs d'attribut,${...}ne doit pas être utilisé. Au lieu de cela, utilisez simplement l'extension sans symboles dollar et accolades.

Composant utilisant un paramètre

Créons un nouveau composant, HelloWithParameter en modifiant le composant Hello pour rendre dynamiquement le message en ajoutant un name dans la classe de composant et en modifiant le modèle de composant et le modèle de page en conséquence.

  • Créer une nouvelle classe de composants HelloWithParameter.java.

  • Ajoutez un champ privé et nommez-le avec le @Parameterannotation. Utilisez l'argument requis pour le rendre obligatoire.

@Parameter(required = true) 
private String name;
  • Ajouter un champ privé, résultat avec @Properyannotation. La propriété result sera utilisée dans le modèle de composant. Le modèle de composant n'a pas accès aux champs annotés avec@Parameter et ne peut accéder qu'aux champs annotés avec @Property. Les variables disponibles dans les modèles de composants sont appelées Variables de rendu.

@Property 
 private String result;
  • Ajoutez une méthode RenderBody et copiez la valeur du paramètre name dans la propriété result.

@BeginRender 
void initializeValues() { 
   result = name; 
}
  • Ajouter un nouveau modèle de composant HelloWithParamter.tml et utilisez la propriété result pour rendre le message.

<div> Hello, ${result} </div>
  • Ajoutez une nouvelle propriété, Username dans la page de test (testhello.java).

public String getUsername() { 
   return "User1"; 
}
  • Utilisez le composant nouvellement créé dans le modèle de page et définissez la propriété Username dans le paramètre name de HelloWithParameter composant.

<t:helloWithParameter name = "username" />

La liste complète est la suivante -

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>

Le résultat sera le suivant -

<div> Hello, User1 </div>

Paramètre avancé

Dans les chapitres précédents, nous avons analysé comment créer et utiliser un paramètre simple dans un composant personnalisé. Un paramètre avancé peut également contenir un balisage complet. Dans ce cas, le balisage doit être spécifié à l'intérieur de la balise de composant, telle que la sous-section du modèle de page. Le composant if intégré a un balisage pour les conditions de réussite et d'échec. Le balisage de réussite est spécifié comme le corps de la balise de composant et le balisage de l'échec est spécifié à l'aide d'unelseparameter.

Voyons comment utiliser le ifcomposant. Le composant if a deux paramètres -

  • test - Paramètre simple basé sur la propriété.

  • Else - Paramètre avancé utilisé pour spécifier un balisage alternatif, si la condition échoue

Tapestry vérifiera la valeur de la propriété de test en utilisant la logique suivante et retournera vrai ou faux. C'est appeléType Coercion, un moyen de convertir un objet d'un type en un autre type avec le même contenu.

  • Si le type de données est String, «True» si non vide et non la chaîne littérale «False» (insensible à la casse).

  • Si le type de données est Number, Vrai si différent de zéro.

  • Si le type de données est Collection, Vrai si non vide.

  • Si le type de données est Object, True (tant que ce n'est pas nul).

Si la condition réussit, le composant restitue son corps; sinon, il restitue le corps du paramètre else.

La liste complète est la suivante -

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>

Événements de composant / navigation dans les pages

L'application Tapestry est un collection of Pagesinteragir les uns avec les autres. Jusqu'à présent, nous avons appris à créer des pages individuelles sans aucune communication entre elles. L'objectif principal d'un événement Component est de fournir une interaction entre les pages (également dans les pages) à l'aide d'événements côté serveur. La plupart des événements de composant proviennent d'événements côté client.

Par exemple, lorsqu'un utilisateur clique sur un lien dans une page, Tapestry appellera la même page elle-même avec des informations sur la cible au lieu d'appeler la page cible et déclenchera un événement côté serveur. La page Tapestry capturera l'événement, traitera les informations cibles et effectuera une redirection côté serveur vers la page cible.

La tapisserie suit un Post/Redirect/Get (RPG) design patternpour la navigation dans les pages. Dans RPG, lorsqu'un utilisateur fait une demande de publication en soumettant un formulaire, le serveur traitera les données publiées, mais ne retournera pas la réponse directement. Au lieu de cela, il effectuera une redirection côté client vers une autre page, qui affichera le résultat. Un modèle RPG est utilisé pour empêcher les soumissions de formulaires en double via le bouton de retour du navigateur, le bouton d'actualisation du navigateur, etc., Tapestry fournit un modèle de RPG en fournissant les deux types de demande suivants.

  • Component Event Request- Ce type de requête cible un composant particulier dans une page et déclenche des événements au sein du composant. Cette demande ne fait qu'une redirection et ne produit pas la réponse.

  • Render Request - Ces types de demandes ciblent une page et retransmettent la réponse au client.

Pour comprendre les événements du composant et la navigation dans les pages, nous devons connaître le modèle d'URL de la demande de tapisserie. Le modèle d'URL pour les deux types de demande est le suivant -

  • Component Event Requests -

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

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

Certains des exemples de modèles d'URL sont -

  • La page d'index peut être demandée par https://«domain»/«app»/index.

  • Si la page d'index est disponible sous un administrateur de sous-dossier, elle peut être demandée par https://«domain»/«app»/admin/index.

  • Si l'utilisateur clique sur le ActionLink component avec id test dans la page d'index, l'URL sera https://«domain»/«app»/index.test.

Événements

Par défaut, Tapestry augmente OnPassivate et OnActivateévénements pour toutes les demandes. Pour le type de demande d'événement Component, tapestry déclenche un ou plusieurs événements supplémentaires en fonction du composant. Le composant ActionLink déclenche un événement Action, tandis qu'un composant Form déclenche plusieurs événements tels queValidate, Success, etc.,

Les événements peuvent être gérés dans la classe de page à l'aide du gestionnaire de méthode correspondant. Le gestionnaire de méthode est créé via une convention de dénomination de méthode ou via le@OnEventannotation. Le format de la convention de dénomination des méthodes estOn«EventName»From«ComponentId».

Un événement d'action du composant ActionLink avec id test peut être géré par l'une des méthodes suivantes -

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

Si le nom de la méthode n'a aucun composant particulier, alors la méthode sera appelée pour tous les composants avec des événements correspondants.

void OnAction() { 
}

Événement OnPassivate et OnActivate

OnPassivate est utilisé pour fournir des informations de contexte pour un gestionnaire d'événements OnActivate. En général, Tapestry fournit les informations de contexte et peut être utilisé comme argument dans le gestionnaire OnActivateevent.

Par exemple, si les informations de contexte sont 3 de type int, l'événement OnActivate peut être appelé comme -

void OnActivate(int id) { 
}

Dans certains scénarios, les informations de contexte peuvent ne pas être disponibles. Dans ce cas, nous pouvons fournir les informations de contexte au gestionnaire d'événements OnActivate via le gestionnaire d'événements OnPassivate. Le type de retour du gestionnaire d'événements OnPassivate doit être utilisé comme argument du gestionnaire d'événements OnActivate.

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

Valeurs de retour du gestionnaire d'événements

Tapestry émet une redirection de page en fonction des valeurs de retour du gestionnaire d'événements. Le gestionnaire d'événements doit renvoyer l'une des valeurs suivantes.

  • Null Response- Renvoie une valeur nulle. Tapestry construira l'URL de la page actuelle et l'enverra au client en tant que redirection.

public Object onAction() { 
   return null; 
}
  • String Response- Renvoie la valeur de la chaîne. Tapestry construira l'URL de la page correspondant à la valeur et l'enverra au client en tant que redirection.

public String onAction() { 
   return "Index"; 
}
  • Class Response- Renvoie une classe de page. Tapestry construira l'URL de la classe de page retournée et l'enverra au client en tant que redirection.

public Object onAction() { 
   return Index.class 
}
  • Page Response- Renvoie un champ annoté avec @InjectPage. Tapestry construira l'URL de la page injectée et l'enverra au client en tant que redirection.

@InjectPage 
private Index index;  

public Object onAction(){ 
   return index; 
}
  • HttpError- Renvoie l'objet HTTPError. Tapestry émettra une erreur HTTP côté client.

public Object onAction(){ 
   return new HttpError(302, "The Error message); 
}
  • Link Response- Renvoie directement une instance de lien. Tapestry construira l'URL à partir de l'objet Link et l'enverra au client en tant que redirection.

  • Stream Response - Renvoie le StreamResponseobjet. Tapestry enverra le flux en réponse directement au navigateur client. Il est utilisé pour générer directement des rapports et des images et les envoyer au client.

  • Url Response - Renvoie le java.net.URLobjet. Tapestry obtiendra l'URL correspondante de l'objet et l'enverra au client en tant que redirection.

  • Object Response- Renvoie toutes les valeurs autres que les valeurs spécifiées ci-dessus. Tapestry soulèvera une erreur.

Contexte de l'événement

En général, le gestionnaire d'événements peut obtenir les informations de contexte à l'aide d'arguments. Par exemple, si les informations de contexte sont 3 de type int, le gestionnaire d'événements sera -

Object onActionFromTest(int id) {  
}

Tapestry gère correctement les informations de contexte et les fournit aux méthodes via des arguments. Parfois, Tapestry peut ne pas être en mesure de le gérer correctement en raison de la complexité de la programmation. À ce moment-là, nous pouvons obtenir les informations de contexte complètes et traiter nous-mêmes.

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