Sixième étape du fil rouge, le temps est enfin venu pour vous d'intégrer une base de données à votre application ! Création de la base, des tables, des DAO associés et intégration dans l'application existante vous attendent.
Objectifs
Fonctionnalités
Vous allez mettre en place une base de données dans votre application. Ce changement va impliquer que :
- lors de la création d'un client ou d'une commande par l'utilisateur, les données ne seront maintenant plus seulement mises en session, mais également enregistrées dans la base ;
- vous allez rendre possible la création de clients portant le même nom, et de commandes passées à la même date ;
- les pages listant les clients et commandes existants continueront à se baser uniquement sur les données présentes en session ;
- la suppression d'un client ou d'une commande ne supprimera pas seulement les données de la session, mais également de la base.
C'est « tout » ce que je vous demande…
Conseils
Ne vous fiez pas à la faible longueur du sujet : énormément de travail et de réflexion vous attendent !
Création de la base de données
La première étape consiste à créer la base et les tables représentant les données de votre application. Ceci ne faisant pas directement l'objet de ce cours, je vais vous accompagner en vous détaillant chaque instruction. Suivez le guide !
Connexion au serveur MySQL
Connectez-vous à votre serveur via la commande mysql -h localhost -u root -p
, puis entrez votre mot de passe le cas échéant.
Création d'une base
Mettez en place une nouvelle base de données nommée tp_sdzee à l'aide de l'instruction suivante :
1 | CREATE DATABASE tp_sdzee DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; |
Mise en place des droits
Vous savez qu'utiliser le compte root est une mauvaise pratique, vous devez donc accorder des droits sur la nouvelle table à l'utilisateur java créé dans le cadre du cours, via l'instruction suivante :
1 | GRANT ALL ON tp_sdzee.* TO 'java'@'localhost' IDENTIFIED BY 'SdZ_eE'; |
Vous devez ensuite vous déconnecter de l'utilisateur root via la commande exit
, puis vous reconnecter avec votre compte java via la commande mysql -h localhost -u java -p
, entrer le mot de passe et enfin entrer la commande use tp_sdzee
pour définir la base sur laquelle vous allez travailler.
Création des tables
Vous devez alors créer une table Client contenant les champs id, nom, prenom, adresse, telephone, email et image. Voici un exemple d'instruction que vous pouvez utiliser pour cela :
1 2 3 4 5 6 7 8 9 10 | CREATE TABLE tp_sdzee.Client ( id INT( 11 ) NOT NULL AUTO_INCREMENT , nom VARCHAR( 20 ) NOT NULL , prenom VARCHAR( 20 ) , adresse VARCHAR( 200 ) NOT NULL , telephone VARCHAR( 10 ) NOT NULL, email VARCHAR( 60 ) , image VARCHAR( 200 ) , PRIMARY KEY ( id ) ) ENGINE = INNODB; |
Rien de particulier ici, remarquez simplement la mise en place d'un champ id pour identifier chaque client.
De même, vous devez créer une table Commande contenant les champs id, id_client, date, montant, modePaiement, statutPaiement, modeLivraison et statutLivraison :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | CREATE TABLE tp_sdzee.Commande ( id INT( 11 ) NOT NULL AUTO_INCREMENT , id_client INT( 11 ) , date DATETIME NOT NULL , montant DEC( 11 ) NOT NULL , mode_paiement VARCHAR( 20 ) NOT NULL , statut_paiement VARCHAR( 20 ) , mode_livraison VARCHAR( 20 ) NOT NULL , statut_livraison VARCHAR( 20 ) , PRIMARY KEY ( id ) , CONSTRAINT fk_id_client -- On donne un nom à notre clé FOREIGN KEY (id_client) -- Colonne sur laquelle on crée la clé REFERENCES Client(id) -- Colonne de référence (celle de la table Client) ON DELETE SET NULL -- Action à effectuer lors de la suppression d'une référence ) ENGINE = INNODB; |
Première chose, vous remarquez ici que vous n'allez pas enregistrer les données des clients directement dans la table Commande, mais uniquement leur id dans le champ id_client. Les clients existant déjà dans la table Client, il serait idiot de dupliquer les données !
Deuxième chose, observez en fin d'instruction la mise en place d'une contrainte de clé étrangère sur le champ id_client. Grâce à cette clé, le SGBD sait que le contenu du champ id_client correspond à un id existant dans la table Client.
Enfin, ne manquez pas l'option de la clé étrangère ! Puisqu'une relation est définie par le SGBD entre une commande et son client, il devient impossible par défaut de supprimer un client s'il a déjà passé une commande. Dans le cadre de ce TP, ce n'est pas très ergonomique : vous allez donc devoir changer ce comportement, en précisant que lors de la suppression d'un client, les champs id_client de la table Commande qui y font référence devront passer automatiquement à NULL
. C'est le rôle de la ligne ON DELETE SET NULL
.
Si vous le souhaitez, vous pouvez changer le comportement adopté ici. Vous pouvez par exemple faire en sorte qu'il soit impossible de supprimer un client s'il a déjà passé une commande, ou bien encore faire en sorte que lors de la suppression d'un client, toutes les commandes qu'il a passées soient supprimées. Tout cela est simplement paramétrable via l'option appliquée sur la clé étrangère mise en place !
En construisant ainsi vos tables, vous allez pouvoir vous assurer que les données écrites dans votre base sont cohérentes.
Mise en place de JDBC
Si ce n'est pas déjà fait, vous allez devoir placer le jar du driver JDBC pour MySQL dans le dossier /lib de Tomcat, afin que votre application puisse communiquer avec votre base de données.
Réutilisation de la structure DAO développée dans le cadre du cours
Votre base de données est en place. Vous pouvez maintenant attaquer le développement de votre application. Pour commencer, une bonne nouvelle : vous allez pouvoir réutiliser certaines classes du package com.sdzee.dao
que vous avez développées dans le cadre du cours ! Les voici :
- DAOConfigurationException.java
- DAOException.java
- DAOUtilitaire.java
En effet, inutile de réinventer la roue pour toutes celles-là : elles fonctionnent, vous avez passé du temps à les mettre en place, autant s'en resservir ! Vous pouvez donc créer un package com.sdzee.tp.dao
dans votre projet et y copier chacune d'elles.
De même, vous allez pouvoir réutiliser la classe InitialisationDaoFactory.java et la placer dans un nouveau package com.sdzee.tp.config
.
Enfin, il reste deux fichiers que vous allez pouvoir réutiliser, moyennant quelques petits ajustements :
- vous pouvez reprendre le fichier dao.properties, mais il faudra bien penser à changer le contenu de son entrée url, pour cibler la nouvelle base tp_sdzee que vous avez créée, et non plus bdd_sdzee comme c'était le cas dans le cadre du cours ;
- vous pouvez de même reprendre la classe DAOFactory.java, mais vous allez devoir y changer le chemin vers le fichier dao.properties défini dans la constante FICHIER_PROPERTIES.
Prenez bien le temps de mettre cette structure en place, n'allez pas trop vite et vérifiez que tout est bien au bon endroit avant de poursuivre !
Création des interfaces et implémentations du DAO
Maintenant que le cadre est en place, vous allez devoir mettre la main à la pâte et coder les classes du DAO spécifiques à votre projet :
- l'interface ClientDao et son implémentation ClientDaoImpl ;
- l'interface CommandeDao et son implémentation CommandeDaoImpl.
Les interfaces
Dans le cadre de ce TP, vous n'avez pas développé de formulaires pour la modification des données existantes. Ainsi, vous n'avez pas besoin de définir toutes les méthodes CRUD dans vos DAO. Vous pouvez vous contenter des méthodes creer()
, trouver()
, lister()
et supprimer()
. Inspirez-vous de ce que vous avez mis en place dans le chapitre précédent si vous ne vous souvenez plus comment procéder.
Les implémentations
Vous allez devoir définir les requêtes SQL à effectuer sur vos tables, créer et manipuler des requêtes préparées depuis vos différentes méthodes, tout cela bien entendu en réutilisant les méthodes développées dans la classe DAOUtilitaire. Vous pouvez, là encore, vous inspirer grandement de ce que vous avez développé dans le chapitre précédent, mais vous devrez prendre garde à modifier les méthodes map()
, à créer une méthode lister()
et à bien ajuster les méthodes trouver()
et creer()
, et enfin supprimer()
!
Afin de vous permettre de partir du bon pied, je vous donne ici les requêtes à utiliser respectivement dans les classes ClientDaoImpl et CommandeDaoImpl :
1 2 3 4 | private static final String SQL_SELECT = "SELECT id, nom, prenom, adresse, telephone, email, image FROM Client ORDER BY id"; private static final String SQL_SELECT_PAR_ID = "SELECT id, nom, prenom, adresse, telephone, email, image FROM Client WHERE id = ?"; private static final String SQL_INSERT = "INSERT INTO Client (nom, prenom, adresse, telephone, email, image) VALUES (?, ?, ?, ?, ?, ?)"; private static final String SQL_DELETE_PAR_ID = "DELETE FROM Client WHERE id = ?"; |
Constantes définissant les requêtes dans ClientDaoImpl
1 2 3 4 | private static final String SQL_SELECT = "SELECT id, id_client, date, montant, mode_paiement, statut_paiement, mode_livraison, statut_livraison FROM Commande ORDER BY id"; private static final String SQL_SELECT_PAR_ID = "SELECT id, id_client, date, montant, mode_paiement, statut_paiement, mode_livraison, statut_livraison FROM Commande WHERE id = ?"; private static final String SQL_INSERT = "INSERT INTO Commande (id_client, date, montant, mode_paiement, statut_paiement, mode_livraison, statut_livraison) VALUES (?, ?, ?, ?, ?, ?, ?)"; private static final String SQL_DELETE_PAR_ID = "DELETE FROM Commande WHERE id = ?"; |
Constantes définissant les requêtes dans CommandeDaoImpl
Avec ceci en poche, vous n'avez plus à vous soucier de l'aspect SQL du développement, et vous pouvez vous concentrer sur l'aspect… Java EE !
Intégration dans le code existant
Afin d'intégrer correctement vos DAO dans l'application, vous allez devoir procéder à de nombreux changements dans le code existant…
Modification des beans
Vous allez devoir apporter deux changements :
- ajouter un champ id de type
Long
aux deux beans, pour refléter l'id auto-généré existant dans vos tables ; - modifier le type du champ date dans le bean Commande. Jusqu'à présent vous stockiez cette information sous forme d'une chaîne de caractères pour ne pas vous compliquer la tâche, mais cette fois vous allez devoir faire correspondre ce champ à celui créé dans la table Commande. Puisque nous utilisons la bibliothèque JodaTime, je vous conseille de changer le type du champ date de
String
versDateTime
.
Modification des servlets
Vous allez devoir adapter vos servlets CreationClient et CreationCommande, toujours sur le modèle de ce que vous avez développé dans le cours :
- récupérer la ou les implémentations de DAO depuis la factory, dans la méthode
init()
de chaque servlet ; - passage du ou des DAO à l'objet métier lors de sa construction.
En outre, vous allez devoir apporter un autre changement, qui va avoir un impact considérable sur le reste de l’application. Jusqu'à présent, vous manipuliez des Map
indexées sur les noms et dates des clients et commandes, ce qui rendait impossible la création de deux clients portant le même nom et la création de deux commandes au même instant.
Maintenant que vos données sont identifiables par un id dans vos tables, vous allez pouvoir modifier vos Map
pour qu'elles indexent les id des clients et commandes. Vos Map
vont donc changer de Map<String, Client>
et Map<String, Commande>
vers Map<Long, Client>
et Map<Long, Commande>
. Vous allez donc devoir prendre garde, partout où ces maps sont manipulées, à ne plus travailler sur les noms et dates, mais bien sur les id. Ne prenez pas ce changement à la légère, il va impliquer pas mal de petites modifications ça et là… !
Vous allez également devoir modifier vos servlets de suppression :
- pour qu'elles se basent sur l'id lors de la suppression d'une entrée dans une
Map
, suite à la modification apportée précédemment ; - pour qu'elles suppriment également les données en base, ceci implique donc la récupération du DAO depuis la méthode
init()
et un appel à la méthodesupprimer()
du DAO.
Modification des objets métier
Vous allez devoir reprendre vos deux objets métier CreationClientForm et CreationCommandeForm pour qu'ils interagissent avec la BDD. Là encore, vous pouvez vous inspirer grandement de ce que vous avez développé dans le chapitre précédent. Dans les grandes lignes, il va vous falloir :
- récupérer la ou les instances de DAO nécessaires depuis le constructeur ;
- effectuer un appel à la méthode
creer()
du DAO une fois la validation des champs passée avec succès, et gérer les éventuelles erreurs ou exceptions retournées.
Attention dans le code de CreationCommandeForm ! Vous devrez prendre garde à bien adapter la manipulation de la Map
des clients, suite aux changements que vous avez apportés au maps définies dans vos servlets !
Modification des JSP
Premièrement, il va falloir adapter vos JSP aux changements effectués sur vos maps de clients et commandes. Dans les pages listerClients.jsp et listerCommandes.jsp, vous allez donc devoir modifier les liens de suppression pour qu'ils ne transmettent plus le nom d'un client ou la date d'une commande, mais leur id.
Deuxièmement, vous allez devoir modifier la manière dont vous affichez le champ date du bean Commande ! Eh oui, maintenant que vous l'avez remplacé par un objet Joda DateTime, vous ne pouvez plus vous contenter de l'afficher bêtement via la balise <c:out>
… Pas de panique, les développeurs de Joda ont pensé à ce cas de figure et ont créé une bibliothèque de balises destinées à manipuler les objets Joda !
Vous devez donc télécharger son jar en cliquant sur ce lien, puis le placer dans le répertoire /WEB-INF/lib de votre projet. Ensuite, vous allez pouvoir utiliser les balises comme vous utilisez celles de la JSTL. Voici un exemple d'utilisation, qui se charge de formater un objet DateTime pour affichage à l'utilisateur selon un pattern défini :
1 2 3 4 5 | <%@ taglib prefix="joda" uri="http://www.joda.org/joda/time/tags" %> ... <joda:format value="${ commande.date }" pattern="dd/MM/yyyy HH:mm:ss"/> |
Exemple d'utilisation d'une balise de la bibliothèque Joda
Je vous invite bien entendu à parcourir la documentation du projet plus en profondeur pour découvrir les différentes balises et attributs disponibles.
Création d'un filtre
Enfin, il reste un aspect important à changer dans le mode de fonctionnement de votre application. Je vous ai demandé de faire en sorte que vos pages listant les commandes et clients existants continuent à se baser sur les infos présentes en session. Il va donc falloir réfléchir un petit peu à la manière de procéder ici. En effet, au tout premier lancement de l'application, aucun problème : aucune donnée n'existe, et donc rien n'existe en session.
Imaginez maintenant que l'utilisateur crée tout un tas de clients et commandes, puis quitte l'application et ne revient pas pendant une semaine. À son retour, la session n'existera plus depuis belle lurette sur le serveur, qui aura tôt fait de la supprimer. Ainsi, les pages listant les clients et commandes n'afficheront rien, alors qu'en réalité il existe des données, non pas dans la session, mais dans la base de données !
Ce qu'il vous faut gérer, c'est donc le préchargement des données existant en base dans la session de l'utilisateur lors de son arrivée, et uniquement lors de son arrivée, sur n'importe quelle page de l'application.
Comment réaliser une telle opération ?
En principe, vous avez déjà la réponse à cette question ! Réfléchissez bien. Quel composant est idéal pour ce type de fonctionnalité ? Eh oui, c'est le filtre ! Vous allez donc créer un filtre appliqué à toutes les pages de votre application, qui se chargera de vérifier si une session utilisateur existe, et qui la remplira avec les données présentes en base si elle n'existe pas. En somme, vous allez y récupérer une implémentation de DAO comme vous l'avez déjà fait pour les servlets, effectuer un appel à sa méthode lister()
, et peupler les maps de clients et de commandes avec les données contenues dans les listes récupérées !
N'oubliez pas de bien déclarer le filtre dans le fichier web.xml !
Voilà tout ce dont vous avez besoin. Comme vous le voyez, le sujet était très court, mais en réalité le travail est conséquent !
Correction
Faites attention à bien reprendre les fichiers du cours qui restent inchangés, à corriger les quelques classes qui nécessitent des ajustements, et surtout ne baissez pas les bras devant la charge de travail impliquée par l'introduction d'une base de données dans votre programme ! Cet exercice est l'occasion parfaite pour vous familiariser avec ces concepts si importants. Ne la gâchez pas en abandonnant dès le moindre petit obstacle !
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 !
Prenez le temps de réfléchir, de chercher et de coder par vous-mêmes. Si besoin, n'hésitez pas à relire le sujet ou à retourner lire les chapitres précédents. La pratique est très importante, ne vous ruez pas sur la solution !
Code de la structure DAO
Voici les liens directs vers les fichiers que vous devez reprendre tels quels depuis le chapitre précédent :
- InitialisationDaoFactory (inchangé)
- DAOConfigurationException (inchangé)
- DAOException (inchangé)
- DAOUtilitaire (inchangé)
Voilà le contenu du nouveau fichier dao.properties, à placer dans com.sdzee.tp.dao
:
1 2 3 4 | url = jdbc:mysql://localhost:3306/tp_sdzee driver = com.mysql.jdbc.Driver nomutilisateur = java motdepasse = SdZ_eE |
dao.properties
Et voilà le code de la classe DAOFactory adapté à ce nouveau fichier Properties et au nouveau projet :
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 | package com.sdzee.tp.dao; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; public class DAOFactory { private static final String FICHIER_PROPERTIES = "/com/sdzee/tp/dao/dao.properties"; private static final String PROPERTY_URL = "url"; private static final String PROPERTY_DRIVER = "driver"; private static final String PROPERTY_NOM_UTILISATEUR = "nomutilisateur"; private static final String PROPERTY_MOT_DE_PASSE = "motdepasse"; private String url; private String username; private String password; /* package */DAOFactory( String url, String username, String password ) { this.url = url; this.username = username; this.password = password; } /* * Méthode chargée de récupérer les informations de connexion à la base de * données, charger le driver JDBC et retourner une instance de la Factory */ public static DAOFactory getInstance() throws DAOConfigurationException { Properties properties = new Properties(); String url; String driver; String nomUtilisateur; String motDePasse; ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); InputStream fichierProperties = classLoader.getResourceAsStream( FICHIER_PROPERTIES ); if ( fichierProperties == null ) { throw new DAOConfigurationException( "Le fichier properties " + FICHIER_PROPERTIES + " est introuvable." ); } try { properties.load( fichierProperties ); url = properties.getProperty( PROPERTY_URL ); driver = properties.getProperty( PROPERTY_DRIVER ); nomUtilisateur = properties.getProperty( PROPERTY_NOM_UTILISATEUR ); motDePasse = properties.getProperty( PROPERTY_MOT_DE_PASSE ); } catch ( FileNotFoundException e ) { throw new DAOConfigurationException( "Le fichier properties " + FICHIER_PROPERTIES + " est introuvable.", e ); } catch ( IOException e ) { throw new DAOConfigurationException( "Impossible de charger le fichier properties " + FICHIER_PROPERTIES, e ); } try { Class.forName( driver ); } catch ( ClassNotFoundException e ) { throw new DAOConfigurationException( "Le driver est introuvable dans le classpath.", e ); } DAOFactory instance = new DAOFactory( url, nomUtilisateur, motDePasse ); return instance; } /* Méthode chargée de fournir une connexion à la base de données */ /* package */Connection getConnection() throws SQLException { return DriverManager.getConnection( url, username, password ); } /* * Méthodes de récupération de l'implémentation des différents DAO * (uniquement deux dans le cadre de ce TP) */ public ClientDao getClientDao() { return new ClientDaoImpl( this ); } public CommandeDao getCommandeDao() { return new CommandeDaoImpl( this ); } } |
com.sdzee.tp.dao.DAOFactory
Code des interfaces DAO
L'interface ClientDao :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | package com.sdzee.tp.dao; import java.util.List; import com.sdzee.tp.beans.Client; public interface ClientDao { void creer( Client client ) throws DAOException; Client trouver( long id ) throws DAOException; List<Client> lister() throws DAOException; void supprimer( Client client ) throws DAOException; } |
com.sdzee.tp.dao.ClientDao
L'interface CommandeDao :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | package com.sdzee.tp.dao; import java.util.List; import com.sdzee.tp.beans.Commande; public interface CommandeDao { void creer( Commande commande ) throws DAOException; Commande trouver( long id ) throws DAOException; List<Commande> lister() throws DAOException; void supprimer( Commande commande ) throws DAOException; } |
com.sdzee.tp.dao.CommandeDao
Code des implémentations DAO
Code de ClientDaoImpl :
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 | package com.sdzee.tp.dao; import static com.sdzee.tp.dao.DAOUtilitaire.fermeturesSilencieuses; import static com.sdzee.tp.dao.DAOUtilitaire.initialisationRequetePreparee; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import com.sdzee.tp.beans.Client; public class ClientDaoImpl implements ClientDao { private static final String SQL_SELECT = "SELECT id, nom, prenom, adresse, telephone, email, image FROM Client ORDER BY id"; private static final String SQL_SELECT_PAR_ID = "SELECT id, nom, prenom, adresse, telephone, email, image FROM Client WHERE id = ?"; private static final String SQL_INSERT = "INSERT INTO Client (nom, prenom, adresse, telephone, email, image) VALUES (?, ?, ?, ?, ?, ?)"; private static final String SQL_DELETE_PAR_ID = "DELETE FROM Client WHERE id = ?"; private DAOFactory daoFactory; ClientDaoImpl( DAOFactory daoFactory ) { this.daoFactory = daoFactory; } /* Implémentation de la méthode définie dans l'interface ClientDao */ @Override public Client trouver( long id ) throws DAOException { return trouver( SQL_SELECT_PAR_ID, id ); } /* Implémentation de la méthode définie dans l'interface ClientDao */ @Override public void creer( Client client ) throws DAOException { Connection connexion = null; PreparedStatement preparedStatement = null; ResultSet valeursAutoGenerees = null; try { connexion = daoFactory.getConnection(); preparedStatement = initialisationRequetePreparee( connexion, SQL_INSERT, true, client.getNom(), client.getPrenom(), client.getAdresse(), client.getTelephone(), client.getEmail(), client.getImage() ); int statut = preparedStatement.executeUpdate(); if ( statut == 0 ) { throw new DAOException( "Échec de la création du client, aucune ligne ajoutée dans la table." ); } valeursAutoGenerees = preparedStatement.getGeneratedKeys(); if ( valeursAutoGenerees.next() ) { client.setId( valeursAutoGenerees.getLong( 1 ) ); } else { throw new DAOException( "Échec de la création du client en base, aucun ID auto-généré retourné." ); } } catch ( SQLException e ) { throw new DAOException( e ); } finally { fermeturesSilencieuses( valeursAutoGenerees, preparedStatement, connexion ); } } /* Implémentation de la méthode définie dans l'interface ClientDao */ @Override public List<Client> lister() throws DAOException { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; List<Client> clients = new ArrayList<Client>(); try { connection = daoFactory.getConnection(); preparedStatement = connection.prepareStatement( SQL_SELECT ); resultSet = preparedStatement.executeQuery(); while ( resultSet.next() ) { clients.add( map( resultSet ) ); } } catch ( SQLException e ) { throw new DAOException( e ); } finally { fermeturesSilencieuses( resultSet, preparedStatement, connection ); } return clients; } /* Implémentation de la méthode définie dans l'interface ClientDao */ @Override public void supprimer( Client client ) throws DAOException { Connection connexion = null; PreparedStatement preparedStatement = null; try { connexion = daoFactory.getConnection(); preparedStatement = initialisationRequetePreparee( connexion, SQL_DELETE_PAR_ID, true, client.getId() ); int statut = preparedStatement.executeUpdate(); if ( statut == 0 ) { throw new DAOException( "Échec de la suppression du client, aucune ligne supprimée de la table." ); } else { client.setId( null ); } } catch ( SQLException e ) { throw new DAOException( e ); } finally { fermeturesSilencieuses( preparedStatement, connexion ); } } /* * Méthode générique utilisée pour retourner un client depuis la base de * données, correspondant à la requête SQL donnée prenant en paramètres les * objets passés en argument. */ private Client trouver( String sql, Object... objets ) throws DAOException { Connection connexion = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; Client client = null; try { /* Récupération d'une connexion depuis la Factory */ connexion = daoFactory.getConnection(); /* * Préparation de la requête avec les objets passés en arguments * (ici, uniquement un id) et exécution. */ preparedStatement = initialisationRequetePreparee( connexion, sql, false, objets ); resultSet = preparedStatement.executeQuery(); /* Parcours de la ligne de données retournée dans le ResultSet */ if ( resultSet.next() ) { client = map( resultSet ); } } catch ( SQLException e ) { throw new DAOException( e ); } finally { fermeturesSilencieuses( resultSet, preparedStatement, connexion ); } return client; } /* * Simple méthode utilitaire permettant de faire la correspondance (le * mapping) entre une ligne issue de la table des clients (un ResultSet) et * un bean Client. */ private static Client map( ResultSet resultSet ) throws SQLException { Client client = new Client(); client.setId( resultSet.getLong( "id" ) ); client.setNom( resultSet.getString( "nom" ) ); client.setPrenom( resultSet.getString( "prenom" ) ); client.setAdresse( resultSet.getString( "adresse" ) ); client.setTelephone( resultSet.getString( "telephone" ) ); client.setEmail( resultSet.getString( "email" ) ); client.setImage( resultSet.getString( "image" ) ); return client; } } |
com.sdzee.tp.dao.ClientDaoImpl
Code de CommandeDaoImpl :
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 | package com.sdzee.tp.dao; import static com.sdzee.tp.dao.DAOUtilitaire.fermeturesSilencieuses; import static com.sdzee.tp.dao.DAOUtilitaire.initialisationRequetePreparee; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; import org.joda.time.DateTime; import com.sdzee.tp.beans.Commande; public class CommandeDaoImpl implements CommandeDao { private static final String SQL_SELECT = "SELECT id, id_client, date, montant, mode_paiement, statut_paiement, mode_livraison, statut_livraison FROM Commande ORDER BY id"; private static final String SQL_SELECT_PAR_ID = "SELECT id, id_client, date, montant, mode_paiement, statut_paiement, mode_livraison, statut_livraison FROM Commande WHERE id = ?"; private static final String SQL_INSERT = "INSERT INTO Commande (id_client, date, montant, mode_paiement, statut_paiement, mode_livraison, statut_livraison) VALUES (?, ?, ?, ?, ?, ?, ?)"; private static final String SQL_DELETE_PAR_ID = "DELETE FROM Commande WHERE id = ?"; private DAOFactory daoFactory; CommandeDaoImpl( DAOFactory daoFactory ) { this.daoFactory = daoFactory; } /* Implémentation de la méthode définie dans l'interface CommandeDao */ @Override public Commande trouver( long id ) throws DAOException { return trouver( SQL_SELECT_PAR_ID, id ); } /* Implémentation de la méthode définie dans l'interface CommandeDao */ @Override public void creer( Commande commande ) throws DAOException { Connection connexion = null; PreparedStatement preparedStatement = null; ResultSet valeursAutoGenerees = null; try { connexion = daoFactory.getConnection(); preparedStatement = initialisationRequetePreparee( connexion, SQL_INSERT, true, commande.getClient().getId(), new Timestamp( commande.getDate().getMillis() ), commande.getMontant(), commande.getModePaiement(), commande.getStatutPaiement(), commande.getModeLivraison(), commande.getStatutLivraison() ); int statut = preparedStatement.executeUpdate(); if ( statut == 0 ) { throw new DAOException( "Échec de la création de la commande, aucune ligne ajoutée dans la table." ); } valeursAutoGenerees = preparedStatement.getGeneratedKeys(); if ( valeursAutoGenerees.next() ) { commande.setId( valeursAutoGenerees.getLong( 1 ) ); } else { throw new DAOException( "Échec de la création de la commande en base, aucun ID auto-généré retourné." ); } } catch ( SQLException e ) { throw new DAOException( e ); } finally { fermeturesSilencieuses( valeursAutoGenerees, preparedStatement, connexion ); } } /* Implémentation de la méthode définie dans l'interface ClientDao */ @Override public List<Commande> lister() throws DAOException { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; List<Commande> commandes = new ArrayList<Commande>(); try { connection = daoFactory.getConnection(); preparedStatement = connection.prepareStatement( SQL_SELECT ); resultSet = preparedStatement.executeQuery(); while ( resultSet.next() ) { commandes.add( map( resultSet ) ); } } catch ( SQLException e ) { throw new DAOException( e ); } finally { fermeturesSilencieuses( resultSet, preparedStatement, connection ); } return commandes; } /* Implémentation de la méthode définie dans l'interface CommandeDao */ @Override public void supprimer( Commande commande ) throws DAOException { Connection connexion = null; PreparedStatement preparedStatement = null; try { connexion = daoFactory.getConnection(); preparedStatement = initialisationRequetePreparee( connexion, SQL_DELETE_PAR_ID, true, commande.getId() ); int statut = preparedStatement.executeUpdate(); if ( statut == 0 ) { throw new DAOException( "Échec de la suppression de la commande, aucune ligne supprimée de la table." ); } else { commande.setId( null ); } } catch ( SQLException e ) { throw new DAOException( e ); } finally { fermeturesSilencieuses( preparedStatement, connexion ); } } /* * Méthode générique utilisée pour retourner une commande depuis la base de * données, correspondant à la requête SQL donnée prenant en paramètres les * objets passés en argument. */ private Commande trouver( String sql, Object... objets ) throws DAOException { Connection connexion = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; Commande commande = null; try { /* Récupération d'une connexion depuis la Factory */ connexion = daoFactory.getConnection(); /* * Préparation de la requête avec les objets passés en arguments * (ici, uniquement un id) et exécution. */ preparedStatement = initialisationRequetePreparee( connexion, sql, false, objets ); resultSet = preparedStatement.executeQuery(); /* Parcours de la ligne de données retournée dans le ResultSet */ if ( resultSet.next() ) { commande = map( resultSet ); } } catch ( SQLException e ) { throw new DAOException( e ); } finally { fermeturesSilencieuses( resultSet, preparedStatement, connexion ); } return commande; } /* * Simple méthode utilitaire permettant de faire la correspondance (le * mapping) entre une ligne issue de la table des commandes (un ResultSet) * et un bean Commande. */ private Commande map( ResultSet resultSet ) throws SQLException { Commande commande = new Commande(); commande.setId( resultSet.getLong( "id" ) ); /* * Petit changement ici : pour récupérer un client, il nous faut faire * appel à la méthode trouver() du DAO Client, afin de récupérer un bean * Client à partir de l'id présent dans la table Commande. */ ClientDao clientDao = daoFactory.getClientDao(); commande.setClient( clientDao.trouver( resultSet.getLong( "id_client" ) ) ); commande.setDate( new DateTime( resultSet.getTimestamp( "date" ) ) ); commande.setMontant( resultSet.getDouble( "montant" ) ); commande.setModePaiement( resultSet.getString( "mode_paiement" ) ); commande.setStatutPaiement( resultSet.getString( "statut_paiement" ) ); commande.setModeLivraison( resultSet.getString( "mode_livraison" ) ); commande.setStatutLivraison( resultSet.getString( "statut_livraison" ) ); return commande; } } |
com.sdzee.tp.dao.CommandeDaoImpl
Code des beans
Client :
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 | package com.sdzee.tp.beans; import java.io.Serializable; public class Client implements Serializable { private Long id; private String nom; private String prenom; private String adresse; private String telephone; private String email; private String image; public void setId( Long id ) { this.id = id; } public Long getId() { return id; } public void setNom( String nom ) { this.nom = nom; } public String getNom() { return nom; } public void setPrenom( String prenom ) { this.prenom = prenom; } public String getPrenom() { return prenom; } public void setAdresse( String adresse ) { this.adresse = adresse; } public String getAdresse() { return adresse; } public void setTelephone( String telephone ) { this.telephone = telephone; } public String getTelephone() { return telephone; } public void setEmail( String email ) { this.email = email; } public String getEmail() { return email; } public void setImage( String image ) { this.image = image; } public String getImage() { return image; } } |
com.sdzee.tp.beans.Client
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 | package com.sdzee.tp.beans; import java.io.Serializable; import org.joda.time.DateTime; public class Commande implements Serializable { private Long id; private Client client; private DateTime date; private Double montant; private String modePaiement; private String statutPaiement; private String modeLivraison; private String statutLivraison; public Long getId() { return id; } public void setId( Long id ) { this.id = id; } public Client getClient() { return client; } public void setClient( Client client ) { this.client = client; } public DateTime getDate() { return date; } public void setDate( DateTime date ) { this.date = date; } public Double getMontant() { return montant; } public void setMontant( Double montant ) { this.montant = montant; } public String getModePaiement() { return modePaiement; } public void setModePaiement( String modePaiement ) { this.modePaiement = modePaiement; } public String getStatutPaiement() { return statutPaiement; } public void setStatutPaiement( String statutPaiement ) { this.statutPaiement = statutPaiement; } public String getModeLivraison() { return modeLivraison; } public void setModeLivraison( String modeLivraison ) { this.modeLivraison = modeLivraison; } public String getStatutLivraison() { return statutLivraison; } public void setStatutLivraison( String statutLivraison ) { this.statutLivraison = statutLivraison; } } |
com.sdzee.tp.beans.Commande
Code des objets métier
Code de CreationClientForm :
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 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | package com.sdzee.tp.forms; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Part; import com.sdzee.tp.beans.Client; import com.sdzee.tp.dao.ClientDao; import com.sdzee.tp.dao.DAOException; import eu.medsea.mimeutil.MimeUtil; public final class CreationClientForm { private static final String CHAMP_NOM = "nomClient"; private static final String CHAMP_PRENOM = "prenomClient"; private static final String CHAMP_ADRESSE = "adresseClient"; private static final String CHAMP_TELEPHONE = "telephoneClient"; private static final String CHAMP_EMAIL = "emailClient"; private static final String CHAMP_IMAGE = "imageClient"; private static final int TAILLE_TAMPON = 10240; // 10ko private String resultat; private Map<String, String> erreurs = new HashMap<String, String>(); private ClientDao clientDao; public CreationClientForm( ClientDao clientDao ) { this.clientDao = clientDao; } public Map<String, String> getErreurs() { return erreurs; } public String getResultat() { return resultat; } public Client creerClient( HttpServletRequest request, String chemin ) { String nom = getValeurChamp( request, CHAMP_NOM ); String prenom = getValeurChamp( request, CHAMP_PRENOM ); String adresse = getValeurChamp( request, CHAMP_ADRESSE ); String telephone = getValeurChamp( request, CHAMP_TELEPHONE ); String email = getValeurChamp( request, CHAMP_EMAIL ); Client client = new Client(); traiterNom( nom, client ); traiterPrenom( prenom, client ); traiterAdresse( adresse, client ); traiterTelephone( telephone, client ); traiterEmail( email, client ); traiterImage( client, request, chemin ); try { if ( erreurs.isEmpty() ) { clientDao.creer( client ); resultat = "Succès de la création du client."; } else { resultat = "Échec de la création du client."; } } catch ( DAOException e ) { setErreur( "imprévu", "Erreur imprévue lors de la création." ); resultat = "Échec de la création du client : une erreur imprévue est survenue, merci de réessayer dans quelques instants."; e.printStackTrace(); } return client; } private void traiterNom( String nom, Client client ) { try { validationNom( nom ); } catch ( FormValidationException e ) { setErreur( CHAMP_NOM, e.getMessage() ); } client.setNom( nom ); } private void traiterPrenom( String prenom, Client client ) { try { validationPrenom( prenom ); } catch ( FormValidationException e ) { setErreur( CHAMP_PRENOM, e.getMessage() ); } client.setPrenom( prenom ); } private void traiterAdresse( String adresse, Client client ) { try { validationAdresse( adresse ); } catch ( FormValidationException e ) { setErreur( CHAMP_ADRESSE, e.getMessage() ); } client.setAdresse( adresse ); } private void traiterTelephone( String telephone, Client client ) { try { validationTelephone( telephone ); } catch ( FormValidationException e ) { setErreur( CHAMP_TELEPHONE, e.getMessage() ); } client.setTelephone( telephone ); } private void traiterEmail( String email, Client client ) { try { validationEmail( email ); } catch ( FormValidationException e ) { setErreur( CHAMP_EMAIL, e.getMessage() ); } client.setEmail( email ); } private void traiterImage( Client client, HttpServletRequest request, String chemin ) { String image = null; try { image = validationImage( request, chemin ); } catch ( FormValidationException e ) { setErreur( CHAMP_IMAGE, e.getMessage() ); } client.setImage( image ); } private void validationNom( String nom ) throws FormValidationException { if ( nom != null ) { if ( nom.length() < 2 ) { throw new FormValidationException( "Le nom d'utilisateur doit contenir au moins 2 caractères." ); } } else { throw new FormValidationException( "Merci d'entrer un nom d'utilisateur." ); } } private void validationPrenom( String prenom ) throws FormValidationException { if ( prenom != null && prenom.length() < 2 ) { throw new FormValidationException( "Le prénom d'utilisateur doit contenir au moins 2 caractères." ); } } private void validationAdresse( String adresse ) throws FormValidationException { if ( adresse != null ) { if ( adresse.length() < 10 ) { throw new FormValidationException( "L'adresse de livraison doit contenir au moins 10 caractères." ); } } else { throw new FormValidationException( "Merci d'entrer une adresse de livraison." ); } } private void validationTelephone( String telephone ) throws FormValidationException { if ( telephone != null ) { if ( !telephone.matches( "^\\d+$" ) ) { throw new FormValidationException( "Le numéro de téléphone doit uniquement contenir des chiffres." ); } else if ( telephone.length() < 4 ) { throw new FormValidationException( "Le numéro de téléphone doit contenir au moins 4 chiffres." ); } } else { throw new FormValidationException( "Merci d'entrer un numéro de téléphone." ); } } private void validationEmail( String email ) throws FormValidationException { if ( email != null && !email.matches( "([^.@]+)(\\.[^.@]+)*@([^.@]+\\.)+([^.@]+)" ) ) { throw new FormValidationException( "Merci de saisir une adresse mail valide." ); } } private String validationImage( HttpServletRequest request, String chemin ) throws FormValidationException { /* * Récupération du contenu du champ image du formulaire. Il faut ici * utiliser la méthode getPart(). */ String nomFichier = null; InputStream contenuFichier = null; try { Part part = request.getPart( CHAMP_IMAGE ); nomFichier = getNomFichier( part ); /* * Si la méthode getNomFichier() a renvoyé quelque chose, il s'agit * donc d'un champ de type fichier (input type="file"). */ if ( nomFichier != null && !nomFichier.isEmpty() ) { /* * Antibug pour Internet Explorer, qui transmet pour une raison * mystique le chemin du fichier local à la machine du client... * * Ex : C:/dossier/sous-dossier/fichier.ext * * On doit donc faire en sorte de ne sélectionner que le nom et * l'extension du fichier, et de se débarrasser du superflu. */ nomFichier = nomFichier.substring( nomFichier.lastIndexOf( '/' ) + 1 ) .substring( nomFichier.lastIndexOf( '\\' ) + 1 ); /* Récupération du contenu du fichier */ contenuFichier = part.getInputStream(); /* Extraction du type MIME du fichier depuis l'InputStream */ MimeUtil.registerMimeDetector( "eu.medsea.mimeutil.detector.MagicMimeMimeDetector" ); Collection<?> mimeTypes = MimeUtil.getMimeTypes( contenuFichier ); /* * Si le fichier est bien une image, alors son en-tête MIME * commence par la chaîne "image" */ if ( mimeTypes.toString().startsWith( "image" ) ) { /* Écriture du fichier sur le disque */ ecrireFichier( contenuFichier, nomFichier, chemin ); } else { throw new FormValidationException( "Le fichier envoyé doit être une image." ); } } } catch ( IllegalStateException e ) { /* * Exception retournée si la taille des données dépasse les limites * définies dans la section <multipart-config> de la déclaration de * notre servlet d'upload dans le fichier web.xml */ e.printStackTrace(); throw new FormValidationException( "Le fichier envoyé ne doit pas dépasser 1Mo." ); } catch ( IOException e ) { /* * Exception retournée si une erreur au niveau des répertoires de * stockage survient (répertoire inexistant, droits d'accès * insuffisants, etc.) */ e.printStackTrace(); throw new FormValidationException( "Erreur de configuration du serveur." ); } catch ( ServletException e ) { /* * Exception retournée si la requête n'est pas de type * multipart/form-data. */ e.printStackTrace(); throw new FormValidationException( "Ce type de requête n'est pas supporté, merci d'utiliser le formulaire prévu pour envoyer votre fichier." ); } return nomFichier; } /* * 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; } } /* * Méthode utilitaire qui a pour unique but d'analyser l'en-tête * "content-disposition", et de vérifier si le paramètre "filename" y est * présent. Si oui, alors le champ traité est de type File et la méthode * retourne son nom, sinon il s'agit d'un champ de formulaire classique et * la méthode retourne null. */ private static String getNomFichier( Part part ) { /* Boucle sur chacun des paramètres de l'en-tête "content-disposition". */ for ( String contentDisposition : part.getHeader( "content-disposition" ).split( ";" ) ) { /* Recherche de l'éventuelle présence du paramètre "filename". */ if ( contentDisposition.trim().startsWith( "filename" ) ) { /* * Si "filename" est présent, alors renvoi de sa valeur, * c'est-à-dire du nom de fichier sans guillemets. */ return contentDisposition.substring( contentDisposition.indexOf( '=' ) + 1 ).trim().replace( "\"", "" ); } } /* Et pour terminer, si rien n'a été trouvé... */ return null; } /* * Méthode utilitaire qui a pour but d'écrire le fichier passé en paramètre * sur le disque, dans le répertoire donné et avec le nom donné. */ private void ecrireFichier( InputStream contenuFichier, String nomFichier, String chemin ) throws FormValidationException { /* Prépare les flux. */ BufferedInputStream entree = null; BufferedOutputStream sortie = null; try { /* Ouvre les flux. */ entree = new BufferedInputStream( contenuFichier, TAILLE_TAMPON ); sortie = new BufferedOutputStream( new FileOutputStream( new File( chemin + nomFichier ) ), TAILLE_TAMPON ); /* * Lit le fichier reçu et écrit son contenu dans un fichier sur le * disque. */ byte[] tampon = new byte[TAILLE_TAMPON]; int longueur = 0; while ( ( longueur = entree.read( tampon ) ) > 0 ) { sortie.write( tampon, 0, longueur ); } } catch ( Exception e ) { throw new FormValidationException( "Erreur lors de l'écriture du fichier sur le disque." ); } finally { try { sortie.close(); } catch ( IOException ignore ) { } try { entree.close(); } catch ( IOException ignore ) { } } } } |
com.sdzee.tp.forms.CreationClientForm
Code de CreationCommandeForm :
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 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | 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 com.sdzee.tp.beans.Client; import com.sdzee.tp.beans.Commande; import com.sdzee.tp.dao.ClientDao; import com.sdzee.tp.dao.CommandeDao; import com.sdzee.tp.dao.DAOException; 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>(); private ClientDao clientDao; private CommandeDao commandeDao; public CreationCommandeForm( ClientDao clientDao, CommandeDao commandeDao ) { this.clientDao = clientDao; this.commandeDao = commandeDao; } public Map<String, String> getErreurs() { return erreurs; } public String getResultat() { return resultat; } public Commande creerCommande( HttpServletRequest request, String chemin ) { 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 de l'id du client choisi */ String idAncienClient = getValeurChamp( request, CHAMP_LISTE_CLIENTS ); Long id = null; try { id = Long.parseLong( idAncienClient ); } catch ( NumberFormatException e ) { setErreur( CHAMP_CHOIX_CLIENT, "Client inconnu, merci d'utiliser le formulaire prévu à cet effet." ); id = 0L; } /* Récupération de l'objet client correspondant dans la session */ HttpSession session = request.getSession(); client = ( (Map<Long, Client>) session.getAttribute( SESSION_CLIENTS ) ).get( id ); } 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( clientDao ); client = clientForm.creerClient( request, chemin ); /* * 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 de la date dans un DateTime Joda. */ DateTime dt = new DateTime(); 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(); try { traiterClient( client, commande ); commande.setDate( dt ); traiterMontant( montant, commande ); traiterModePaiement( modePaiement, commande ); traiterStatutPaiement( statutPaiement, commande ); traiterModeLivraison( modeLivraison, commande ); traiterStatutLivraison( statutLivraison, commande ); if ( erreurs.isEmpty() ) { commandeDao.creer( commande ); resultat = "Succès de la création de la commande."; } else { resultat = "Échec de la création de la commande."; } } catch ( DAOException e ) { setErreur( "imprévu", "Erreur imprévue lors de la création." ); resultat = "Échec de la création de la commande : une erreur imprévue est survenue, merci de réessayer dans quelques instants."; e.printStackTrace(); } return commande; } private void traiterClient( Client client, Commande commande ) { if ( client == null ) { setErreur( CHAMP_CHOIX_CLIENT, "Client inconnu, merci d'utiliser le formulaire prévu à cet effet." ); } commande.setClient( client ); } private void traiterMontant( String montant, Commande commande ) { double valeurMontant = -1; try { valeurMontant = validationMontant( montant ); } catch ( FormValidationException e ) { setErreur( CHAMP_MONTANT, e.getMessage() ); } commande.setMontant( valeurMontant ); } private void traiterModePaiement( String modePaiement, Commande commande ) { try { validationModePaiement( modePaiement ); } catch ( FormValidationException e ) { setErreur( CHAMP_MODE_PAIEMENT, e.getMessage() ); } commande.setModePaiement( modePaiement ); } private void traiterStatutPaiement( String statutPaiement, Commande commande ) { try { validationStatutPaiement( statutPaiement ); } catch ( FormValidationException e ) { setErreur( CHAMP_STATUT_PAIEMENT, e.getMessage() ); } commande.setStatutPaiement( statutPaiement ); } private void traiterModeLivraison( String modeLivraison, Commande commande ) { try { validationModeLivraison( modeLivraison ); } catch ( FormValidationException e ) { setErreur( CHAMP_MODE_LIVRAISON, e.getMessage() ); } commande.setModeLivraison( modeLivraison ); } private void traiterStatutLivraison( String statutLivraison, Commande commande ) { try { validationStatutLivraison( statutLivraison ); } catch ( FormValidationException e ) { setErreur( CHAMP_STATUT_LIVRAISON, e.getMessage() ); } commande.setStatutLivraison( statutLivraison ); } private double validationMontant( String montant ) throws FormValidationException { double temp; if ( montant != null ) { try { temp = Double.parseDouble( montant ); if ( temp < 0 ) { throw new FormValidationException( "Le montant doit être un nombre positif." ); } } catch ( NumberFormatException e ) { temp = -1; throw new FormValidationException( "Le montant doit être un nombre." ); } } else { temp = -1; throw new FormValidationException( "Merci d'entrer un montant." ); } return temp; } private void validationModePaiement( String modePaiement ) throws FormValidationException { if ( modePaiement != null ) { if ( modePaiement.length() < 2 ) { throw new FormValidationException( "Le mode de paiement doit contenir au moins 2 caractères." ); } } else { throw new FormValidationException( "Merci d'entrer un mode de paiement." ); } } private void validationStatutPaiement( String statutPaiement ) throws FormValidationException { if ( statutPaiement != null && statutPaiement.length() < 2 ) { throw new FormValidationException( "Le statut de paiement doit contenir au moins 2 caractères." ); } } private void validationModeLivraison( String modeLivraison ) throws FormValidationException { if ( modeLivraison != null ) { if ( modeLivraison.length() < 2 ) { throw new FormValidationException( "Le mode de livraison doit contenir au moins 2 caractères." ); } } else { throw new FormValidationException( "Merci d'entrer un mode de livraison." ); } } private void validationStatutLivraison( String statutLivraison ) throws FormValidationException { if ( statutLivraison != null && statutLivraison.length() < 2 ) { throw new FormValidationException( "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
Code des servlets
Contenu du 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 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 | <?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> <filter> <filter-name>PrechargementFilter</filter-name> <filter-class>com.sdzee.tp.filters.PrechargementFilter</filter-class> </filter> <filter-mapping> <filter-name>PrechargementFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>com.sdzee.tp.config.InitialisationDaoFactory</listener-class> </listener> <servlet> <servlet-name>CreationClient</servlet-name> <servlet-class>com.sdzee.tp.servlets.CreationClient</servlet-class> <init-param> <param-name>chemin</param-name> <param-value>/fichiers/images/</param-value> </init-param> <multipart-config> <location>c:/fichiers/images</location> <max-file-size>2097152</max-file-size> <!-- 2 Mo --> <max-request-size>10485760</max-request-size> <!-- 5 x 2Mo --> <file-size-threshold>1048576</file-size-threshold> <!-- 1 Mo --> </multipart-config> </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> <init-param> <param-name>chemin</param-name> <param-value>/fichiers/images/</param-value> </init-param> <multipart-config> <location>c:/fichiers/images</location> <max-file-size>2097152</max-file-size> <!-- 2 Mo --> <max-request-size>10485760</max-request-size> <!-- 5 x 2Mo --> <file-size-threshold>1048576</file-size-threshold> <!-- 1 Mo --> </multipart-config> </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> <servlet-name>Image</servlet-name> <servlet-class>com.sdzee.tp.servlets.Image</servlet-class> <init-param> <param-name>chemin</param-name> <param-value>/fichiers/images/</param-value> </init-param> </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> <servlet-mapping> <servlet-name>Image</servlet-name> <url-pattern>/images/*</url-pattern> </servlet-mapping> </web-app> |
/WEB-INF/web.xml
Code de la servlet 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 75 76 77 78 | 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.dao.ClientDao; import com.sdzee.tp.dao.DAOFactory; import com.sdzee.tp.forms.CreationClientForm; public class CreationClient extends HttpServlet { public static final String CONF_DAO_FACTORY = "daofactory"; public static final String CHEMIN = "chemin"; 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"; private ClientDao clientDao; public void init() throws ServletException { /* Récupération d'une instance de notre DAO Utilisateur */ this.clientDao = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getClientDao(); } 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 { /* * Lecture du paramètre 'chemin' passé à la servlet via la déclaration * dans le web.xml */ String chemin = this.getServletConfig().getInitParameter( CHEMIN ); /* Préparation de l'objet formulaire */ CreationClientForm form = new CreationClientForm( clientDao ); /* Traitement de la requête et récupération du bean en résultant */ Client client = form.creerClient( request, chemin ); /* 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<Long, Client> clients = (HashMap<Long, Client>) session.getAttribute( SESSION_CLIENTS ); /* Si aucune map n'existe, alors initialisation d'une nouvelle map */ if ( clients == null ) { clients = new HashMap<Long, Client>(); } /* Puis ajout du client courant dans la map */ clients.put( client.getId(), 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
Code de la servlet CreationCommande :
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 | 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.dao.ClientDao; import com.sdzee.tp.dao.CommandeDao; import com.sdzee.tp.dao.DAOFactory; import com.sdzee.tp.forms.CreationCommandeForm; public class CreationCommande extends HttpServlet { public static final String CONF_DAO_FACTORY = "daofactory"; public static final String CHEMIN = "chemin"; 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 APPLICATION_CLIENTS = "initClients"; public static final String SESSION_COMMANDES = "commandes"; public static final String APPLICATION_COMMANDES = "initCommandes"; public static final String VUE_SUCCES = "/WEB-INF/afficherCommande.jsp"; public static final String VUE_FORM = "/WEB-INF/creerCommande.jsp"; private ClientDao clientDao; private CommandeDao commandeDao; public void init() throws ServletException { /* Récupération d'une instance de nos DAO Client et Commande */ this.clientDao = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getClientDao(); this.commandeDao = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getCommandeDao(); } 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 { /* * Lecture du paramètre 'chemin' passé à la servlet via la déclaration * dans le web.xml */ String chemin = this.getServletConfig().getInitParameter( CHEMIN ); /* Préparation de l'objet formulaire */ CreationCommandeForm form = new CreationCommandeForm( clientDao, commandeDao ); /* Traitement de la requête et récupération du bean en résultant */ Commande commande = form.creerCommande( request, chemin ); /* 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<Long, Client> clients = (HashMap<Long, Client>) session.getAttribute( SESSION_CLIENTS ); /* Si aucune map n'existe, alors initialisation d'une nouvelle map */ if ( clients == null ) { clients = new HashMap<Long, Client>(); } /* Puis ajout du client de la commande courante dans la map */ clients.put( commande.getClient().getId(), 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<Long, Commande> commandes = (HashMap<Long, Commande>) session.getAttribute( SESSION_COMMANDES ); /* Si aucune map n'existe, alors initialisation d'une nouvelle map */ if ( commandes == null ) { commandes = new HashMap<Long, Commande>(); } /* Puis ajout de la commande courante dans la map */ commandes.put( commande.getId(), 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
Code de la servlet 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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 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.dao.ClientDao; import com.sdzee.tp.dao.DAOException; import com.sdzee.tp.dao.DAOFactory; public class SuppressionClient extends HttpServlet { public static final String CONF_DAO_FACTORY = "daofactory"; public static final String PARAM_ID_CLIENT = "idClient"; public static final String SESSION_CLIENTS = "clients"; public static final String VUE = "/listeClients"; private ClientDao clientDao; public void init() throws ServletException { /* Récupération d'une instance de notre DAO Utilisateur */ this.clientDao = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getClientDao(); } public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { /* Récupération du paramètre */ String idClient = getValeurParametre( request, PARAM_ID_CLIENT ); Long id = Long.parseLong( idClient ); /* Récupération de la Map des clients enregistrés en session */ HttpSession session = request.getSession(); Map<Long, Client> clients = (HashMap<Long, Client>) session.getAttribute( SESSION_CLIENTS ); /* Si l'id du client et la Map des clients ne sont pas vides */ if ( id != null && clients != null ) { try { /* Alors suppression du client de la BDD */ clientDao.supprimer( clients.get( id ) ); /* Puis suppression du client de la Map */ clients.remove( id ); } catch ( DAOException e ) { e.printStackTrace(); } /* 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
Code de la servlet SuppressionCommande :
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 | 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; import com.sdzee.tp.dao.CommandeDao; import com.sdzee.tp.dao.DAOException; import com.sdzee.tp.dao.DAOFactory; public class SuppressionCommande extends HttpServlet { public static final String CONF_DAO_FACTORY = "daofactory"; public static final String PARAM_ID_COMMANDE = "idCommande"; public static final String SESSION_COMMANDES = "commandes"; public static final String VUE = "/listeCommandes"; private CommandeDao commandeDao; public void init() throws ServletException { /* Récupération d'une instance de notre DAO Utilisateur */ this.commandeDao = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getCommandeDao(); } public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { /* Récupération du paramètre */ String idCommande = getValeurParametre( request, PARAM_ID_COMMANDE ); Long id = Long.parseLong( idCommande ); /* Récupération de la Map des commandes enregistrées en session */ HttpSession session = request.getSession(); Map<Long, Commande> commandes = (HashMap<Long, Commande>) session.getAttribute( SESSION_COMMANDES ); /* Si l'id de la commande et la Map des commandes ne sont pas vides */ if ( id != null && commandes != null ) { try { /* Alors suppression de la commande de la BDD */ commandeDao.supprimer( commandes.get( id ) ); /* Puis suppression de la commande de la Map */ commandes.remove( id ); } catch ( DAOException e ) { e.printStackTrace(); } /* 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
Code du filtre
Code du filtre de préchargement :
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 | package com.sdzee.tp.filters; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import com.sdzee.tp.beans.Client; import com.sdzee.tp.beans.Commande; import com.sdzee.tp.dao.ClientDao; import com.sdzee.tp.dao.CommandeDao; import com.sdzee.tp.dao.DAOFactory; public class PrechargementFilter implements Filter { public static final String CONF_DAO_FACTORY = "daofactory"; public static final String ATT_SESSION_CLIENTS = "clients"; public static final String ATT_SESSION_COMMANDES = "commandes"; private ClientDao clientDao; private CommandeDao commandeDao; public void init( FilterConfig config ) throws ServletException { /* Récupération d'une instance de nos DAO Client et Commande */ this.clientDao = ( (DAOFactory) config.getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getClientDao(); this.commandeDao = ( (DAOFactory) config.getServletContext().getAttribute( CONF_DAO_FACTORY ) ) .getCommandeDao(); } public void doFilter( ServletRequest req, ServletResponse res, FilterChain chain ) throws IOException, ServletException { /* Cast de l'objet request */ HttpServletRequest request = (HttpServletRequest) req; /* Récupération de la session depuis la requête */ HttpSession session = request.getSession(); /* * Si la map des clients n'existe pas en session, alors l'utilisateur se * connecte pour la première fois et nous devons précharger en session * les infos contenues dans la BDD. */ if ( session.getAttribute( ATT_SESSION_CLIENTS ) == null ) { /* * Récupération de la liste des clients existants, et enregistrement * en session */ List<Client> listeClients = clientDao.lister(); Map<Long, Client> mapClients = new HashMap<Long, Client>(); for ( Client client : listeClients ) { mapClients.put( client.getId(), client ); } session.setAttribute( ATT_SESSION_CLIENTS, mapClients ); } /* * De même pour la map des commandes */ if ( session.getAttribute( ATT_SESSION_COMMANDES ) == null ) { /* * Récupération de la liste des commandes existantes, et * enregistrement en session */ List<Commande> listeCommandes = commandeDao.lister(); Map<Long, Commande> mapCommandes = new HashMap<Long, Commande>(); for ( Commande commande : listeCommandes ) { mapCommandes.put( commande.getId(), commande ); } session.setAttribute( ATT_SESSION_COMMANDES, mapCommandes ); } /* Pour terminer, poursuite de la requête en cours */ chain.doFilter( request, res ); } public void destroy() { } } |
com.sdzee.tp.filters.PrechargementFilter
Code des JSP
Code de 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 57 58 59 60 | <%@ 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>Image</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> <td> <%-- On ne construit et affiche un lien vers l'image que si elle existe. --%> <c:if test="${ !empty mapClients.value.image }"> <c:set var="image"><c:out value="${ mapClients.value.image }"/></c:set> <a href="<c:url value="/images/${ image }"/>">Voir</a> </c:if> </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="idClient" 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
Code de listerCommandes.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 57 | <%@ page pageEncoding="UTF-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib prefix="joda" uri="http://www.joda.org/joda/time/tags" %> <!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><joda:format value="${ mapCommandes.value.date }" pattern="dd/MM/yyyy HH:mm:ss"/></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="idCommande" 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
Code de creerCommande.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 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 | <%@ page pageEncoding="UTF-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib prefix="joda" uri="http://www.joda.org/joda/time/tags" %> <!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"/>" enctype="multipart/form-data"> <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.key }">${ 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="<joda:format value="${ commande.date }" pattern="dd/MM/yyyy HH:mm:ss"/>" 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
Code de afficherCommande.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 | <%@ page pageEncoding="UTF-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib prefix="joda" uri="http://www.joda.org/joda/time/tags" %> <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Affichage 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 id="corps"> <p class="info">${ form.resultat }</p> <p>Client</p> <p>Nom : <c:out value="${ commande.client.nom }"/></p> <p>Prénom : <c:out value="${ commande.client.prenom }"/></p> <p>Adresse : <c:out value="${ commande.client.adresse }"/></p> <p>Numéro de téléphone : <c:out value="${ commande.client.telephone }"/></p> <p>Email : <c:out value="${ commande.client.email }"/></p> <p>Image : <c:out value="${ commande.client.image }"/></p> <p>Commande</p> <p>Date : <joda:format value="${ commande.date }" pattern="dd/MM/yyyy HH:mm:ss"/></p> <p>Montant : <c:out value="${ commande.montant }"/></p> <p>Mode de paiement : <c:out value="${ commande.modePaiement }"/></p> <p>Statut du paiement : <c:out value="${ commande.statutPaiement }"/></p> <p>Mode de livraison : <c:out value="${ commande.modeLivraison }"/></p> <p>Statut de la livraison : <c:out value="${ commande.statutLivraison }"/></p> </div> </body> </html> |
/WEB-INF/afficherCommande.jsp