d3:tp04:jpa

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
d3:tp04:jpa [2025/10/12 20:00] – [3. Créer un DAO] dthevenotd3:tp04:jpa [2025/10/12 20:25] (Version actuelle) – supprimée dthevenot
Ligne 1: Ligne 1:
-====== D3-TP04 : Projet gestion de clients - Persistence des données avec un ORM - JPA de Payara ====== 
-<bootnote warning>On travaille sur une **copie du projet "Gestion de clients"** en jakartaa</bootnote> 
-===== ORM ===== 
-Un ORM est un ensemble de bibliothèques permettant de mapper (faire correspondre) les structures de données orientées objet d'un langage de programmation avec les tables d'une base de données relationnelle. L'objectif est de simplifier et d'abstraire les opérations de base de données pour le développeur, en permettant de manipuler les données comme s'il s'agissait d'objets dans le langage de programmation choisi. 
- 
-L'ORM offre plusieurs avantages significatifs : 
- 
-  * Abstraction des détails de la base de données : Le développeur n'a pas besoin de connaître le langage SQL spécifique au SGBDR utilisé. 
-  * Productivité accrue : Les opérations CRUD (Create, Read, Update, Delete) sont simplifiées, souvent réduites à de simples appels de méthodes. 
-  * Maintenabilité : Le code est plus lisible et plus facile à maintenir, car il reflète directement les structures de données utilisées par l'application. 
-  * Sécurité : Beaucoup d'ORMs intègrent des mécanismes de prévention des injections SQL. 
-===== JPA ===== 
-JPA est un acronyme qui signifie **Java Persistence API**. C'est évolution de l'approche JDBC classique (“API bas niveau” : classe Connexion, ClientMysql avec Statement, ResultSet etc.) → **API standard pour l’utilisation d’un ORM** 
- 
-==== 1-La datasource ==== 
-Dans Payara il faut une **DataSource JDBC jdbc/bdclient pointant vers ta base MariaDB**. 
- 
-Définir la ressource JNDI sur ton serveur 
-  - Aller sur : http://localhost:4848 
-  - Menu : Resources → JDBC → JDBC Connection Pools 
-  - Créer un pool de connexions (ex. : MonPoolMariaDB)  
-    - Pool Name : MonPoolMariaDB 
-    - Resource Type : javax.sql.DataSource 
-    - Classname : org.mariadb.jdbc.MariaDbDataSource 
-    - Database Vendor : MySQL (MariaDB est compatible MySQL) 
-    - Next 
-    - Propriétés additionnelles :{{:promo_2026:sio2:slam:d3:ppespoolmariadbgestionclient.png?600|}} 
-    - Finish 
-<badge>Ping : OK ! **OBLIGATOIRE**</badge> 
-<bootnote>JNDI signifie Java Naming and Directory Interface, cette API permet : 
-  * d’accéder à différents services de nommage ou de répertoire de façon uniforme ; 
-  * d'organiser et rechercher des informations ou des objets par nommage (java naming and directory interface) ; 
-  * de faire des opérations sur des annuaires (java naming and directory interface) 
-</bootnote> 
-Créer la JDBC Resource (source de données JDBC) : 
-  - Menu : Resources → JDBC → JDBC Resources 
-  - Clique sur New... 
-  - Configure : 
-    - JNDI Name : **jdbc/bdclient** (nom utilisé dans ton code Jakarta EE) 
-    - Pool Name : monPoolMariaDB 
-    - Clique sur OK 
- 
- 
-==== 2-Configurer la persistence avec JPA ==== 
-=== a) Les dépendances JPA === 
-Le projet va inclure : 
-  * Jakarta Persistence (jakarta.persistence-api) 
-  * Une implémentation JPA (ex. : EclipseLink, inclus avec Payara) 
-  * Le driver MariaDB (mariadb-java-client) 
-<code ruby pom.xml> 
-    <dependency> 
-        <groupId>jakarta.platform</groupId> 
-        <artifactId>jakarta.jakartaee-web-api</artifactId> 
-        <version>10.0.0</version> 
-        <scope>provided</scope> 
-    </dependency> 
-    <dependency> 
-        <groupId>org.mariadb.jdbc</groupId> 
-        <artifactId>mariadb-java-client</artifactId> 
-        <version>3.3.2</version> 
-    </dependency> 
-</code> 
-=== b) persistence.xml === 
-Ce fichier indique à JPA comment se connecter à la base de données. 
- 
-Dans WEB-INF/classes/META-INF/ (dans NETBEANS : Other Sources - src/main/resources-META-INF), créer un fichier (Source) :  
-<code ruby persistence.xml> 
- <!-- Define Persistence Unit --> 
-  <persistence-unit name="bdclientPU" transaction-type="JTA"> 
-    <jta-data-source>jdbc/bdclient</jta-data-source> 
-    <properties> 
-      <property name="jakarta.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver"/> 
-      <property name="jakarta.persistence.jdbc.url" value="jdbc:mariadb://192.168.100.100/bdclient"/> 
-      <property name="jakarta.persistence.jdbc.user" value="adminBDClient"/> 
-      <property name="jakarta.persistence.jdbc.password" value="mdpBDClient"/> 
-      <!-- Optionnel : génération du schéma --> 
-      <property name="jakarta.persistence.schema-generation.database.action" value="none"/> 
-    </properties> 
-  </persistence-unit> 
-</code> 
-==== Les transactions ==== 
-__Rappel__ :Une transaction est une série d’actions qui doivent toutes se terminer avec succès, sinon toutes les modifications apportées à chaque action sont annulées. Les transactions se terminent par une validation ou une annulation. 
- 
-Deux modes de gestion de transactions dans JPA : 
-  * JTA (Java Transaction API) – mode container-managed 
-Utilisé dans les serveurs d’application comme WildFly, Payara, GlassFish, TomEE, etc. Les transactions sont gérées par le conteneur. 
- 
-Les transactions gérées par conteneur simplifient le développement, car le code de l'EJB (Enterprise JavaBeans) ne marque pas explicitement les limites de la transaction. Le code n’inclut pas les instructions qui commencent et terminent la transaction. Par défaut, si aucune démarcation de transaction n’est spécifiée, les EJB utilisent la démarcation de transaction gérée par conteneur. 
- 
-En règle générale, le conteneur commence une transaction immédiatement avant le démarrage d’une méthode et valide la transaction juste avant la fermeture de la méthode. Chaque méthode peut être associée à une seule transaction. Les transactions imbriquées ou multiples ne sont pas autorisées dans une méthode. 
- 
-  * RESOURCE_LOCAL – mode application-managed 
-Utilisé dans les applis standalone (Java SE, Spring Boot sans conteneur JEE). Les transactions sont gérées par le code (ex : getTransaction(), begin(), commit()). 
- 
-<bootnote>Nous utiliserons le mode conteneur **JTA** permis avec Payara (voir fichier **persistence.xml** ci-dessus) 
-  <persistence-unit name="bdclientPU" transaction-type="JTA"> 
-    <jta-data-source>jdbc/bdclient</jta-data-source> 
-</bootnote> 
-==== L'EJB ==== 
-EJB est une spécification Java pour créer des composants métier côté serveur, qui permettent de gérer automatiquement: 
-  * La logique métier (ex : traitement de commandes, calculs…) 
-  * La sécurité 
-  * La transaction 
-  * La concurrence 
- 
-Types principaux d’EJB 
-  - **Stateless (@Stateless)** : 
-    - Pas d’état entre les appels. 
-    - Idéal pour des services comme “calculer le prix d’une commande”. 
-    - Exemple : un service qui ne se soucie pas de qui l’a appelé avant. 
-  - Stateful (@Stateful) : 
-    - Garde un état pour chaque client. 
-    - Exemple : panier d’achat en session. 
-  - Singleton (@Singleton) : 
-    - Une seule instance partagée pour tous les clients. 
-    - Exemple : compteur global ou cache partagé. 
-==== 3-Créer l’entité Client utilisable par la JPA  ==== 
-Une entité JPA est très proche d’une classe java Bean (Client), mais avec quelques annotations supplémentaires pour que JPA sache comment la relier à la base de données. 
-<bootnote warning>Pour ne pas changer tout le code, l'entité vas s'appeller **Client**, renommer pour l'instant la **javabean Client en ClientOld** pour garder le code visible mais à terme il ne sera plus utilisé</bootnote> 
-Au lieu d’une classe java Client, on fait une **Entity** : 
-  * "New > Entity Class" : création de l'entité à la main, définition des attributs, des annotations (@Entity, @Id, etc.) et de la correspondance avec la table. 
-  * "New > Entity Classes from Database" : NetBeans génère automatiquement les classes d’entités à partir de la base existante (via la connexion JDBC). 
- 
-Nous allons créer l'entity JPA manuellement pour avoir l'équivalent de la classe Client : 
-<code ruby entité Client> 
-package com.Test.entities; 
-import jakarta.persistence.*; 
- 
-//Annotations pour la JPA 
-@Entity                   // indique que c’est une entité gérée par JPA 
-@Table(name = "client"  // nom de la table SQL dans la bd liée 
- 
-public class Client { 
-  
-    //Annotations pour gérer id auto-incrémenté 
-    @Id 
-    @GeneratedValue(strategy = GenerationType.IDENTITY)  // clé primaire auto-incrémentée 
-    private int id; 
-  
-    private String nom; 
-    private String prenom; 
-    private String mail; 
-  
-    public Client() {}  // obligatoire pour JPA (constructeur vide) 
-  
-    public Client(int id, String nom, String prenom, String mail) { 
-        this.id=id; 
-        this.nom = nom; 
-        this.prenom = prenom; 
-        this.mail = mail; 
-    } 
-     
-    public Client(String nom, String prenom, String mail) { 
-        this.nom = nom; 
-        this.prenom = prenom; 
-        this.mail = mail; 
-    } 
-  
-    // Getters, setters, toString() identiques 
-    public int getId() { return id; } 
-    public void setId(int id) { this.id = id; } 
-    public String getNom() { return nom; } 
-    public void setNom(String nom) { this.nom = nom; } 
-    public String getPrenom() { return prenom; } 
-    public void setPrenom(String prenom) { this.prenom = prenom; } 
-    public String getMail() { return mail; } 
-    public void setMail(String mail) { this.mail = mail; } 
-  
-    @Override 
-    public String toString() { 
-        return "Client{" + "id=" + id + ", nom=" + nom + ", prenom=" + prenom + ", mail=" + mail + '}'; 
-    } 
-} 
-</code> 
-<badge>Comparaison</badge> 
-^Élément ^Classe Java simple ^Classe JPA Entity^ 
-|Utilisation |Objet métier (logique applicative) |Objet persistant (lié à une table SQL)| 
-|Base de données|Aucune relation directe|Mappée à une table| 
-|Annotations |Aucune |@Entity, @Id, @Table, etc.| 
-|Constructeur vide|Optionnel|Obligatoire| 
-|Gestion SQL |Fait à la main (JDBC)|Automatique (via EntityManager)| 
-==== 3. Créer un DAO  ==== 
-La classe java **ClientMysql** est un DAO (Data Access Object) en mode **JDBC classique** (Connection, Statement, ResultSet, etc.) 
- 
-Passer à JPA va permettre de simplifier le code, tout en gardant la même logique métier (lire tous les clients, créer un client, etc.). 
- 
-<bootnote warning>Version JPA de la classe ClientMysql : la classe **ClientJPA**, à terme ClientMysql ne sera plus utilisé</bootnote> 
-<code ruby ClientJpa> 
-@Stateless //type EJB, logique métier, à injecter dans les autres classes avec @EJB 
-public class ClientJPA { 
-     
-    @PersistenceContext(unitName = "bdclientPU") //en lien avec le fichier persistence.xml :  <persistence-unit name="bdclientPU" transaction-type="JTA"> 
-    private EntityManager em; 
-     
-    // Lecture de tous les clients 
-    public List<Client> readAll() { 
-        List<Client> lesClients = em.createQuery("SELECT c FROM Client c", Client.class).getResultList(); 
-        return lesClients; 
-    } 
-  
-    // Création d’un client 
-    public int create(Client unClient) { 
-        em.persist(unClient);         // enregistre l’objet en base 
-        // Force la synchro avec la base pour récupérer l’ID tout de suite 
-        em.flush(); 
-        return unClient.getId();      // l’ID est rempli automatiquement par JPA 
-    } 
-} 
-</code> 
-<badge>Comparaison</badge> 
-^Action ^JDBC (ClientMysql) ^JPA (ClientJpa)^ 
-|Connexion à la base |Connection, PreparedStatement, ResultSet |EntityManager (géré par JPA)| 
-|Lecture |Boucle while(resultSet.next()) |SELECT c FROM Client c (JPQL)| 
-|Insertion |INSERT INTO ... VALUES (...) |em.persist(client)| 
-|Gestion des transactions |Manuelle (implémentée ou pas) |Automatique via em.getTransaction()| 
-|Fermeture |stmt.close(), resultSet.close() |em.close()| 
- 
-<badge>A retenir</badge> 
-^Notion ^Explication^ 
-|EntityManagerFactory |Point d’entrée JPA (selon le fichier persistence.xml)| 
-|EntityManager |Objet qui gère les entités (sélection, insertion, etc.)=objet fourni par JPA pour interagir avec la base de données.| 
-|persist() |Dit à JPA d’insérer l’objet dans la table correspondante| 
-|JPQL |Langage de requête orienté objets au lieu de SQL| 
- 
-| |exemple : SELECT c FROM Client c |Client est l’entité.| | 
-| | |c est un alias qu’on utilise pour faire référence à chaque client.| 
-| | |SELECT c signifie : « prends tous les clients ».| 
-| | |Client.class indique le type de retour attendu : ici, chaque résultat sera un objet Client.| 
- 
-==== 4-Adaptation de l'application : Création d'un client avec JPA  ==== 
-=== Modification de la classe NouveauClientForm === 
-Prise en compte du conteneur : modification de la déclaration de la dao qui devient une propriété de la classe 
-<code> 
-@Stateless //type EJB 
-public class NouveauClientForm { 
-    @EJB //pour utiliser la classe ClientJPA définie en @Stateless 
-    private ClientJPA dao; 
-     
-    private String resultat; 
- 
-    public String getResultat() { 
-        return resultat; 
-    } 
- 
-    public void setResultat(String resultat) { 
-        this.resultat = resultat; 
-    } 
-     
-    public int verifierClient(HttpServletRequest request){ 
-        int id=-1; 
-       
-        String leNom = request.getParameter("nom"); 
-        String lePrenom =request.getParameter("prenom"); 
-         
-        if ((lePrenom.matches("[A-Za-zÀ-ÖØ-öø-ÿ' -]{1,100}"))&& (leNom.matches("[A-Za-zÀ-ÖØ-öø-ÿ' -]{1,100}"))){ 
-            Client cliSaisi = new Client(request.getParameter("nom"),request.getParameter("prenom"),request.getParameter("mail") ); 
-            int idCree = dao.create(cliSaisi); 
-            System.out.println("Client créé avec id : " + idCree); 
-        } 
-        return id; 
-    } 
-} 
- 
-<bootnote>La classe Client utilisée est maintenant l'entité JPA créée précédemment</bootnote> 
-=== Modification de la servlet NouveauServlet.java === 
-Prise en compte du conteneur : modification de la déclaration de l'objet NouveauClientForm qui devient une propriété de la classe 
-<code> 
- @EJB 
- private NouveauClientForm leControle; // injecté par Jakarta EE grâce à @EJB, géré par le contrôleur 
-</code> 
- 
- 
  
  • d3/tp04/jpa.1760292032.txt.gz
  • Dernière modification : 2025/10/12 20:00
  • de dthevenot