TP Fil rouge - Étape 4

Ce contenu est obsolète. Il peut contenir des informations intéressantes mais soyez prudent avec celles-ci.

Les sessions constituant déjà un gros morceau à elles seules, dans cette étape du fil rouge vous n'allez pas manipuler de cookies. Et croyez-moi, même sans ça vous avez du pain sur la planche !

Objectifs

Fonctionnalités

Vous allez devoir effectuer une modification importante, qui va impacter presque tout votre code existant : je vous demande dans cette étape d'enregistrer en session les clients et commandes créés par un utilisateur. Cela pourrait très bien être un jeu d'enfants, si je ne vous demandais rien d'autre derrière… Mais ne rêvez pas, vous n'êtes pas ici pour vous tourner les pouces ! :p

Enregistrement en session

Pour commencer, comme je viens de vous l'annoncer, vous allez devoir enregistrer en session les clients et commandes créés par un utilisateur. Ainsi, les informations saisies par l'utilisateur ne seront plus perdues après validation d'un formulaire de création !

Liste récapitulative des clients et commandes créés

Deuxièmement, vous allez devoir créer deux nouvelles pages :

  • listerClients.jsp, qui listera les clients créés par l'utilisateur ;
  • listerCommandes.jsp, qui listera les commandes créées par l'utilisateur.

Vous les placerez bien entendu sous /WEB-INF tout comme leurs consœurs, Vous en profiterez pour mettre à jour la page menu.jsp en y ajoutant deux liens vers les nouvelles servlets gérant ces deux pages fraîchement créées.

Un formulaire de création de commande intelligent

Troisièmement, et cette fois il va falloir réfléchir davantage, je vous demande de modifier le formulaire de création de commandes. Maintenant que votre application est capable d'enregistrer les clients créés par l'utilisateur, vous allez lui donner un choix lorsqu'il crée une commande :

  • si la commande qu'il veut créer concerne un nouveau client, alors affichez-lui les champs permettant la saisie des informations du nouveau client, comme vous le faisiez déjà auparavant ;
  • si la commande qu'il veut créer concerne un client déjà existant, alors affichez-lui une liste déroulante des clients existants, lui permettant de choisir son client et lui évitant ainsi de saisir à nouveau ces informations.

Système de suppression des clients et commandes

Quatrièmement, vous allez devoir mettre en place un système permettant la suppression d'un client ou d'une commande enregistrée dans la session. Vous allez ensuite devoir compléter vos pages listerClients.jsp et listerCommandes.jsp pour qu'elles affichent à côté de chaque client et commande un lien vers ce système, permettant la suppression de l'entité correspondante.

Gestion de l'encodage UTF-8 des données

Cinquièmement, vous allez appliquer le filtre d'encodage de Tomcat à votre projet, afin de rendre votre application capable de gérer n'importe quelle donnée UTF-8.

Enfin, vous devrez vous préparer une tasse un thermos de café ou de thé bien fort, parce qu'avec tout ce travail, vous n'êtes pas couchés ! :lol:

Exemples de rendus

Voici aux figures suivantes quelques exemples de rendu. Liste des clients créés au cours de la session, ici avec quatre clients.

Liste des clients créés au cours de la session, ici avec quatre clients

Liste des commandes lorsqu'aucune commande n'a été créée au cours de la session :

Liste des commandes lorsqu'aucune commande n'a été créée au cours de la session

Formulaire de création d'une commande lorsque la case "Nouveau client : Oui" est cochée :

Formulaire de création d'une commande lorsque la case

Formulaire de création d'une commande lorsque la case "Nouveau client : Non" est cochée :

Formulaire de création d'une commande lorsque la case

Liste des commandes lorsque deux commandes ont été créées au cours de la session :

Liste des commandes lorsque deux commandes ont été créées au cours de la session

Conseils

Enregistrement en session

Concernant l'aspect technique de cette problématique, vous avez toutes les informations dans le chapitre sur ce sujet : il vous suffit de récupérer la session en cours depuis l'objet requête, et d'y mettre en place des attributs. Concernant la mise en place dans ce cas précis par contre, il y a une question que vous allez devoir vous poser : quel type d'attributs enregistrer en session ? Autrement dit, comment stocker les clients et commandes ? C'est une bonne question. Essayez d'y réfléchir par vous-mêmes avant de lire le conseil qui suit…

Ici, ce qui vous intéresse, c'est d'enregistrer les clients et les commandes créés. Une liste de clients et une liste de commandes pourraient donc a priori faire l'affaire, mais retrouver quelque chose dans une liste, ce n'est pas simple… Pourtant, vous aimeriez bien pouvoir identifier facilement un client ou une commande dans ces listes. Pour cette raison, une Map semble la solution adaptée. Oui, mais comment organiser cette Map ? Les objets Client et Commande seront bien entendu les valeurs, mais qu'est-ce qui va bien pouvoir servir de clé ? Il y a tout un tas de solutions possibles, mais je vous conseille pour le moment de mettre en place la moins contraignante : considérez que le nom permet d'identifier de manière unique un client, et que la date permet d'identifier de manière unique une commande. Cela implique que votre application ne permettra pas de créer deux commandes au même instant, ni de créer deux clients portant le même nom. Ce n'est pas génial comme comportement, mais pour le moment votre application ne gère toujours pas les données, donc ça ne vous pose absolument aucun problème ! Vous aurez tout le loisir de régler ce petit souci dans l'étape 6 du fil rouge ! :D

