Mis à jour le vendredi 10 mars 2017
  • 40 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Faisons le point !

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Il est temps de mettre en pratique ce que nous avons appris. Nous avons en effet abordé toutes les balises et tous les concepts nécessaires, et sommes maintenant capables de réécrire proprement nos premiers exemples en utilisant des tags JSTL ! Je vous propose ensuite, pour vous détendre un peu, quelques conseils autour de l'écriture de code Java en général.

Reprenons notre exemple

Dans la partie précédente, la mise en place de boucles et conditions était un obstacle que nous étions incapables de franchir sans écrire de code Java. Maintenant que nous avons découvert les balises de la bibliothèque Core de la JSTL, nous avons tout ce qu'il nous faut pour réussir.

Pour rappel, voici où nous en étions :

<%@ page pageEncoding="UTF-8" %>
<%@ page import="java.util.List" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Test</title>
    </head>
    <body>
        <p>Ceci est une page générée depuis une JSP.</p>
        <p>
            ${test}
            ${param.auteur}
        </p>
        <p>
            Récupération du bean :
            ${coyote.prenom}
            ${coyote.nom}
        </p>
        <p>
            Récupération de la liste :
            <%
            List<Integer> liste = (List<Integer>) request.getAttribute( "liste" );
            for( Integer i : liste ){
                out.println(i + " : ");	
            }
            %>
        </p>
        <p>
            Récupération du jour du mois :
            <%
            Integer jourDuMois = (Integer) request.getAttribute( "jour" );
            if ( jourDuMois % 2 == 0 ){
                out.println("Jour pair : " + jourDuMois);
            } else {
                out.println("Jour impair : " + jourDuMois);
            }
            %>
        </p>
    </body>
</html>

Et voici les nouvelles balises qui vont nous permettre de faire disparaître le code Java de notre JSP d'exemple :

  • <c:choose> pour la mise en place de conditions ;

  • <c:forEach> pour la mise en place de boucles.

Reprise de la boucle

En utilisant la syntaxe JSTL, notre boucle devient simplement :

<p>
    Récupération de la liste :
    <%-- Boucle sur l'attribut de la requête nommé 'liste' --%>
    <c:forEach items="${liste}" var="element">
        <c:out value="${element}" /> : 
    </c:forEach>
</p>

Comme prévu, plus besoin de récupérer explicitement la variable contenant la liste depuis la requête, et plus besoin d'écrire du code Java en dur pour mettre en place la boucle sur la liste.

Reprise de la condition

En utilisant la syntaxe JSTL, notre condition devient simplement :

<p>
    Récupération du jour du mois :
    <c:choose>
        <%-- Test de parité sur l'attribut de la requête nommé 'jour' --%>
        <c:when test="${ jour % 2 == 0 }">Jour pair : ${jour}</c:when>
        <c:otherwise>Jour impair : ${jour}</c:otherwise>
    </c:choose>
</p>

Comme prévu, plus besoin de récupérer explicitement la variable contenant le jour du mois depuis la requête, et plus besoin d'écrire du code Java en dur pour mettre en place le test de parité.

Ainsi, notre page finale est bien plus claire et compréhensible :

<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Titre</title>
    </head>
    <body>
        <p>Ceci est une page générée depuis une JSP.</p>
        <p>
            ${test}
            ${param.auteur}
        </p>
        <p>
            Récupération du bean :
            ${coyote.prenom}
            ${coyote.nom}
        </p>
        <p>
            Récupération de la liste :
	    <c:forEach items="${liste}" var="element">
		${element} : 
	    </c:forEach>
	</p>
	<p>
            Récupération du jour du mois :
	    <c:choose>
		<c:when test="${ jour % 2 == 0 }">Jour pair : ${jour}</c:when>
		<c:otherwise>Jour impair : ${jour}</c:otherwise>
	    </c:choose>
	</p>
    </body>
</html>

Quelques conseils

Avant d'attaquer la suite du cours, détendez-vous un instant et découvrez ces quelques astuces pour mieux organiser votre code et le rendre plus lisible.

Utilisation de constantes

Afin de faciliter la lecture et la modification du code d'une classe, il est recommandé de ne pas écrire le contenu des attributs de type primitifs en dur au sein de votre code, et de les regrouper sous forme de constantes en début de classe afin d'y centraliser les données.

