FAQ Java EEConsultez toutes les FAQ
Nombre d'auteurs : 27, nombre de questions : 85, dernière mise à jour : 3 mai 2015 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de http://www.developpez.com et de l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.
- Comment utiliser une bibliothèque de tags (taglib) ?
- Comment l'interface Tag fonctionne-t-elle ?
- Comment l'interface IterationTag fonctionne-t-elle ?
- Comment l'interface BodyTag fonctionne-t-elle ?
- Comment écrire le descripteur de taglib (TLD) ?
- Comment faire le mapping entre un nom de balise et une classe Tag ?
- Comment écrire un tag ?
- Comment utiliser des attributs de balise ?
- Comment créer un tag conditionnel ?
- Comment créer un tag itératif ?
- Comment interagir avec le contenu du tag ?
Une bibliothèque de tags peut être distribuée sous deux formes :
- le descripteur de fichiers est séparé des classes Java ;
- le descripteur de fichiers est inclus dans le Jar avec les classes et possède le nom suivant : « META-INF/taglib.tld ».
Afin de pouvoir utiliser cette taglib dans un fichier JSP, il faut la déclarer avec la directive taglib.
Respectivement avec le code suivant :
Code xml : | Sélectionner tout |
<%@ taglib uri="/WEB-INF/taglib-v1.0.tld" prefix="tag-prefix">
Code xml : | Sélectionner tout |
<%@ taglib uri="/WEB-INF/lib/taglib-v1.0.jar" prefix="tag-prefix">
En effet, étant donné que la directive taglib doit être présente sur toutes les pages JSP qui l'utilisent, les modifications du nom du descripteur de taglib pourraient être longues et pénibles.
Afin de faciliter la maintenance, il faut déclarer la taglib dans le fichier web.xml :
Code xml : | Sélectionner tout |
1 2 3 4 | <taglib> <taglib-uri>taglib-URI</taglib-uri> <taglib-location>/WEB-INF/lib/taglib-v1.0.jar</taglib-location> </taglib> |
Code xml : | Sélectionner tout |
<%@ taglib uri="taglib-URI" prefix="tag-prefix" %>
Enfin, pour utiliser les tags de la bibliothèque, il suffit de les faire précéder par le préfixe indiqué dans la directive taglib :
Code xml : | Sélectionner tout |
<tag-prefix:nom-du-tag param="valeur"/>
L'évaluation d'un Tag JSP aboutit aux appels suivants :
- les méthodes setParent(Tag) et setPageContext(PageContext) sont renseignées, ainsi que d'éventuels attributs présents dans le tag ;
- la méthode doStartTag() est appelée. Son code de retour détermine l'affichage du contenu de la balise. Si le retour vaut Tag.EVAL_BODY_INCLUDE, le corps est évalué et écrit dans le JspWriter de la page, mais il est ignoré s'il vaut Tag.SKIP_BODY. Si Tag.EVAL_BODY_INCLUDE est retourné alors que la balise n'a pas de corps, il est ignoré ;
- la méthode doEndTag() est appelée. Son code de retour détermine si le reste de la page doit être évalué ou pas. Si le retour vaut Tag.EVAL_PAGE, le reste de la page est évalué, mais il est ignoré si le retour vaut Tag.SKIP_PAGE.
Enfin, la méthode release() est appelée avant que l'objet ne soit rendu au garbage collector.
Attention toutefois, afin d'éviter trop d'allocations, les tags sont conservés en cache et réutilisés (tout comme les Servlet/JSP).
La classe javax.servlet.jsp.tagext.TagSupport propose une implémentation par défaut de l'interface Tag (et de son interface fille IterationTag).
L'interface IterationTag étend l'interface Tag. Elle hérite donc de toutes ses propriétés et permet d'effectuer des itérations sur le contenu de la balise.
La méthode doAfterBody() est appelée après chaque affichage du corps du tag. Son code de retour détermine si le corps doit être réévalué ou pas. Si le retour vaut IterationTag.EVAL_BODY_AGAIN, le corps sera réévalué, mais si le retour vaut Tag.SKIP_BODY, on passe à la fin du tag (doEndTag()) sans réévaluer le corps. La classe javax.servlet.jsp.tagext.TagSupport propose une implémentation par défaut de l'interface IterationTag.
L'interface BodyTag étend l'interface IterationTag. Elle hérite donc de toutes ses propriétés, mais permet plus de traitements sur le corps de la balise.
La méthode doStartTag() peut désormais retourner BodyTag.EVAL_BODY_BUFFERED.
Dans ce cas (et dans ce cas seulement), les méthodes setbodyContent() puis doInitBody() sont appelées avant la première évaluation du corps de la balise.
La méthode setBodyContent() permet au serveur d'applications d'indiquer un buffer qui sera utilisé pour écrire le contenu du corps.
La méthode doInitBody() est appelée avant la première évaluation du corps du message.
La classe javax.servlet.jsp.tagext.BodyTagSupport propose une implémentation par défaut de l'interface BodyTag.
Le Tag Library Descriptor décrit les différents tags de la bibliothèque.
Il s'agit d'un fichier XML qui prend la forme suivante :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <taglib> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>name</shortname> <uri></uri> <info>Description de la taglib</info> <tag>...</tag> </taglib> |
- tlibversion : numéro de version de la bibliothèque ;
- jspversion : version minimum des JSP requise pour pouvoir utiliser la bibliothèque (optionnel, défaut: 1.1) ;
- shortname : indique le préfixe par défaut de la bibliothèque pour les EDI compatibles (ceci n'est qu'à titre indicatif, le préfixe de la directive <%@ taglib %> est utilisé) ;
- uri : une URI unique qui identifie cette version de la taglib (optionnel) ;
- info : un texte de description de la taglib (optionnel) ;
- tag : un ou plusieurs mappings de balise avec les classes Java.
Dans un Jar, ce fichier doit se situer dans le répertoire META-INF avec le nom taglib.tld afin de pouvoir référencer directement le fichier Jar.
Dans le fichier TLD, il faut ajouter, pour chaque tag, les balises suivantes :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | <tag> <name>name</name> <tagclass>package.NameTag</tagclass> <teiclass>package.NameTEI</teiclass> <bodycontent>JSP</bodycontent> <info>description</info> <attribute> <name>arg1</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> |
- name : nom de la balise (Utilisation: <taglib-prefix:nom/>) ;
- tagclass : nom de la classe Java qui représente cette balise (hérite de Tag) ;
- teiclass : nom de la classe Java qui fournit des informations complémentaires sur la balise (optionnel) ;
- bodycontent : type de contenu que peut accepter la balise, peut prendre les valeurs empty (pas de corps), JSP (le contenu est interprété comme du JSP), ou tagdependent (le contenu n'est pas interprété) (optionnel, défaut: JSP) ;
- info : un texte de description du tag (optionnel) ;
- attribute : zéro, une, ou plusieurs déclarations d'attribut du tag, décomposé de la manière suivante :
- name : nom de l'attribut. La classe tagclass doit posséder un mutateur pour cet attribut,
- required : true/false, indique si l'attribut est obligatoire ou pas (optionnel, défaut: false),
- rtexprvalue : true/false, indique si l'attribut peut être le résultat d'une expression (${bean} ou <%=bean%>) ou s'il doit être une chaine statique (optionnel, défaut: false/valeur statique).
Exemple simple, un tag vide (sans contenu ni attribut) qui affiche simplement la chaine « Hello World ».
Le code pourrait se limiter à cela :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | public class HelloTag extends TagSupport { public int doStartTag() throws JspException { try { pageContext.getOut().println ("Hello World !"); } catch (IOException e) { throw new JspException ("I/O Error", e); } return Tag.SKIP_BODY; } } |
Explication
- On étend TagSupport afin de bénéficier des implémentations par défaut des méthodes de Tag.
- On surcharge doStartTag(), dans lequel on se contente d'écrire la chaine « Hello World » dans la sortie de la page courante (pageContext est initialisé par l'implémentation par défaut de setPageContext()).
- On retourne Tag.SKIP_BODY, car on ne veut pas traiter le corps de la balise.
Il est inutile de surcharger doEndTag(), car son implémentation par défaut retourne Tag.EVAL_PAGE.
Notre descripteur de fichier complet ressemble à ceci :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <taglib> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>tex</shortname> <uri></uri> <info>Taglib d'exemple</info> <tag> <name>hello</name> <tagclass>HelloTag</tagclass> <bodycontent>empty</bodycontent> </tag> </taglib> |
Notre page JSP pourrait ressembler à ceci :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 | <%@ taglib uri="taglib-URI" prefix="p" %> <html> <body> <b><p:hello/></b> </body> </html> |
Code : | Sélectionner tout |
Hello World !
Cet exemple se base sur l'exemple précédent.
Nous allons améliorer notre tag précédent en lui ajoutant un attribut name.
Si name est présent, on devra afficher "Hello " suivi de la valeur de l'attribut name, sinon on affiche "Hello World".
Le code précédent devient :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class HelloTag extends TagSupport { private String name = null; public void setName(String string) { name = string; } public int doStartTag() throws JspException { if (name == null) { name = "World"; } try { pageContext.getOut().println ("Hello " + name + " !"); } catch (IOException e) { throw new JspException ("I/O Error", e); } return SKIP_BODY; } } |
Explication
- On ajoute une variable name ainsi que son mutateur setName().
Le mutateur setName() est obligatoire, car il sera utilisé afin d'initialiser l'attribut de classe name avec la valeur de l'attribut du tag, avant d'appeler doStartTag(). - Dans doStartTag(), on affiche "Hello " + name + " !"...
enfin, on modifie le TLD de la manière suivante :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 | <tag> <name>hello</name> <tagclass>HelloTag</tagclass> <bodycontent>empty</bodycontent> <attribute> <name>name</name> </attribute> </tag> |
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | <%@ taglib uri="taglib-URI" prefix="p"> <html> <body> <b><p:hello/></b> <br/> <b><p:hello name="Fred"/></b> <br/> </body> </html> |
Code java : | Sélectionner tout |
Hello World ! Hello Fred !
On peut avoir besoin d'exécuter une portion de code seulement si une condition est vérifiée.
Par exemple, on va exécuter le corps d'un tag seulement si l'attribut indiqué en paramètre est présent dans la session :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class IsPresentTag extends TagSupport { private String name = "World"; public void setName(String string) { name = string; } public int doStartTag() throws JspException { if (name == null) { throw new JspException ("name est null !"); } if (pageContext.getAttribute(name,PageContext.SESSION_SCOPE) != null ) { return EVAL_BODY_INCLUDE; } return SKIP_BODY; } } |
Code xml : | Sélectionner tout |
1 2 3 | <p:isPresent name="infoConnection"> [ Vous êtes en ligne ] </p:isPresent> |
Code java : | Sélectionner tout |
1 2 3 | <% if ( session.getAttribute("infoConnection") ) { %> [ Vous êtes en ligne ] <% } %> |
Afin de créer un tag itératif, il faut implémenter l'interface IterationTag.
Toutefois, TagSupport implémente déjà cette interface, on pourra donc étendre cette classe afin de bénéficier des méthodes par défaut.
Notre tag itératif effectuera un certain nombre de boucles selon un paramètre count.
Son mapping serait :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | <tag> <name>iterate</name> <tagclass>IterateTag</tagclass> <bodycontent>JSP</bodycontent> <attribute> <name>count</name> <required>true</required> </attribute> </tag> |
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class IterateTag extends TagSupport { private int count = 0; private int current; public void setCount(int i) { count = i; } public int doStartTag() throws JspException { current = 0; if (current < count) return Tag.EVAL_BODY_INCLUDE; return Tag.SKIP_BODY; } public int doAfterBody() throws JspException { current++; if (current < count) return IterationTag.EVAL_BODY_AGAIN; return Tag.SKIP_BODY; } } |
Explication
- L'attribut count contiendra la valeur de l'attribut de la balise.
Il n'y a pas de conversion String/int à effectuer, car elle est automatique puisque le mutateur prend un int en paramètre.
En cas de valeur incorrecte, une exception est lancée. - Dans doStartTag(), on initialise current qui contiendra le nombre de lignes déjà affichées. Il est important de l'initialiser dans doStartTag(), car la même instance de Tag peut être utilisée plusieurs fois.
Utilisation :
Code xml : | Sélectionner tout |
1 2 3 | <p:iterate count="3"> Cette ligne sera affichée trois fois<br/> </p:iterate> |
Code : | Sélectionner tout |
1 2 3 | Cette ligne sera affichée trois fois Cette ligne sera affichée trois fois Cette ligne sera affichée trois fois |
Il peut être intéressant d'interagir avec le corps de la balise.
Par exemple, dans le cas d'un tag itératif, on peut avoir besoin du numéro de ligne courant dans le body.
Pour cela, il suffit de stocker des éléments dans un des scopes (page, request, session, application).
On reprend donc le tag précédent et on met le numéro de la ligne dans le scope « page ».
Notre code devient alors :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | public class IterateTag extends TagSupport { private int count = 0; private int current = 0; public void setCount(int i) { count = i; } public int doStartTag() throws JspException { current = 0; if (current < count) { pageContext.setAttribute("line", new Integer(current) ); return Tag.EVAL_BODY_INCLUDE; } return Tag.SKIP_BODY; } public int doAfterBody() throws JspException { current++; if (current < count) { pageContext.setAttribute("line", new Integer(current) ); return IterationTag.EVAL_BODY_AGAIN; } return Tag.SKIP_BODY; } public int doEndTag() throws JspException { pageContext.removeAttribute("line"); return Tag.EVAL_PAGE; } } |
Explication
- Avant chaque évaluation du corps, on place dans le scope "page" un attribut "line" contenant un Integer contenant le numéro de ligne courante.
- Dans doEndTag(), on supprime cet attribut afin de ne pas 'polluer' inutilement le reste de la page.
Note : On peut également proposer un attribut supplémentaire afin de changer le nom de l'attribut stocké dans le scope "page", ainsi que le scope à utiliser...
Utilisation :
Code xml : | Sélectionner tout |
1 2 3 | <p:iterate count="3"> Ligne numéro <%=pageContext.getAttribute("line")%> </p:iterate> |
Code : | Sélectionner tout |
Ligne numéro 0 Ligne numéro 1 Ligne numéro 2
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.