Bref, je vous conseille donc de placer en session une Map<String, Client> contenant les clients identifiés par leur nom, et une Map<String, Commande> contenant les commandes identifiées par leur date.

Liste récapitulative des clients et commandes créés

Deux pages JSP accédant directement aux attributs stockés en session suffisent ici. Puisque vous allez les placer sous /WEB-INF, elles ne seront pas accessibles directement par leur URL et vous devrez mettre en place des servlets en amont, qui se chargeront de leur retransmettre les requêtes reçues. Vous pouvez par exemple les appeler ListeClients et ListeCommandes, et vous n'oublierez pas de les déclarer dans votre fichier web.xml.

Dans chacune de ces JSP, le plus simple est de générer un tableau HTML qui affichera ligne par ligne les clients ou commandes créés (voir les exemples de rendus). Pour cela, il vous suffit de parcourir les Map enregistrées en tant qu'attributs de session à l'aide de la balise de boucle JSTL <c:forEach>. Relisez le passage du cours sur la JSTL si vous avez oublié comment itérer sur une collection, et relisez la correction de l'exercice sur la JSTL Core si vous avez oublié comment atteindre les clés et valeurs d'une Map depuis une EL ! Dans le corps de cette boucle, vous placerez les balises HTML nécessaires à la création des lignes du tableau HTML, contenant les entrées de la Map des clients ou des commandes.

En bonus, pour aérer la lecture du tableau final dans le navigateur, vous pouvez utiliser un compteur au sein de votre boucle pour alterner la couleur de fond d'une ligne à l'autre. Cela se fait par exemple en testant simplement si l'indice de parcours de la boucle est pair ou impair.

Second bonus, vous pouvez mettre en place un test vérifiant si les objets présents en sessions existent ou non, via par exemple la balise <c:choose> : si non, alors vous pouvez par exemple afficher un message signalant qu'aucun client ou aucune commande n'existe (voir les exemples de rendus).

Un formulaire de création de commande intelligent

En ce qui concerne cette modification, vous allez devoir réfléchir un peu à la solution à mettre en place : comment donner un choix à l'utilisateur ? Si vous regardez les exemples de rendus que je vous ai donnés ci-dessus, vous verrez que j'ai mis en place deux simples boutons de type <input type="radio" /> :

  • au clic sur "Oui", la première partie du formulaire classique s'affiche ;
  • au clic sur "Non", un nouveau champ <select> listant les clients existants remplace la première partie du formulaire !

Bien entendu, vous n'êtes pas forcés d'utiliser ce moyen ! Si vous souhaitez que votre apprentissage soit efficace, alors vous devez réfléchir par vous-mêmes à cette petite problématique et lui trouver une solution adaptée sans mon aide. Ce petit exercice de conception donnera du fil à retordre à vos neurones et vous fera prendre encore un peu plus d'aisance avec le Java EE ! ;)

En outre, la solution que je propose ici est un peu évoluée, car elle implique un petit morceau de code Javascript pour permettre la modification du formulaire au clic sur un bouton radio. Si vous ne la sentez pas, prenez le temps et pensez à un autre système plus simple et peut-être moins évolué graphiquement qui permettrait à l'utilisateur de choisir entre une liste des clients existants et un formulaire classique comme vous l'affichiez par défaut auparavant. Ne vous découragez pas, testez et réussissez !

Note : une telle modification du formulaire va bien évidemment impliquer une modification de l'objet métier qui y est associé, c'est-à-dire CreationCommandeForm. En effet, puisque vous proposez la réutilisation d'un client existant à l'utilisateur dans le formulaire, vous devrez faire en sorte dans votre objet métier de ne valider les informations clients que si un nouveau client a été créé, et simplement récupérer l'objet Client existant si l'utilisateur choisit un ancien client dans la liste !

Système de suppression des clients et commandes

Pour terminer, il vous suffit ici de créer deux servlets, dédiées chacune à la suppression d'un client et d'une commande de la Map présente en session. Vous contacterez ces servlets via de simples liens HTML depuis vos pages listerClients.jsp ou listerCommandes.jsp ; il faudra donc y implémenter la méthode doGet(). Ces liens contiendront alors, soit un nom de client, soit une date de commande en tant que paramètre d'URL, et les servlets se chargeront alors de retirer l'entrée correspondante de la Map des clients ou des commandes, grâce à la méthode remove().

Dans les exemples de rendus ci-dessus, les croix rouges affichées en fin de chaque ligne des tableaux sont des liens vers les servlets de suppression respectives, que vous pouvez par exemple nommer SuppressionClient et SuppressionCommande.

Gestion de l'encodage UTF-8 des données

Rien de particulier à vous conseiller ici, il suffit simplement de recopier la déclaration du filtre de Tomcat dans le web.xml du projet, et le tour est joué ! ;)