Reprenons par exemple notre servlet d'exemple, où vous pouvez voir aux lignes 42 à 45 et 48 des String initialisées directement dans le code :

package com.sdzee.servlets;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.joda.time.DateTime;

import com.sdzee.beans.CoyoteBean;

public class Test extends HttpServlet {
	public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException{
		
		/** Création et initialisation du message. */
		String message = "Message transmis de la servlet à la JSP.";
		
		/** Création du bean et initialisation de ses propriétés */
		CoyoteBean premierBean = new CoyoteBean();
		premierBean.setNom( "Coyote" );
		premierBean.setPrenom( "Wile E." );
		
		/** Création de la liste et insertion de quatre éléments */
		List<Integer> premiereListe = new ArrayList<Integer>();
		premiereListe.add( 27 );
		premiereListe.add( 12 );
		premiereListe.add( 138 );
		premiereListe.add( 6 );
		
		/** On utilise ici la libraire Joda pour manipuler les dates, pour deux raisons :
		 *    - c'est tellement plus simple et limpide que de travailler avec les objets Date ou Calendar !
		 *    - c'est (probablement) un futur standard de l'API Java.
		 */
		DateTime dt = new DateTime();
		Integer jourDuMois = dt.getDayOfMonth();
		
		/** Stockage du message, du bean et de la liste dans l'objet request */
		request.setAttribute( "test", message );
		request.setAttribute( "coyote", premierBean );
		request.setAttribute( "liste", premiereListe );
		request.setAttribute( "jour", jourDuMois );
		
		/** Transmission de la paire d'objets request/response à notre JSP */
		this.getServletContext().getRequestDispatcher( "/WEB-INF/test.jsp" ).forward( request, response );
	}
}

Les lignes 20, 24 à 25 et 29 à 32, bien qu'elles contiennent des String et int en dur, correspondent simplement à l'initialisation des données d'exemple que nous transmettons à notre JSP : ce sont des données "externes". Dans le cas d'une application réelle, ces données seront issues de la base de données, du modèle ou encore d'une saisie utilisateur, mais bien évidemment jamais directement issues de la servlet comme c'est le cas dans cet exemple.

En ce qui concerne les String initialisées en dur, vous devez remarquer qu'elles ne contiennent que des données "internes" : en l'occurrence, un nom de page JSP et quatre noms d'attributs. Il s'agit bien ici de données propres au fonctionnement de l'application et non pas de données destinées à être transmises à la vue pour affichage.

Eh bien comme je vous l'ai annoncé, une bonne pratique est de remplacer ces initialisations directes par des constantes, regroupées en tête de classe. Voici donc le code de notre servlet après modification :

package com.sdzee.servlets;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.joda.time.DateTime;

import com.sdzee.beans.CoyoteBean;

public class Test extends HttpServlet {
	public static final String ATT_MESSAGE = "test";
	public static final String ATT_BEAN	 = "coyote";
	public static final String ATT_LISTE	 = "liste";
	public static final String ATT_JOUR	 = "jour";
	public static final String VUE	 = "/WEB-INF/test.jsp";
	
	public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException{
		
		/** Création et initialisation du message. */
		String message = "Message transmis de la servlet à la JSP.";
		
		/** Création du bean et initialisation de ses propriétés */
		CoyoteBean premierBean = new CoyoteBean();
		premierBean.setNom( "Coyote" );
		premierBean.setPrenom( "Wile E." );
		
		/** Création de la liste et insertion de quatre éléments */
		List<Integer> premiereListe = new ArrayList<Integer>();
		premiereListe.add( 27 );
		premiereListe.add( 12 );
		premiereListe.add( 138 );
		premiereListe.add( 6 );
		
		/** On utilise ici la libraire Joda pour manipuler les dates, pour deux raisons :
		 *    - c'est tellement plus simple et limpide que de travailler avec les objets Date ou Calendar !
		 *    - c'est (probablement) un futur standard de l'API Java.
		 */
		DateTime dt = new DateTime();
		Integer jourDuMois = dt.getDayOfMonth();
		
		/** Stockage du message, du bean et de la liste dans l'objet request */
		request.setAttribute( ATT_MESSAGE, message );
		request.setAttribute( ATT_BEAN, premierBean );
		request.setAttribute( ATT_LISTE, premiereListe );
		request.setAttribute( ATT_JOUR, jourDuMois );
		
		/** Transmission de la paire d'objets request/response à notre JSP */
		this.getServletContext().getRequestDispatcher( VUE ).forward( request, response );
	}
}

