Les FAQs Java :
FAQ JAVA FAQ Java EE FAQ Java ME FAQ Java XML FAQ JavaFX FAQ Java GUI FAQ Struts FAQ JSF FAQ JDBC JDO FAQ Hibernate FAQ Spring FAQ Eclipse FAQ NetBeans FAQ JCreator FAQ Maven 2

La FAQ Java EEConsultez toutes les FAQ

Nombre d'auteurs : 27, nombre de questions : 83, dernière mise à jour : 26 avril 2013 

 
OuvrirSommaireJSPJSP TaglibsTaglibs 1.1

Une librairie de tag peut être distribué sous deux formes :

  • Le descripteur de fichier est séparé des classes Java...
  • Le descripteur de fichier est inclut 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 :

 
Sélectionnez
<%@ taglib uri="/WEB-INF/taglib-v1.0.tld" prefix="tag-prefix">

ou

 
Sélectionnez
<%@ taglib uri="/WEB-INF/lib/taglib-v1.0.jar" prefix="tag-prefix">

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 :

 
Sélectionnez
<taglib>
	<taglib-uri>taglib-URI</taglib-uri>
	<taglib-location>/WEB-INF/lib/taglib-v1.0.jar</taglib-location>
</taglib>

Et utiliser l'URI dans les JSP :

 
Sélectionnez
<%@ taglib uri="taglib-URI" prefix="tag-prefix" %>

Ainsi, les changements de fichier de descripteur s'effectue seulement dans le fichier web.xml...

Enfin, pour utiliser les tags de la librairie, il suffit de les préfixé par le prefixe indiqué dans la directive taglib :

 
Sélectionnez
<tag-prefix:nom-du-tag param="valeur"/>
Créé le 16 février 2005  par adiGuba

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

Créé le 16 février 2005  par adiGuba

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.

Créé le 16 février 2005  par adiGuba

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.

Créé le 16 février 2005  par adiGuba

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 :

 
Sélectionnez
<?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>

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.

Créé le 16 février 2005  par adiGuba

Dans le fichier TLD, il faut ajouter, pour chaque tag, les balises suivantes :

 
Sélectionnez
<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>

Avec les éléments suivants :

  • 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)
Créé le 16 février 2005  par adiGuba

Exemple simple, un tag vide (sans contenu ni attribut) qui affiche simplement la chaine "Hello World".
Le code pourrait se limiter a cela :

 
Sélectionnez
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 :

 
Sélectionnez
<?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>

Le fait de spécifier un bodycontent empty permet de lancer une exception à la compilation si le tag possède un contenu quelconque...

Notre page JSP pourrait ressembler à ceci :

 
Sélectionnez
<%@ taglib uri="taglib-URI" prefix="p" %>
<html>
	<body>
		<b><p:hello/></b>
	</body>
</html>

donnera l'affichage suivant :

 
Sélectionnez
Hello World !
Créé le 16 février 2005  par adiGuba

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 :

 
Sélectionnez
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'appeller doStartTag().
  • Dans doStartTag(), on affiche "Hello " + name + " !"...

enfin, on modifie le TLD de la manière suivante :

 
Sélectionnez
<tag>
	<name>hello</name>
	<tagclass>HelloTag</tagclass>
	<bodycontent>empty</bodycontent>
	<attribute>
		<name>name</name>
	</attribute>
</tag>

Ainsi la page JSP :

 
Sélectionnez
<%@ taglib uri="taglib-URI" prefix="p">
<html>
	<body>
		<b><p:hello/></b>
		<br/>
		<b><p:hello name="Fred"/></b>
		<br/>
	</body>
</html>

donnera l'affichage suivant :

 
Sélectionnez
Hello World ! Hello Fred !
Créé le 16 février 2005  par adiGuba

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 :

 
Sélectionnez
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; 
	}
}

ainsi le code suivant :

 
Sélectionnez
<p:isPresent name="infoConnection">
	[ Vous êtes en ligne ] 
</p:isPresent>

remplace le scriplet suivant :

 
Sélectionnez
<% if ( session.getAttribute("infoConnection") ) { %>
	[ Vous êtes en ligne ] 
<% } %>
Créé le 16 février 2005  par adiGuba

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 :

 
Sélectionnez
<tag>
	<name>iterate</name>
	<tagclass>IterateTag</tagclass>
	<bodycontent>JSP</bodycontent>
	<attribute>
		<name>count</name>
		<required>true</required>
	</attribute>
</tag>

Et son code source :

 
Sélectionnez
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 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 :

 
Sélectionnez
<p:iterate count="3">
	Cette ligne sera affichée trois fois<br/>
</p:iterate>

Résultat:

 
Sélectionnez
Cette ligne sera affichée trois fois
Cette ligne sera affichée trois fois 
Cette ligne sera affichée trois fois
Créé le 16 février 2005  par adiGuba

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 :

 
Sélectionnez
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 :

 
Sélectionnez
<p:iterate count="3">
	Ligne numéro <%=pageContext.getAttribute("line")%>
</p:iterate>

Résultat :

 
Sélectionnez
Ligne numéro 0 Ligne numéro 1 Ligne numéro 2
Créé le 16 février 2005  par adiGuba
  

Les 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 © 2003 - 2013 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.