Correction

Cette fois, la longueur du sujet n'est pas trompeuse : le travail que vous devez fournir est bien important ! :D Posez-vous calmement les bonnes questions, faites l'analogie avec ce que vous avez appris dans les chapitres de cours et n'oubliez pas les bases que vous avez découvertes auparavant (création d'une servlet, modification du fichier web.xml, utilisation de la JSTL, etc.). Comme toujours, ce n'est pas la seule manière de faire, le principal est que votre solution respecte les consignes que je vous ai données !

Pour que cette correction soit entièrement fonctionnelle, vous devrez inclure la bibliothèque jQuery dans le répertoire /inc de votre projet, ainsi que le fichier image utilisé pour illustrer le bouton de suppression.

Voici les deux fichiers à télécharger :

Le code des vues

Ajout des deux nouveaux liens dans la page menu.jsp :

1
2
3
4
5
6
7
8
<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<div id="menu">
    <p><a href="<c:url value="/creationClient"/>">Créer un nouveau client</a></p>
    <p><a href="<c:url value="/creationCommande"/>">Créer une nouvelle commande</a></p>
    <p><a href="<c:url value="/listeClients"/>">Voir les clients existants</a></p>
    <p><a href="<c:url value="/listeCommandes"/>">Voir les commandes existantes</a></p>
</div>

/inc/menu.jsp

Modification du formulaire de création d'une commande :

  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
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Création d'une commande</title>
        <link type="text/css" rel="stylesheet" href="<c:url value="/inc/style.css"/>" />
    </head>
    <body>
        <c:import url="/inc/menu.jsp" />
        <div>
            <form method="post" action="<c:url value="/creationCommande"/>">
                <fieldset>
                    <legend>Informations client</legend>
                    <%-- Si et seulement si la Map des clients en session n'est pas vide, alors on propose un choix à l'utilisateur --%>
                    <c:if test="${ !empty sessionScope.clients }">
                        <label for="choixNouveauClient">Nouveau client ? <span class="requis">*</span></label>
                        <input type="radio" id="choixNouveauClient" name="choixNouveauClient" value="nouveauClient" checked /> Oui
                        <input type="radio" id="choixNouveauClient" name="choixNouveauClient" value="ancienClient" /> Non
                        <br/><br />
                    </c:if>

                    <c:set var="client" value="${ commande.client }" scope="request" />
                    <div id="nouveauClient">
                        <c:import url="/inc/inc_client_form.jsp" />
                    </div>

                    <%-- Si et seulement si la Map des clients en session n'est pas vide, alors on crée la liste déroulante --%>
                    <c:if test="${ !empty sessionScope.clients }">
                    <div id="ancienClient">
                        <select name="listeClients" id="listeClients">
                            <option value="">Choisissez un client...</option>
                            <%-- Boucle sur la map des clients --%>
                            <c:forEach items="${ sessionScope.clients }" var="mapClients">
                            <%--  L'expression EL ${mapClients.value} permet de cibler l'objet Client stocké en tant que valeur dans la Map, 
                                  et on cible ensuite simplement ses propriétés nom et prenom comme on le ferait avec n'importe quel bean. --%>
                            <option value="${ mapClients.value.nom }">${ mapClients.value.prenom } ${ mapClients.value.nom }</option>
                            </c:forEach>
                        </select>
                    </div>
                    </c:if>
                </fieldset>
                <fieldset>
                    <legend>Informations commande</legend>

                    <label for="dateCommande">Date <span class="requis">*</span></label>
                    <input type="text" id="v" name="dateCommande" value="<c:out value="${commande.date}"/>" size="30" maxlength="30" disabled />
                    <span class="erreur">${form.erreurs['dateCommande']}</span>
                    <br />

                    <label for="montantCommande">Montant <span class="requis">*</span></label>
                    <input type="text" id="montantCommande" name="montantCommande" value="<c:out value="${commande.montant}"/>" size="30" maxlength="30" />
                    <span class="erreur">${form.erreurs['montantCommande']}</span>
                    <br />

                    <label for="modePaiementCommande">Mode de paiement <span class="requis">*</span></label>
                    <input type="text" id="modePaiementCommande" name="modePaiementCommande" value="<c:out value="${commande.modePaiement}"/>" size="30" maxlength="30" />
                    <span class="erreur">${form.erreurs['modePaiementCommande']}</span>
                    <br />

                    <label for="statutPaiementCommande">Statut du paiement</label>
                    <input type="text" id="statutPaiementCommande" name="statutPaiementCommande" value="<c:out value="${commande.statutPaiement}"/>" size="30" maxlength="30" />
                    <span class="erreur">${form.erreurs['statutPaiementCommande']}</span>
                    <br />

                    <label for="modeLivraisonCommande">Mode de livraison <span class="requis">*</span></label>
                    <input type="text" id="modeLivraisonCommande" name="modeLivraisonCommande" value="<c:out value="${commande.modeLivraison}"/>" size="30" maxlength="30" />
                    <span class="erreur">${form.erreurs['modeLivraisonCommande']}</span>
                    <br />

                    <label for="statutLivraisonCommande">Statut de la livraison</label>
                    <input type="text" id="statutLivraisonCommande" name="statutLivraisonCommande" value="<c:out value="${commande.statutLivraison}"/>" size="30" maxlength="30" />
                    <span class="erreur">${form.erreurs['statutLivraisonCommande']}</span>
                    <br />

                    <p class="info">${ form.resultat }</p>
                </fieldset>
                <input type="submit" value="Valider"  />
                <input type="reset" value="Remettre à zéro" /> <br />
            </form>
        </div>

        <%-- Inclusion de la bibliothèque jQuery. Vous trouverez des cours sur JavaScript et jQuery aux adresses suivantes :
               - http://www.siteduzero.com/tutoriel-3-309961-dynamisez-vos-sites-web-avec-javascript.html 
               - http://www.siteduzero.com/tutoriel-3-659477-un-site-web-dynamique-avec-jquery.html 

             Si vous ne souhaitez pas télécharger et ajouter jQuery à votre projet, vous pouvez utiliser la version fournie directement en ligne par Google :
             <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script> 
        --%>
        <script src="<c:url value="/inc/jquery.js"/>"></script>

        <%-- Petite fonction jQuery permettant le remplacement de la première partie du formulaire par la liste déroulante, au clic sur le bouton radio. --%>
        <script>
            jQuery(document).ready(function(){
                /* 1 - Au lancement de la page, on cache le bloc d'éléments du formulaire correspondant aux clients existants */
                $("div#ancienClient").hide();
                /* 2 - Au clic sur un des deux boutons radio "choixNouveauClient", on affiche le bloc d'éléments correspondant (nouveau ou ancien client) */
                jQuery('input[name=choixNouveauClient]:radio').click(function(){
                    $("div#nouveauClient").hide();
                    $("div#ancienClient").hide();
                    var divId = jQuery(this).val();
                    $("div#"+divId).show();
                });
            });
        </script>
    </body>
