You are on page 1of 73

JAVA ENTREPRISE EDITION « JEE »

Professeur:
Pr HIBA ASRI
Filière:
Génie Informatique , 4 ème année
1
BASE DE DONNÉES

2
SGBD

SGBD: Système de Gestion des Base de Données

MySQL : solution libre et gratuite, c'est le SGBD le plus répandu.


PostgreSQL : solution libre et gratuite, moins connue du grand public mais proposant des fonctionnalités
inexistantes dans MySQL ;
Oracle : solution propriétaire et payante, massivement utilisée par les grandes entreprises. C'est un des SGBD les
plus complets, mais un des plus chers également ;
SQL Server : la solution propriétaire de Microsoft ;
DB2 : la solution propriétaire d'IBM, utilisée principalement dans les très grandes entreprises sur des Mainframes.

Language SQL
3
MYSQL INSTALLATION

Lien de téléchargement: https://dev.mysql.com/downloads/mysql/#downloads

4
JDBC

5
JDBC

• API de la plateforme JEE : classes permettant l'accès depuis vos applications Java à des données
rangées sous forme de tables
JDBC permet:
• la connexion avec le SGBD ;
• l'envoi de requêtes SQL au SGBD depuis une application Java ;
• le traitement des données et éventuelles erreurs retournées par le SGBD lors des différentes étapes
du dialogue (connexion, requête, exécution, etc.).

6
JDBC

• Problème:
• Plusieurs SGBD == Plusieurs manière de traiter les données.

Solution :
• JDBC : s'adapter à n'importe quel SGBD .
• Ajouter un driver spécifique au SGBD
• https://dev.mysql.com/downloads/connector/j/

7
JDBC DRIVER

Etapes à suivre:

1. Décompressez son contenu dans un


dossier sur votre poste.

2. Copier le fichier : mysql-connector-java-


xxx-bin.jar dans le dossier lib du
serveur Tomcat.

8
COMMUNIQUER AVEC LA BD

1. Charger le Driver MySql:

/* Chargement du driver JDBC pour MySQL */


try {Class.forName( "com.mysql.jdbc.Driver" );

} catch ( ClassNotFoundException e ) {
/* Gérer les éventuelles erreurs ici. */
}

9
COMMUNIQUER AVEC LA BD

2. Se connecter à la BD

Identification de l’URL:

jdbc:mysql://nomhote:port/nombdd

le nom de la base de données à


le nom de l'hôte sur lequel le
laquelle vous souhaitez vous
serveur MySQL est installé. connecter

le port TCP/IP écouté par votre


serveur MySQL. Par défaut, il s'agit
du port 3306

jdbc:mysql://localhost:3306/BDGinfo 10
COMMUNIQUER AVEC LA BD

try {
Etablissement de la connexion: connexion = DriverManager.getConnection( url, user, mdp );

/* requêtes vers la BDD */


/* Connexion à la base de données */ } catch ( SQLException e ) {
String url = "jdbc:mysql://localhost:3306/BDGinfo"; /* Gérer les éventuelles erreurs ici */
String user = "user"; } finally {
String mdp = "mdp";
if ( connexion != null )
Connection connexion = null;
try {
/* Fermeture de la connexion */
connexion.close();
} catch ( SQLException ignore ) {
/* Si une erreur survient lors de la fermeture*/
}
}

11
COMMUNIQUER AVEC LA BD

Erreurs

• SQLException: No suitable driver : driver JDBC n'a pas été chargé ou que l'URL n'a été reconnue par
aucun des drivers chargés par votre application ;
• SQLException: Connection refused ou Connection timed out ou encore CommunicationsException:
Communications link failure : la base de données n'est pas joignable.

12
COMMUNIQUER AVEC LA BD

Cause éventuelle Solution


Le serveur MySQL est éteint ? Démarrez le serveur MySQL...
Le numéro de port dans l'URL est manquant ou incorrect ? Ouvrez le fichier de configuration my.cnf de votre serveur
MySQL, et vérifiez le port qui y est spécifié.

Le nom d'hôte ou l'adresse IP dans l'URL est incorrect(e) ? Testez la connectivité en effectuant un simpleping.

