Toutefois, il est préférrable de ne pas utiliser ces
notations sous cette forme.
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 pourrait être longue et pénible.
Afin de faciliter la maintenance, il faut déclarer
la taglib dans le fichier
web.xml
:
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é si
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'allocation, 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 determine 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
traitement 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'application d'indiqué 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 tag
de la librairie.
Il s'agit d'un fichier XML qui prend la forme
suivante :
<?xmlversion="1.0"encoding="ISO-8859-1"?><!DOCTYPEtaglibPUBLIC"-//SunMicrosystems,Inc.//DTDJSPTagLibrary1.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>
Après l'entête XML et la déclaration du doctype, on
a les éléments suivants :
tlibversion
: Numero de version de la librairie.
jspversion
: Version minimum des JSP requise pour
pouvoir utilisé la librarie (optionnel,
défaut: 1.1).
shortname
: Indique le prefix par défaut de la
librairie pour les EDI compatible (ceci
n'est qu'a titre indicatif, le prefix 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
: Une ou plusieurs mapping 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.
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émentaire 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 si il doit être une chaine
statique (optionnel, défaut:
false/valeur statique)
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 :
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 :
publicclass HelloTag extends TagSupport {private String name =null;
publicvoidsetName(String string) {
name = string;
}publicintdoStartTag() throws JspException {if (name==null) name ="World";
try{
pageContext.getOut().println ("Hello"+ name +"!");
}catch (IOException e) {thrownew JspException ("I/OError", 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'appeller
doStartTag()
.
Dans
doStartTag()
, on affiche
"Hello " + name + " !"
...
On peut avoir besoin d'exécuter une portion de code
seulement si une condition est vérifié.
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 :
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
boucle selon un paramètre count.
Son mapping serait :
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 ligne déjà affiché. Il est
important de l'initialisé dans
doStartTag()
car la même instance de
Tag
peut être utilisé plusieurs fois...
Utilisation :</paragapah>
<p:iteratecount="3">
Cette ligne sera affichée trois fois
<br/></p:iterate>
Résultat:
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 :
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 :
<p:iteratecount="3">
Ligne numéro <%=pageContext.getAttribute("line")%></p:iterate>