Vous visualisez bien ici l'intérêt d'une telle pratique : en début de code sont accessibles en un coup d’œil toutes les données utilisées en dur au sein de la classe. Si vous nommez intelligemment vos constantes, vous pouvez alors, sans avoir à parcourir le code, savoir quelle constante correspond à quelle donnée. Ici par exemple, j'ai préfixé les noms des attributs de requête par "ATT_" et nommé "VUE" la constante contenant le chemin vers notre page JSP. Ainsi, si vous procédez plus tard à une modification sur une de ces données, il vous suffira de modifier la valeur de la constante correspondante et vous n'aurez pas besoin de parcourir votre code. C'est d'autant plus utile que votre classe est volumineuse : plus long est votre code, plus pénible il sera d'y chercher les données initialisées en dur.

Inclure automatiquement la JSTL Core à toutes vos JSP

Vous le savez, pour pouvoir utiliser les balises de la bibliothèque Core dans vos pages JSP, il est nécessaire de faire intervenir la directive include en tête de page :

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

Admettons-le : dans une application, rares seront les vues qui ne nécessiteront pas l'utilisation de balises issues de la JSTL. Afin d'éviter d'avoir à dupliquer cette ligne dans l'intégralité de vos vues, il existe un moyen de rendre cette inclusion automatique ! C'est dans le fichier web.xml que vous avez la possibilité de spécifier une telle section :

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
	<jsp-config>
		<jsp-property-group>
			<url-pattern>*.jsp</url-pattern>
			<include-prelude>/WEB-INF/taglibs.jsp</include-prelude>
		</jsp-property-group>
	</jsp-config>

	...

Le fonctionnement est très simple, la balise <jsp-property-group> ne contenant dans notre cas que deux balises :

  • <url-pattern>, qui permet comme vous vous en doutez de spécifier à quels fichiers appliquer l'inclusion automatique. Ici, j'ai choisi de l'appliquer à tous les fichiers JSP de l'application !

  • <include-prelude>, qui permet de préciser l'emplacement du fichier à inclure en tête de chacune des pages couvertes par le pattern précédemment défini. Ici, j'ai nommé ce fichier taglibs.jsp .

Il ne nous reste donc plus qu'à créer un fichier taglibs.jsp sous le répertoire /WEB-INF de notre application, et à y placer la directive taglib que nous souhaitons voir apparaître sur chacune de nos pages JSP :

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

Redémarrez Tomcat pour que les modifications apportées au fichier web.xml soient prises en compte, et vous n'aurez dorénavant plus besoin de préciser la directive en haut de vos pages JSP : ce sera fait de manière transparente ! :)

Sachez par ailleurs que ce système est équivalent à une inclusion statique, en d'autres termes une directive include <%@ include file="/WEB-INF/taglibs.jsp" %> placée en tête de chaque JSP.

Formater proprement et automatiquement votre code avec Eclipse

Produire un code propre et lisible est très important lorsque vous travaillez sur un projet, et c'est d'autant plus vrai dans le cas d'un projet professionnel et en équipe. Toutefois, harmoniser son style d'écriture sur l'ensemble des classes que l'on rédige n'est pas toujours évident ; il est difficile de faire preuve d'une telle rigueur. Pour nous faciliter la tâche, Eclipse propose un système de formatage automatique du code !

Créer un style de formatage

Sous Eclipse, rendez-vous dans le menu Window > Preferences > Java > Code Style > Formatter, comme indiqué à la figure suivante.

Eclipse format tool.
Eclipse format tool.

Le volet de droite de cette fenêtre est composé de plusieurs blocs :

  • un lien intitulé "Configure Project Specific Settings...", qui vous redirige vers la fenêtre de configuration pour un projet en particulier uniquement ;

  • un formulaire d'édition des profils de formatage existant ;

  • un cadre d'aperçu qui vous montre l'apparence de votre code lorsque le profil actuellement en place est utilisé.

Pour modifier le style de formatage par défaut, il suffit de cliquer sur le bouton Edit.... Vous accédez alors à une vaste interface vous permettant de personnaliser un grand nombre d'options (voir la figure suivante).