</html>

/WEB-INF/creerCommande.jsp

Ajout des styles CSS des éléments des tableaux :

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

/* Tableaux -------------------------------------------------------------------------------------*/
table{
    border-collapse: collapse;
}
tr.pair{
    background-color: #efefef;
}
tr.impair{
    background-color: #fff; 
}
th{
    color: #0568CD;
    border: 1px solid #0568CD;
    padding: 5px;
}
th.action{
    border: 1px solid #900;
    color: #900;
}
td{
    border: 1px solid #ddd;
    padding: 5px;
}
td.action{
    text-align: center;
}

/inc/style.css

Création des pages listant les clients et commandes créés :

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Liste des clients existants</title>
        <link type="text/css" rel="stylesheet" href="<c:url value="/inc/style.css"/>" />
    </head>
    <body>
        <c:import url="/inc/menu.jsp" />
        <div id="corps">
        <c:choose>
            <%-- Si aucun client n'existe en session, affichage d'un message par défaut. --%>
            <c:when test="${ empty sessionScope.clients }">
                <p class="erreur">Aucun client enregistré.</p>
            </c:when>
            <%-- Sinon, affichage du tableau. --%>
            <c:otherwise>
            <table>
                <tr>
                    <th>Nom</th>
                    <th>Prénom</th>
                    <th>Adresse</th>
                    <th>Téléphone</th>
                    <th>Email</th>
                    <th class="action">Action</th>                    
                </tr>
                <%-- Parcours de la Map des clients en session, et utilisation de l'objet varStatus. --%>
                <c:forEach items="${ sessionScope.clients }" var="mapClients" varStatus="boucle">
                <%-- Simple test de parité sur l'index de parcours, pour alterner la couleur de fond de chaque ligne du tableau. --%>
                <tr class="${boucle.index % 2 == 0 ? 'pair' : 'impair'}">
                    <%-- Affichage des propriétés du bean Client, qui est stocké en tant que valeur de l'entrée courante de la map --%>
                    <td><c:out value="${ mapClients.value.nom }"/></td>
                    <td><c:out value="${ mapClients.value.prenom }"/></td>
                    <td><c:out value="${ mapClients.value.adresse }"/></td>
                    <td><c:out value="${ mapClients.value.telephone }"/></td>
                    <td><c:out value="${ mapClients.value.email }"/></td>
                    <%-- Lien vers la servlet de suppression, avec passage du nom du client - c'est-à-dire la clé de la Map - en paramètre grâce à la balise <c:param/>. --%>
                    <td class="action">
                        <a href="<c:url value="/suppressionClient"><c:param name="nomClient" value="${ mapClients.key }" /></c:url>">
                            <img src="<c:url value="/inc/supprimer.png"/>" alt="Supprimer" />
                        </a>
                    </td>
                </tr>
                </c:forEach>
            </table>
            </c:otherwise>
        </c:choose>
        </div>
    </body>
</html>