Le serveur MySQL n'accepte pas de connexions TCP/IP ? Vérifiez que MySQL a été lancé sans l'option--skip-
networking.
Il n'y a plus aucune connexion disponible sur le serveur Redémarrez MySQL, et corrigez le code de votre application
MySQL ? pour qu'il libère les connexions efficacement.
Quelque chose entre l'application Java et le serveur MySQL Configurez votre pare-feu et/ou proxy pour qu'il(s)
bloque la connexion, comme un pare-feu ou un proxy ? autorise(nt) le port écouté par votre serveur MySQL.

Le nom d'hôte dans l'URL n'est pas reconnu par votre Utilisez l'adresse IP dans l'URL au lieu du nom d'hôte, ou
serveur DNS local ? actualisez si possible votre DNS.

13
COMMUNIQUER AVEC LA BD

3. Créer une requête

• Interface Statement: Création des requêtes SQL


• Méthode createStatement

Statement statement = connexion.createStatement();

14
COMMUNIQUER AVEC LA BD

3. Exécuter une requête


• executeQuery(): cette méthode est dédiée à la lecture de données via une
requête de type SELECT;

• executeUpdate(): cette méthode est réservée à l'exécution de requêtes ayant


un effet sur la base de données (écriture ou suppression), typiquement les
requêtes de type INSERT, UPDATE, DELETE, etc.

15
COMMUNIQUER AVEC LA BD

3. Exécuter une requête en lecture (executeQuery)