Options de formatage du code.
Options de formatage du code.

Je laisse aux plus motivés d'entre vous le loisir de parcourir les différents onglets et de modifier eux-mêmes le style de formatage. Vous devrez, pour que vos modifications soient prises en compte, changer le nom du profil actuel, dans l'encadré en haut de la fenêtre, puis valider les changements en cliquant sur le bouton Apply en bas de fenêtre.

Pour tous les autres, j'ai créé un modèle de formatage prêt à l'emploi, que je vous propose de mettre en place et d'utiliser pour formater vos fichiers sources :
=> Télécharger le fichier format_sdzee.xml (clic droit, puis "Enregistrer sous...")

Une fois le fichier téléchargé, il vous suffit de l'importer dans votre Eclipse en cliquant sur le bouton Import... dans le formulaire de la première fenêtre, comme indiqué à la figure suivante.

Import du modèle de formatage.
Import du modèle de formatage.

Le nom du profil change alors pour format_sdzee, et il vous reste enfin à appliquer les changements en cliquant sur le bouton Apply en bas de fenêtre.

Utiliser un style de formatage

Maintenant que le profil est en place, vous pouvez formater automatiquement votre code source Java. Pour cela, ouvrez un fichier Java quelconque de votre projet, et rendez-vous dans le menu Source > Format, ou utilisez tout simplement le raccourci clavier Ctrl + Maj + F. Prenons pour exemple le code de notre servlet Test (voir la figure suivante).

Rendu du formatage de la source.Rendu du formatage de la source.

À gauche la version non formatée, et à droite la version après formatage. La différence n'est pas énorme sur un code aussi court, d'autant plus que le code d'origine était déjà relativement bien organisé et indenté. Vous pouvez toutefois remarquer quelques changements aérant le code et facilitant sa lecture :

  • l'alignement des valeurs des constantes en tête de classe ;

  • l'ajout d'espaces après l'ouverture et avant la fermeture de parenthèses.

Automatiser le formatage à chaque sauvegarde

Nous voilà mieux équipés, mais il reste un détail pénible : il nous faut encore taper Ctrl + Maj + F chaque fois que nous effectuons des modifications dans le code source, afin de conserver un formatage parfait. Comme nous sommes fainéants, nous allons demander à Eclipse d'y penser pour nous ! Rendez-vous dans le menu Window > Preferences > Java > Editor > Save Actions, comme c'est indiqué sur la figure suivante.

Formatage automatique.
Formatage automatique.

Comme indiqué dans l'encadré, cochez les cases "Perform the selected actions on save" et "Format source code". Validez les changements, et c'est terminé : votre code source Java sera formaté automatiquement selon les règles définies dans votre profil chaque fois que vous enregistrerez des modifications effectuées sur un fichier.

Vous n'avez dorénavant plus aucune excuse : votre code doit être correctement formaté, organisé et indenté ! ;)

Documentation

Les tutoriaux d'auteurs différents vous feront profiter de nouveaux points de vue et angles d'attaque, et les documentations officielles vous permettront un accès à des informations justes et maintenues à jour (en principe).

Liens utiles

Vous l'aurez compris, cette liste ne se veut pas exhaustive, et je vous recommande d'aller chercher par vous-mêmes l'information sur les forums et sites du web. En outre, faites bien attention aux dates de création des documents que vous lisez : les ressources périmées sont légion sur le web, notamment au sujet de la plate-forme Java EE, en constante évolution. N'hésitez pas à demander à la communauté sur le forum Java du Site du Zéro, si vous ne parvenez pas à trouver l'information que vous cherchez.

  • La JSTL nous ouvre la porte aux fonctionnalités jusque là uniquement réalisables avec des scriptlets.

  • Mettre en place des constantes permet de clarifier le code d'une classe et de simplifier sa maintenance.

  • Eclipse peut prendre en charge pour vous le formatage et l'indentation de votre code, ainsi que la gestion automatique des imports.

  • Cette prise en charge est automatisable, vous permettant ainsi de vous libérer de cette contrainte et de vous concentrer sur l'utile.

  • La documentation est indispensable, à condition qu'elle soit à jour.

Exemple de certificat de réussite
Exemple de certificat de réussite