/WEB-INF/listerClients.jsp

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Liste des commandes existantes</title>
        <link type="text/css" rel="stylesheet" href="<c:url value="/inc/style.css"/>" />
    </head>
    <body>
        <c:import url="/inc/menu.jsp" />
        <div id="corps">
        <c:choose>
            <%-- Si aucune commande n'existe en session, affichage d'un message par défaut. --%>
            <c:when test="${ empty sessionScope.commandes }">
                <p class="erreur">Aucune commande enregistrée.</p>
            </c:when>
            <%-- Sinon, affichage du tableau. --%>
            <c:otherwise>
            <table>
                <tr>
                    <th>Client</th>
                    <th>Date</th>
                    <th>Montant</th>
                    <th>Mode de paiement</th>
                    <th>Statut de paiement</th>
                    <th>Mode de livraison</th>
                    <th>Statut de livraison</th>
                    <th class="action">Action</th>                    
                </tr>
                <%-- Parcours de la Map des commandes en session, et utilisation de l'objet varStatus. --%>
                <c:forEach items="${ sessionScope.commandes }" var="mapCommandes" varStatus="boucle">
                <%-- Simple test de parité sur l'index de parcours, pour alterner la couleur de fond de chaque ligne du tableau. --%>
                <tr class="${boucle.index % 2 == 0 ? 'pair' : 'impair'}">
                    <%-- Affichage des propriétés du bean Commande, qui est stocké en tant que valeur de l'entrée courante de la map --%>
                    <td><c:out value="${ mapCommandes.value.client.prenom } ${ mapCommandes.value.client.nom }"/></td>
                    <td><c:out value="${ mapCommandes.value.date }"/></td>
                    <td><c:out value="${ mapCommandes.value.montant }"/></td>
                    <td><c:out value="${ mapCommandes.value.modePaiement }"/></td>
                    <td><c:out value="${ mapCommandes.value.statutPaiement }"/></td>
                    <td><c:out value="${ mapCommandes.value.modeLivraison }"/></td>
                    <td><c:out value="${ mapCommandes.value.statutLivraison }"/></td>
                    <%-- Lien vers la servlet de suppression, avec passage de la date de la commande - c'est-à-dire la clé de la Map - en paramètre grâce à la balise <c:param/>. --%>
                    <td class="action">
                        <a href="<c:url value="/suppressionCommande"><c:param name="dateCommande" value="${ mapCommandes.key }" /></c:url>">
                            <img src="<c:url value="/inc/supprimer.png"/>" alt="Supprimer" />
                        </a>
                    </td>
                </tr>
                </c:forEach>
            </table>
            </c:otherwise>
        </c:choose>
        </div>
    </body>
</html>

/WEB-INF/listerCommandes.jsp

Le code des servlets

Ajout des quatre servlets de suppression et de listage dans le fichier web.xml :

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
    <filter>
        <filter-name>Set Character Encoding</filter-name>
        <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>ignore</param-name>
            <param-value>false</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>Set Character Encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>CreationClient</servlet-name>
        <servlet-class>com.sdzee.tp.servlets.CreationClient</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>ListeClients</servlet-name>
    <servlet-class>com.sdzee.tp.servlets.ListeClients</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>SuppressionClient</servlet-name>
        <servlet-class>com.sdzee.tp.servlets.SuppressionClient</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>CreationCommande</servlet-name>
        <servlet-class>com.sdzee.tp.servlets.CreationCommande</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>ListeCommandes</servlet-name>
        <servlet-class>com.sdzee.tp.servlets.ListeCommandes</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>SuppressionCommande</servlet-name>
        <servlet-class>com.sdzee.tp.servlets.SuppressionCommande</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>CreationClient</servlet-name>
        <url-pattern>/creationClient</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>ListeClients</servlet-name>
        <url-pattern>/listeClients</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>SuppressionClient</servlet-name>
        <url-pattern>/suppressionClient</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>CreationCommande</servlet-name>
        <url-pattern>/creationCommande</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>ListeCommandes</servlet-name>
        <url-pattern>/listeCommandes</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>SuppressionCommande</servlet-name>
        <url-pattern>/suppressionCommande</url-pattern>
    </servlet-mapping>
</web-app>

/WEB-INF/web.xml

Création des servlets de listage :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package com.sdzee.tp.servlets;

import java.io.IOException;

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

public class ListeClients extends HttpServlet {
    public static final String ATT_CLIENT = "client";
    public static final String ATT_FORM   = "form";

    public static final String VUE        = "/WEB-INF/listerClients.jsp";

    public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
        /* À la réception d'une requête GET, affichage de la liste des clients */
        this.getServletContext().getRequestDispatcher( VUE ).forward( request, response );
    }
}

com.sdzee.tp.servlets.ListeClients

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package com.sdzee.tp.servlets;

import java.io.IOException;

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

public class ListeCommandes extends HttpServlet {
    public static final String ATT_COMMANDE = "commande";
    public static final String ATT_FORM     = "form";

    public static final String VUE          = "/WEB-INF/listerCommandes.jsp";

    public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
        /* À la réception d'une requête GET, affichage de la liste des commandes */
        this.getServletContext().getRequestDispatcher( VUE ).forward( request, response );
    }
}

com.sdzee.tp.servlets.ListeClients

Création des servlets de suppression :

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.sdzee.tp.servlets;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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

import com.sdzee.tp.beans.Client;

public class SuppressionClient extends HttpServlet {