ResultSet resultat = statement.executeQuery( "SELECT id, email, mot_de_passe, nom FROM
Utilisateur;" );

4. Exécuter une requête en écriture (executeUpdate)

int statut = statement.executeUpdate( "INSERT INTO Utilisateur (email, mot_de_passe, nom)


VALUES (‘asri.hiba@mail.fr', MD5(‘H@ZER!Y'), ‘Asri');" );

16
COMMUNIQUER AVEC LA BD

5. Récupérer les résultats ( requête de lecture SELECT )


/* Exécution d'une requête de lecture */
ResultSet resultat = statement.executeQuery( "SELECT id, email, mot_de_passe, nom FROM
Utilisateur;" );

/* Récupération des données du résultat de la requête de lecture */


while ( resultat.next() ) {
int idUtilisateur = resultat.getInt( "id" );
String emailUtilisateur = resultat.getString( "email" );
String motDePasseUtilisateur = resultat.getString( "mot_de_passe" );
String nomUtilisateur = resultat.getString( "nom" );

…………….
} 17
COMMUNIQUER AVEC LA BD

5. Récupérer les résultats ( requête de lecture SELECT )


/* Exécution d'une requête de lecture */
ResultSet resultat = statement.executeQuery( "SELECT id, email, mot_de_passe, nom FROM
Utilisateur;" );

/* Récupération des données du résultat de la requête de lecture */


while ( resultat.next() ) {
int idUtilisateur = resultat.getInt( 1 );
String emailUtilisateur = resultat.getString( 2 );
String motDePasseUtilisateur = resultat.getString( 3 );
String nomUtilisateur = resultat.getString( 4 );

…………….
} 18
COMMUNIQUER AVEC LA BD

6. Récupérer les résultats ( requête d’écriture DELETE UPDATE ADD)


INSERT: renvoie 0 en cas d'échec de la requête d'insertion, et 1 en cas de succès ;

UPDATE ou DELETE: renvoie le nombre de lignes respectivement mises à jour ou supprimées ;

CREATE, ou de toute autre requête: ne retournant rien, renvoie 0.

Exemple:

int statut = statement.executeUpdate( "INSERT INTO Utilisateur (email, mot_de_passe, nom,)


VALUES (‘asri.hiba@mail.fr', MD5(‘H@ZER!Y'), ‘Asri');" );

19
COMMUNIQUER AVEC LA BD
7. LIBÉRER LES RESSOURCES

Connection connexion = null; if ( statement != null ) {


Statement statement = null; try {
ResultSet resultat = null; /* Puis on ferme le Statement */
try { statement.close();
/* } catch ( SQLException ignore ) {
* Ouverture de la connexion, initialisation d'un }
Statement, initialisation d'un ResultSet, etc. }
*/ if ( connexion != null ) {
} catch ( SQLException e ) { try {
/* Traiter les erreurs éventuelles ici. */ /* Et enfin on ferme la connexion */
} finally {
connexion.close();
if ( resultat != null ) { } catch ( SQLException ignore ) {
try { }
resultat.close(); }
} catch ( SQLException ignore ) { }
}
} 20
INJECTIONS SQL

« il ne faut jamais faire confiance à l'utilisateur ».

Exemple:

http://localhost:8080/GInfo/testjdbc?nom=Nom'&motdepasse=mdp&email=nom@gmail.co
m

INSERT INTO Utilisateur (email, mot_de_passe, nom, date_inscription) VALUES


('h.asri@gmail.comr',MD5(‘mdp'), ‘Nom’ ‘ );
 Erreur  Injection SQL

21
INJECTIONS SQL

Solution

1. Créer une fonction de vérification

2. Les requêtes préparées

22
REQUÊTES PRÉPARÉES

Définition
 Nouvel objet: peparedStatement

 Nouvelle Interface implémentant l’interface statement

Intérêts:

1. pré-compiler une requête SQL ;

2. une requête SQL paramétrée: Contient des jokers comblés lors de son exécution ;

3. une requête SQL protégée contre les injections SQL (erreurs sur les types des paramètres)

23
REQUÊTES PRÉPARÉES

1. pré-compiler une requête SQL :


• Prendre une requête comme argument lors de la création
Cas général:
Requête SQL  SGBD  compilation
Cas PreparedStatement
Requête SQL pré-compilée  SGBD  exécution

Note: Tous les drivers JDBC ne procèdent pas de cette manière, certains n'effectuent pas l'envoi de la
requête vers le serveur SQL pour pré-compilation lors de sa création via un PreparedStatement. Ces
différences de comportement d'un driver à l'autre existent parce que cette fonctionnalité n'est pas
définie noir sur blanc dans les spécifications de l'API JDBC.
24
REQUÊTES PRÉPARÉES

2. Des requêtes paramétrées

• Créer des requêtes modèles prenant en compte des paramètres « ? »

• Ils doivent être précisés avant l’exécution

Exemple:

SELECT * FROM Utilisateur WHERE email = ?

Lorsque vous passez une telle requête à un objet PreparedStatement, celui-ci va la faire pré-compiler
et se chargera ensuite de remplacer le paramètre manquant par la valeur que vous souhaitez lui
donner au moment de l'exécution.
25
REQUÊTES PRÉPARÉES

2. Des requêtes protégées

• Eviter tout risque de failles de ce type : disponible dans tous les Driver JDBC

• Requêtes protégées des Injections SQL

26
REQUÊTES PRÉPARÉES

Préparer sa requête:

Avec Statement:
Statement statement = connexion.createStatement();

Avec PreparedStatement
PreparedStatement preparedStatement = connexion.prepareStatement( "SELECT id, email,
mot_de_passe, nom FROM User ;" );

27
REQUÊTES PRÉPARÉES

Exécuter sa requête:

Avec Statement:
statement.executeQuery( "SELECT id, email, mot_de_passe, nom FROM User ;" );

Avec PreparedStatement
preparedStatement.executeQuery();

28
REQUÊTES PRÉPARÉES

Utiliser des paramètres:


Avec Statement:

statement = connexion.createStatement();
String paramEmail = request.getParameter( "email" ); String paramMotDePasse = request.getParameter( "motdepasse" );
String paramNom = request.getParameter( "nom" );

if ( paramEmail != null && paramMotDePasse != null && paramNom != null ) {


int statut = statement.executeUpdate( "INSERT INTO Utilisateur (email, mot_de_passe, nom, date_inscription) "
+ "VALUES ('" + paramEmail + "', MD5('" + paramMotDePasse + "'), '" + paramNom + "', NOW());" );
}
29
REQUÊTES PRÉPARÉES

Utiliser des paramètres:


Avec PreparedStatement:
preparedStatement = connexion.prepareStatement( "INSERT INTO Utilisateur (email, mot_de_passe, nom,

date_inscription) VALUES(?, MD5(?), ?, NOW());" );

String paramEmail = request.getParameter( "email" ); String paramMotDePasse = request.getParameter(


"motdepasse" ); String paramNom = request.getParameter( "nom" );

preparedStatement.setString( 1, paramEmail );
preparedStatement.setString( 2, paramMotDePasse );
preparedStatement.setString( 3, paramNom );
int statut = preparedStatement.executeUpdate();
30
LIMITES

• MVC est bien respecté.


• Dans la pratique (application complexes )  problème de conception
• Liaison forte (code responsable des traitements métier et code responsable du
stockage des données)
• Impossible des les exécuter séparément
• Impossible de mettre en place des tests unitaires
• Impossible de changer le mode de stockage

31
SOLUTION

Isoler le stockage des données  Ajouter une couche intermédiaire

32
DAO (DATA ACCESS OBJECT)

33
SOLUTION: PATTERN DAO

• Isolement pur et simple du code responsable du stockage des données


• Transparence de la manière dont sont stockées les données au reste de l'application.
• Seul le DAO est en contact avec le système de stockage
• Création d'une nouvelle couche est nécessaire (Ecriture de codes supplémentaires et
répétitifs.)

• DAO  Faire la distinction entre les données auxquelles vous souhaitez


accéder, et la manière dont elles sont stockées.
34
PRINCIPE

• Séparer la couche modèle d'une application en deux sous-couches distinctes :


• Couche métier ou service: une couche gérant les traitements métier appliqués aux données.
• Ex: travail de validation réalisé dans nos objets EmpruntForm et ConnexionForm en fait partie ;
• Couche de données: une couche gérant le stockage des données.
• Opérations classiques de stockage : la création, la lecture, la modification et la suppression.

• Opérations appelées: CRUD

35
PRINCIPE

1. Encapsulation des exceptions de stockage:


• Exceptions propre à la couche DAO
• Exceptions (générées par JDBC / SQL ) vues par les objets métiers comme Exceptions émanant
de la couche DAO

2. Masquer le code responsable du stockage


• Utiliser des interfaces
• Code JDBC isolé (connu par la DAO)
• Objet métier connaissent uniquement les interfaces

36
PRINCIPE

Résultat:
Couche modèle = Couche métier +
Couche Couche de données
Modèle
Couche Métier:
• utilise les interfaces décrivant les objets de
la couche de données.
• Méthodes à appeler ne changent pas
Couche de données:
• Implémentation des CRUD (Mode de
stockage)
37
ARCHITECTURE JEE

RMI SGBD
CORBA, SOAP
Objet Java
Serveur d’application JEE
REST (HTTP,JSON)
Smart Phone Couche DAO (Data Access Object)
Mapping Object Relationnel (JPA, Hibernate)
SOAP (HTTP, XML
Application .net
Couche Métier
SOAP (HTTP, XML
Application php
Couche Service Couche Web
JMS HTTP
Client JMS • Servlet
MiddleWare: Client
• RMI • JSP
SMS • Frameworks (HTML,CSS,
• CORBA
JavaScript,…)
Client SMS • SOAP (struts, Spring
• JMS MVC, JSF)
• ….
38
MISE EN PLACE

Exemple : Inscription Utilisateur

Base de données: GestionUser


NomUser: user
Mdp: user

39
MISE EN PLACE

package com.sdzee.beans;

Etapes 1:
import java.sql.Timestamp;

Création du Bean utilisateur:


public class Utilisateur {

Bonnes pratiques: private Long id;


1. Champ de types primitifs private String email;
 Eviter les valeurs null private String motDePasse;
2. Contraintes BD : private String nom;
 Valeur non null dans la Base de données private Timestamp dateInscription;

// getter & setter


40
}
MISE EN PLACE

Etapes 2:

Création des Exceptions DAO: Exceptions SQL lors d’une Tentative de


lecture / Ecriture:
• liées à la configuration du DAO et du driver JDBC ;
• liées à l'interaction avec la base de données. • des soucis de connexions,
• des requêtes incorrectes,
Conception DAO: • des données absentes,
• la base qui ne répond plus, etc
Objets métier  Appels des méthodes DAO  manipulation BD

But: Aucune exception de cette forme

41
Etapes 2 (Suite): MISE EN PLACE
Solution: Créer une exception personnalisée qui va encapsuler les exceptions liées à SQL ou JDBC.

public class DAOConfigurationException extends


public class DAOException extends RuntimeException {
RuntimeException {
public DAOConfigurationException( String
public DAOException( String message ) { message ) {
super( message ); super( message );
} }

public DAOException( String message, public DAOConfigurationException( String


Throwable cause ) { message, Throwable cause ) {
super( message, cause ); super( message, cause );
} }

public DAOException( Throwable cause ) { public DAOConfigurationException(


super( cause ); Throwable cause ) {
} super( cause );
} }
} 42
MISE EN PLACE

Etapes 3:

Créer un fichier de configuration :


• Fichier daoProperties : Package DAO
• fichier texte dont les lignes respectent un certain format.
• Informations de connexion à la base de données

url = jdbc:mysql://localhost:3306/GestionUSer
driver = com.mysql.jdbc.Driver
nomutilisateur = user
motdepasse = user
43
MISE EN PLACE

Etapes 4:

Création d’une Factory (Aide DAO):

• Instanciation des différents DAO de votre application (Ex: Une table  un seul DAO)
• Lire les informations de configuration depuis le fichier properties ;
• Charger le driver JDBC du SGBD utilisé ;
• Fournir une connexion à la base de données.

44
public class DAOFactory {
MISE
private static final String FICHIER_PROPERTIES
EN PLACE
= "/com/sdzee/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;


Variables pour sauvegarder les propriétées décrites
private String username;
dans le fichier dao.properties
private String password;

DAOFactory( String url, String username, String password ) {


this.url = url;
this.username = username;
Constructeur
this.password = password;
}
45
Méthode getInstance

public static DAOFactory getInstance()


MISE
throws
EN PLACE
DAOConfigurationException {
• Instancier la classe DAOFactory
Properties properties = new Properties(); • Static: Appel avant instanciation de DAOFactory
String url; String driver;
String nomUtilisateur; String motDePasse;
• Ouverture du fichier Properties.
ClassLoader classLoader = • Appel de la méthode RessourceAsStream de l’objet
classLoader
Thread.currentThread().getContextClassLoader();
 Ouvrir le flux demandé et de retourner null en cas
InputStream fichierProperties = d'erreur
classLoader.getResourceAsStream(
FICHIER_PROPERTIES );

if ( fichierProperties == null ) { • envoyer une exception personnalisée


throw new DAOConfigurationException( "Le DAOConfigurationException stipulant que le fichier n'a
fichier properties " + FICHIER_PROPERTIES + " est pas été trouvé.
introuvable." ); 46

}
MISE EN PLACE
try {
properties.load( fichierProperties );
url = properties.getProperty( PROPERTY_URL );
driver = properties.getProperty( • Charger les propriétés du fichier Properties.
PROPERTY_DRIVER );
• Intercepter l'exception éventuellement envoyée en cas
nomUtilisateur = properties.getProperty( d'erreur lors du chargement des propriétés (format du
PROPERTY_NOM_UTILISATEUR ); fichier properties incorrect)
motDePasse = properties.getProperty(
• l'encapsuler dans une
PROPERTY_MOT_DE_PASSE ); exception DAOConfigurationException.
} catch ( IOException e ) {
throw new DAOConfigurationException( "Impossible
de charger le fichier properties " + FICHIER_PROPERTIES, e );
}

47
…….
MISE EN PLACE

try {
Class.forName( driver ); • Appel à Class.forName(drive)
} catch ( ClassNotFoundException e ) {
• Encapsuler l’exception dans une
throw new DAOConfigurationException( "Le driver exception DAOConfigurationException.
est introuvable dans le classpath.", e );
}

DAOFactory instance = new DAOFactory(


• Appel à Class.forName(drive)
url, nomUtilisateur, motDePasse );
• Encapsuler l’exception dans une
return instance; exception DAOConfigurationException.
}

48
MISE EN PLACE

Méthode getConnection

• Méthode chargée de fournir une connexion à la base de données

Connection getConnection() throws SQLException {


return DriverManager.getConnection( url, username, password );
}

49
MISE EN PLACE

Méthode de récupération de l’implémentation des différents DAO

• Ex: Un seul DAO à implémenter

public UtilisateurDao getUtilisateurDao() {


return new UtilisateurDaoImpl( this );
}

50
MISE EN PLACE

Etapes 5:
Création de l’interface du DAO utilisateur
• Actions effectuées sur les données, c'est-à-dire sur le bean Utilisateur.

Bonne Pratiques:
• Table nommée: User
• Interface: UserDAO
• Implémentation: UserDaoImpl

51
MISE EN PLACE

package com.sdzee.dao;

import com.sdzee.beans.Utilisateur;

public interface UtilisateurDao {

void creer( Utilisateur utilisateur ) throws DAOException;

Utilisateur trouver( String email ) throws DAOException;

} 52
MISE EN PLACE

Etapes 6:
Création de l’implémentation du DAO utilisateur

• Classe: manipuler la table Utilisateur de la base de données.


• Contenir le code des méthodes create() et find() (opérations CRUD par la suite).

53
MISE EN PLACE

public class UtilisateurDaoImpl implements UtilisateurDao {


/* Implémentation de la méthode trouver() définie dans l'interface UtilisateurDao */
@Override
public Utilisateur trouver( String email ) throws DAOException {
return null;
}

/* Implémentation de la méthode creer() définie dans l'interface UtilisateurDao */


@Override
public void creer( Utilisateur utilisateur ) throws IllegalArgumentException, DAOException {
}
}
54
MISE EN PLACE

Etapes 7:

Création de la relation entre la couche métier et le DAO

• Factory déjà créée 


• Créer le DAO via le getter getUtilisateurDao(),
• Acquérir une connexion à la base de données en appelant la méthode getConnection().

Solution:
• le DAO doit avoir accès à une instance de la DAOFactory

55
MISE EN PLACE

1. Créer un Constructeur qui prend en argument un objet de type daoFactory

public class UtilisateurDaoImpl implements UtilisateurDao {


private DAOFactory daoFactory;

UtilisateurDaoImpl( DAOFactory daoFactory ) {


this.daoFactory = daoFactory;
}
...
}

56
MISE EN PLACE

Etapes 8:

2. Implémentation des méthodes creer() et trouver() définit dans l’interface userDao


 Communication avec la base de données.
 Créer la classe userDaoImpl

TAF:
• Initialiser une requête préparée avec des paramètres ;
• Récupérer une ligne d'une table et enregistrer son contenu dans un bean ;
• Fermer les ressources ouvertes (Connection, PreparedStatement, ResultSet).
57
MISE EN PLACE

Etapes 8:

3 méthodes:

1. Méthode 1: récupère une liste de paramètres et les ajoute à une requête préparée donnée ;
2. Méthode 2: récupère un ResultSet et enregistre ses données dans un bean ;
3. Méthode 3: ferme toutes les ressources ouvertes.

 Créer une classe Utilitaire contenant les méthodes 1 et 3


 Créer la classe userDaoUser contenant la méthode 2, la définition de créer() et trouver()
58
MISE EN PLACE

Etapes 8:
Méthode 1: Requête préparée:

public static PreparedStatement initialisationRequetePreparee( Connection connexion, String sql,


boolean returnGeneratedKeys, Object... objets ) throws SQLException {
PreparedStatement preparedStatement = connexion.prepareStatement( sql, returnGeneratedKeys ?
Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS );
for ( int i = 0; i < objets.length; i++ ) {
preparedStatement.setObject( i + 1, objets[i] );
}
return preparedStatement;
}

59
MISE EN PLACE

Etapes 8:
Méthode 2: Mapping entre un resultsSet et un bean User

private static Utilisateur map( ResultSet resultSet ) throws SQLException {


Utilisateur utilisateur = new Utilisateur();
utilisateur.setId( resultSet.getLong( "id" ) );
utilisateur.setEmail( resultSet.getString( "email" ) );
utilisateur.setMotDePasse( resultSet.getString( "mot_de_passe" ) );
utilisateur.setNom( resultSet.getString( "nom" ) );
utilisateur.setDateInscription( resultSet.getTimestamp( "date_inscription" ) );
return utilisateur;
}

60
Etapes 8: Méthode 3: Fermeture des ressources
MISE EN PLACE
public static void closeRessource( ResultSet resultSet ) {
if ( resultSet != null ) {
try {
resultSet.close();
} catch ( SQLException e ) {
System.out.println( "Échec de la fermeture du public static void closeRessource( Connection
ResultSet : " + e.getMessage() ); connexion ) {
} if ( connexion != null ) {
} try {
} connexion.close();
public static void closeRessource( Statement statement ) } catch ( SQLException e ) {
{ System.out.println( "Échec de la fermeture de la
if ( statement != null ) { connexion : " + e.getMessage() );
try { }
statement.close(); }
} catch ( SQLException e ) { }
System.out.println( "Échec de la fermeture du
Statement : " + e.getMessage() );
}
}
61
}
MISE EN PLACE

Etapes 8:
Méthode 3: Fermeture des ressources
public static void closeRessource( Statement statement, Connection connexion ) {
closeRessource( statement );
closeRessource( connexion );
}

public static void closeRessource( ResultSet resultSet, Statement statement, Connection connexion ) {
closeRessource( resultSet );
closeRessource( statement );
closeRessource( connexion );
}
62
try {
MISE EN PLACE
connexion = daoFactory.getConnection();
preparedStatement = initialisationRequetePreparee(
Etapes 8: connexion, SQL_SELECT_PAR_EMAIL, false, email ); //1
Méthode trouver()
resultSet = preparedStatement.executeQuery();
private static final String SQL_SELECT_PAR_EMAIL =
if ( resultSet.next() ) {
"SELECT id, email, nom, mot_de_passe, date_inscription
FROM User WHERE email = ?"; utilisateur = map( resultSet ); //2

@Override } catch ( SQLException e ) {

private Utilisateur trouver( String email ) throws throw new DAOException( e );

DAOException { } finally {

Connection connexion = null; closeRessource( resultSet, preparedStatement, connexion

PreparedStatement preparedStatement = null; );//3


ResultSet resultSet = null;
}
Utilisateur utilisateur = null;
return utilisateur;
} 63
MISE EN PLACE

Etapes 8:
Méthode creer()

private static final String SQL_INSERT = "INSERT INTO


Utilisateur (email, mot_de_passe, nom, date_inscription) try {
VALUES (?, ?, ?, NOW())";
connexion = daoFactory.getConnection(); //1
preparedStatement = initialisationRequetePreparee(
@Override
connexion, SQL_INSERT, true, utilisateur.getEmail(),
public void creer( Utilisateur utilisateur ) throws
DAOException { utilisateur.getMotDePasse(), utilisateur.getNom() ); //2

Connection connexion = null; int statut = preparedStatement.executeUpdate();

PreparedStatement preparedStatement = null;


ResultSet valeursAutoGenerees = null;

64
MISE EN PLACE

Etapes 8: Méthode creer()


else {
throw new DAOException( "Échec de la création de

if ( statut == 0 ) { l'utilisateur en base, aucun ID auto-généré retourné." );

throw new DAOException( "Échec de la création de }

l'utilisateur, aucune ligne ajoutée dans la table." ); } catch ( SQLException e ) {

} throw new DAOException( e );

valeursAutoGenerees = }

preparedStatement.getGeneratedKeys(); finally {

if ( valeursAutoGenerees.next() ) { closeRessource( valeursAutoGenerees,


utilisateur.setId( valeursAutoGenerees.getLong( 1 ) ); preparedStatement, connexion ); //3
} }
}
65
INTÉGRATION DAO DANS UNE APP JEE

Inscription utilisateur

1. Chargement de la DaoFactory
• Instanciation de cet objet une seule fois au démarrage de l’application
• Utiliser l'interface ServletContextListener.
• Méthode contextInitialized() appelée dès le démarrage de l'application, avant le
chargement des servlets et filtres du projet.

66
INTÉGRATION DAO DANS UNE APP JEE

Création du listener
public class InitialisationDaoFactory implements
/* Enregistrement dans un attribut ayant pour portée toute
ServletContextListener {
l'application */
private static final String ATT_DAO_FACTORY = "daofactory";
servletContext.setAttribute( ATT_DAO_FACTORY,
private DAOFactory daoFactory;
this.daoFactory );
}
@Override
public void contextInitialized( ServletContextEvent event
@Override
){
public void contextDestroyed( ServletContextEvent event
/* Récupération du ServletContext lors du chargement
){
de l'application */
/* Rien à réaliser lors de la fermeture de l'application... */
ServletContext servletContext = event.getServletContext();
}
/* Instanciation de notre DAOFactory */
}
this.daoFactory = DAOFactory.getInstance(); 67
INTÉGRATION DAO DANS UNE APP JEE

Configuration du listener

<listener>
<listener-class>com.projet.config.InitialisationDaoFactory</listener-class>
</listener>

68
INTÉGRATION DAO DANS UNE APP JEE
public class Inscription extends HttpServlet {
public static final String CONF_DAO_FACTORY = "daofactory";
public static final String ATT_USER = "utilisateur";
public static final String ATT_FORM = "form";
public static final String VUE = "/WEB-INF/inscription.jsp";

private UtilisateurDao utilisateurDao;

public void init() throws ServletException {


/* Récupération d'une instance de notre DAO Utilisateur */
this.utilisateurDao = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY )
).getUtilisateurDao();
}

public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,


IOException {
/* Affichage de la page d'inscription */
this.getServletContext().getRequestDispatcher( VUE ).forward( request, response );
} 69
INTÉGRATION DAO DANS UNE APP JEE

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

/* Traitement de la requête et récupération du bean en résultant */


Utilisateur utilisateur = form.inscrireUtilisateur( request );

/* Stockage du formulaire et du bean dans l'objet request */


request.setAttribute( ATT_FORM, form );
request.setAttribute( ATT_USER, utilisateur );

this.getServletContext().getRequestDispatcher( VUE ).forward( request, response );


}
}

70
INTÉGRATION DAO DANS UNE APP JEE

Méthode inscrireUtilisateur
public Utilisateur inscrireUtilisateur(
HttpServletRequest request ) {
if ( erreurs.isEmpty() ) {
String email = getValeurChamp( request, CHAMP_EMAIL
utilisateurDao.creer( utilisateur );
resultat = "Succès de l'inscription.";
);
} else {
String motDePasse = getValeurChamp( request,
resultat = "Échec de l'inscription.";
CHAMP_PASS );
}
String confirmation = getValeurChamp( request,
} catch ( DAOException e ) {
CHAMP_CONF );
resultat = "Échec de l'inscription : une erreur imprévue
String nom = getValeurChamp( request, CHAMP_NOM );
est survenue, merci de réessayer dans quelques instants.";
e.printStackTrace();
Utilisateur utilisateur = new Utilisateur();
}
try {
traiterEmail( email, utilisateur );
return utilisateur;
traiterMotsDePasse( motDePasse, confirmation,
}
utilisateur );
traiterNom( nom, utilisateur ); 71
RÉCAPITULONS (BONNE PRATIQUES)

 Le pattern DAO permet d'isoler l'accès aux données et leur stockage du reste de l'application.

 Mettre en place des exceptions spécifiques au DAO permet de masquer le type du stockage sous-
jascent.

 Mettre en place une Factory initialisée au démarrage de l'application via un


ServletContextListener permet de ne charger qu'une seule et unique fois le driver JDBC.

 Mettre en place des utilitaires pour la préparation des requêtes et la libération des ressources
permet de limiter la duplication et d'alléger grandement le code.

 Notre DAO libérant proprement les ressources qu'il met en jeu, une seule et unique instance de
notre DAO peut être partagée par toutes les requêtes entrantes.

72
RÉCAPITULONS (BONNE PRATIQUES)

 Récupérer une telle instance de DAO de manière unique depuis une servlet, et non pas à
chaque requête entrante, peut se faire simplement en utilisant sa méthode init().

 Une servlet transmet simplement l'instance du DAO à l'objet métier, qui sera responsable de
la gestion des données.

 L’objet métier ne connaît pas le système de stockage final utilisé : il ne fait qu'appeler les
méthodes définies dans l'interface de notre DAO.

73

You might also like