    public static final String PARAM_NOM_CLIENT = "nomClient";
    public static final String SESSION_CLIENTS  = "clients";

    public static final String VUE              = "/listeClients";

    public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
        /* Récupération du paramètre */
        String nomClient = getValeurParametre( request, PARAM_NOM_CLIENT );

        /* Récupération de la Map des clients enregistrés en session */
        HttpSession session = request.getSession();
        Map<String, Client> clients = (HashMap<String, Client>) session.getAttribute( SESSION_CLIENTS );

        /* Si le nom du client et la Map des clients ne sont pas vides */
        if ( nomClient != null && clients != null ) {
            /* Alors suppression du client de la Map */
            clients.remove( nomClient );
            /* Et remplacement de l'ancienne Map en session par la nouvelle */
            session.setAttribute( SESSION_CLIENTS, clients );
        }

        /* Redirection vers la fiche récapitulative */
        response.sendRedirect( request.getContextPath() + VUE );
    }

    /*
     * Méthode utilitaire qui retourne null si un paramètre est vide, et son
     * contenu sinon.
     */
    private static String getValeurParametre( HttpServletRequest request, String nomChamp ) {
        String valeur = request.getParameter( nomChamp );
        if ( valeur == null || valeur.trim().length() == 0 ) {
            return null;
        } else {
            return valeur;
        }
    }
}

com.sdzee.tp.servlets.SuppressionClient

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.sdzee.tp.servlets;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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

import com.sdzee.tp.beans.Commande;

public class SuppressionCommande extends HttpServlet {

    public static final String PARAM_DATE_COMMANDE = "dateCommande";
    public static final String SESSION_COMMANDES   = "commandes";

    public static final String VUE                 = "/listeCommandes";

    public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
        /* Récupération du paramètre */
        String dateCommande = getValeurParametre( request, PARAM_DATE_COMMANDE );

        /* Récupération de la Map des commandes enregistrées en session */
        HttpSession session = request.getSession();
        Map<String, Commande> commandes = (HashMap<String, Commande>) session.getAttribute( SESSION_COMMANDES );

        /* Si la date de la commande et la Map des commandes ne sont pas vides */
        if ( dateCommande != null && commandes != null ) {
            /* Alors suppression de la commande de la Map */
            commandes.remove( dateCommande );
            /* Et remplacement de l'ancienne Map en session par la nouvelle */
            session.setAttribute( SESSION_COMMANDES, commandes );
        }

        /* Redirection vers la fiche récapitulative */
        response.sendRedirect( request.getContextPath() + VUE );
    }

    /*
     * Méthode utilitaire qui retourne null si un paramètre est vide, et son
     * contenu sinon.
     */
    private static String getValeurParametre( HttpServletRequest request, String nomChamp ) {
        String valeur = request.getParameter( nomChamp );
        if ( valeur == null || valeur.trim().length() == 0 ) {
            return null;
        } else {
            return valeur;
        }
    }
}

com.sdzee.tp.servlets.SuppressionCommande

Modification des servlets existantes pour l'enregistrement en session :

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.sdzee.tp.servlets;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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

import com.sdzee.tp.beans.Client;
import com.sdzee.tp.forms.CreationClientForm;

public class CreationClient extends HttpServlet {

    public static final String ATT_CLIENT      = "client";
    public static final String ATT_FORM        = "form";
    public static final String SESSION_CLIENTS = "clients";

    public static final String VUE_SUCCES      = "/WEB-INF/afficherClient.jsp";
    public static final String VUE_FORM        = "/WEB-INF/creerClient.jsp";

    public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
        /* À la réception d'une requête GET, simple affichage du formulaire */
        this.getServletContext().getRequestDispatcher( VUE_FORM ).forward( request, response );
    }

    public void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
        /* Préparation de l'objet formulaire */
        CreationClientForm form = new CreationClientForm();

        /* Traitement de la requête et récupération du bean en résultant */
        Client client = form.creerClient( request );

        /* Ajout du bean et de l'objet métier à l'objet requête */
        request.setAttribute( ATT_CLIENT, client );
        request.setAttribute( ATT_FORM, form );

        /* Si aucune erreur */
        if ( form.getErreurs().isEmpty() ) {
            /* Alors récupération de la map des clients dans la session */
            HttpSession session = request.getSession();
            Map<String, Client> clients = (HashMap<String, Client>) session.getAttribute( SESSION_CLIENTS );
            /* Si aucune map n'existe, alors initialisation d'une nouvelle map */
            if ( clients == null ) {
                clients = new HashMap<String, Client>();
            }
            /* Puis ajout du client courant dans la map */
            clients.put( client.getNom(), client );
            /* Et enfin (ré)enregistrement de la map en session */
            session.setAttribute( SESSION_CLIENTS, clients );

            /* Affichage de la fiche récapitulative */
            this.getServletContext().getRequestDispatcher( VUE_SUCCES ).forward( request, response );
        } else {
            /* Sinon, ré-affichage du formulaire de création avec les erreurs */
            this.getServletContext().getRequestDispatcher( VUE_FORM ).forward( request, response );
        }
    }
}

com.sdzee.tp.servlets.CreationClient

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.sdzee.tp.servlets;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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

import com.sdzee.tp.beans.Client;
import com.sdzee.tp.beans.Commande;
import com.sdzee.tp.forms.CreationCommandeForm;

public class CreationCommande extends HttpServlet {
    public static final String ATT_COMMANDE      = "commande";
    public static final String ATT_FORM          = "form";
    public static final String SESSION_CLIENTS   = "clients";
    public static final String SESSION_COMMANDES = "commandes";

    public static final String VUE_SUCCES        = "/WEB-INF/afficherCommande.jsp";
    public static final String VUE_FORM          = "/WEB-INF/creerCommande.jsp";

    public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
        /* À la réception d'une requête GET, simple affichage du formulaire */
        this.getServletContext().getRequestDispatcher( VUE_FORM ).forward( request, response );
    }

    public void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
        /* Préparation de l'objet formulaire */
        CreationCommandeForm form = new CreationCommandeForm();

        /* Traitement de la requête et récupération du bean en résultant */
        Commande commande = form.creerCommande( request );

        /* Ajout du bean et de l'objet métier à l'objet requête */
        request.setAttribute( ATT_COMMANDE, commande );
        request.setAttribute( ATT_FORM, form );

        /* Si aucune erreur */
        if ( form.getErreurs().isEmpty() ) {
            /* Alors récupération de la map des clients dans la session */
            HttpSession session = request.getSession();
            Map<String, Client> clients = (HashMap<String, Client>) session.getAttribute( SESSION_CLIENTS );
            /* Si aucune map n'existe, alors initialisation d'une nouvelle map */
            if ( clients == null ) {
                clients = new HashMap<String, Client>();
            }
            /* Puis ajout du client de la commande courante dans la map */
            clients.put( commande.getClient().getNom(), commande.getClient() );
            /* Et enfin (ré)enregistrement de la map en session */
            session.setAttribute( SESSION_CLIENTS, clients );

            /* Ensuite récupération de la map des commandes dans la session */
            Map<String, Commande> commandes = (HashMap<String, Commande>) session.getAttribute( SESSION_COMMANDES );
            /* Si aucune map n'existe, alors initialisation d'une nouvelle map */
            if ( commandes == null ) {
                commandes = new HashMap<String, Commande>();
            }
            /* Puis ajout de la commande courante dans la map */
            commandes.put( commande.getDate(), commande );
            /* Et enfin (ré)enregistrement de la map en session */
            session.setAttribute( SESSION_COMMANDES, commandes );

            /* Affichage de la fiche récapitulative */
            this.getServletContext().getRequestDispatcher( VUE_SUCCES ).forward( request, response );
        } else {
            /* Sinon, ré-affichage du formulaire de création avec les erreurs */
            this.getServletContext().getRequestDispatcher( VUE_FORM ).forward( request, response );
        }
    }
}

com.sdzee.tp.servlets.CreationCommande

Le code des objets métiers

Modification de l'objet gérant la création d'une commande :

  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
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
package com.sdzee.tp.forms;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import com.sdzee.tp.beans.Client;
import com.sdzee.tp.beans.Commande;

public final class CreationCommandeForm {
    private static final String CHAMP_CHOIX_CLIENT     = "choixNouveauClient";
    private static final String CHAMP_LISTE_CLIENTS    = "listeClients";
    private static final String CHAMP_DATE             = "dateCommande";
    private static final String CHAMP_MONTANT          = "montantCommande";
    private static final String CHAMP_MODE_PAIEMENT    = "modePaiementCommande";
    private static final String CHAMP_STATUT_PAIEMENT  = "statutPaiementCommande";
    private static final String CHAMP_MODE_LIVRAISON   = "modeLivraisonCommande";
    private static final String CHAMP_STATUT_LIVRAISON = "statutLivraisonCommande";

    private static final String ANCIEN_CLIENT          = "ancienClient";
    private static final String SESSION_CLIENTS        = "clients";
    private static final String FORMAT_DATE            = "dd/MM/yyyy HH:mm:ss";

    private String              resultat;
    private Map<String, String> erreurs                = new HashMap<String, String>();

    public Map<String, String> getErreurs() {
        return erreurs;
    }

    public String getResultat() {
        return resultat;
    }

    public Commande creerCommande( HttpServletRequest request ) {
        Client client;
        /*
         * Si l'utilisateur choisit un client déjà existant, pas de validation à
         * effectuer
         */
        String choixNouveauClient = getValeurChamp( request, CHAMP_CHOIX_CLIENT );
        if ( ANCIEN_CLIENT.equals( choixNouveauClient ) ) {
            /* Récupération du nom du client choisi */
            String nomAncienClient = getValeurChamp( request, CHAMP_LISTE_CLIENTS );
            /* Récupération de l'objet client correspondant dans la session */
            HttpSession session = request.getSession();
            client = ( (Map<String, Client>) session.getAttribute( SESSION_CLIENTS ) ).get( nomAncienClient );
        } else {
            /*
             * Sinon on garde l'ancien mode, pour la validation des champs.
             * 
             * L'objet métier pour valider la création d'un client existe déjà,
             * il est donc déconseillé de dupliquer ici son contenu ! À la
             * place, il suffit de passer la requête courante à l'objet métier
             * existant et de récupérer l'objet Client créé.
             */
            CreationClientForm clientForm = new CreationClientForm();
            client = clientForm.creerClient( request );

            /*
             * Et très important, il ne faut pas oublier de récupérer le contenu
             * de la map d'erreur créée par l'objet métier CreationClientForm
             * dans la map d'erreurs courante, actuellement vide.
             */
            erreurs = clientForm.getErreurs();
        }

        /*
         * Ensuite, il suffit de procéder normalement avec le reste des champs
         * spécifiques à une commande.
         */

        /*
         * Récupération et conversion de la date en String selon le format
         * choisi.
         */
        DateTime dt = new DateTime();
        DateTimeFormatter formatter = DateTimeFormat.forPattern( FORMAT_DATE );
        String date = dt.toString( formatter );

        String montant = getValeurChamp( request, CHAMP_MONTANT );
        String modePaiement = getValeurChamp( request, CHAMP_MODE_PAIEMENT );
        String statutPaiement = getValeurChamp( request, CHAMP_STATUT_PAIEMENT );
        String modeLivraison = getValeurChamp( request, CHAMP_MODE_LIVRAISON );
        String statutLivraison = getValeurChamp( request, CHAMP_STATUT_LIVRAISON );

        Commande commande = new Commande();

        commande.setClient( client );

        double valeurMontant = -1;
        try {
            valeurMontant = validationMontant( montant );
        } catch ( Exception e ) {
            setErreur( CHAMP_MONTANT, e.getMessage() );
        }
        commande.setMontant( valeurMontant );

        commande.setDate( date );

        try {
            validationModePaiement( modePaiement );
        } catch ( Exception e ) {
            setErreur( CHAMP_MODE_PAIEMENT, e.getMessage() );
        }
        commande.setModePaiement( modePaiement );

        try {
            validationStatutPaiement( statutPaiement );
        } catch ( Exception e ) {
            setErreur( CHAMP_STATUT_PAIEMENT, e.getMessage() );
        }
        commande.setStatutPaiement( statutPaiement );

        try {
            validationModeLivraison( modeLivraison );
        } catch ( Exception e ) {
            setErreur( CHAMP_MODE_LIVRAISON, e.getMessage() );
        }
        commande.setModeLivraison( modeLivraison );

        try {
            validationStatutLivraison( statutLivraison );
        } catch ( Exception e ) {
            setErreur( CHAMP_STATUT_LIVRAISON, e.getMessage() );
        }
        commande.setStatutLivraison( statutLivraison );

        if ( erreurs.isEmpty() ) {
            resultat = "Succès de la création de la commande.";
        } else {
            resultat = "Échec de la création de la commande.";
        }
        return commande;
    }

    private double validationMontant( String montant ) throws Exception {
        double temp;
        if ( montant != null ) {
            try {
                temp = Double.parseDouble( montant );
                if ( temp < 0 ) {
                    throw new Exception( "Le montant doit être un nombre positif." );
                }
            } catch ( NumberFormatException e ) {
                temp = -1;
                throw new Exception( "Le montant doit être un nombre." );
            }
        } else {
            temp = -1;
            throw new Exception( "Merci d'entrer un montant." );
        }
        return temp;
    }

    private void validationModePaiement( String modePaiement ) throws Exception {
        if ( modePaiement != null ) {
            if ( modePaiement.length() < 2 ) {
                throw new Exception( "Le mode de paiement doit contenir au moins 2 caractères." );
            }
        } else {
            throw new Exception( "Merci d'entrer un mode de paiement." );
        }
    }

    private void validationStatutPaiement( String statutPaiement ) throws Exception {
        if ( statutPaiement != null && statutPaiement.length() < 2 ) {
            throw new Exception( "Le statut de paiement doit contenir au moins 2 caractères." );
        }
    }

    private void validationModeLivraison( String modeLivraison ) throws Exception {
        if ( modeLivraison != null ) {
            if ( modeLivraison.length() < 2 ) {
                throw new Exception( "Le mode de livraison doit contenir au moins 2 caractères." );
            }
        } else {
            throw new Exception( "Merci d'entrer un mode de livraison." );
        }
    }

    private void validationStatutLivraison( String statutLivraison ) throws Exception {
        if ( statutLivraison != null && statutLivraison.length() < 2 ) {
            throw new Exception( "Le statut de livraison doit contenir au moins 2 caractères." );
        }
    }

    /*
     * Ajoute un message correspondant au champ spécifié à la map des erreurs.
     */
    private void setErreur( String champ, String message ) {
        erreurs.put( champ, message );
    }

    /*
     * Méthode utilitaire qui retourne null si un champ est vide, et son contenu
     * sinon.
     */
    private static String getValeurChamp( HttpServletRequest request, String nomChamp ) {
        String valeur = request.getParameter( nomChamp );
        if ( valeur == null || valeur.trim().length() == 0 ) {
            return null;
        } else {
            return valeur;
        }
    }
}

com.sdzee.tp.forms.CreationCommandeForm