Le modèle correspond aux données de notre système. Il s’agit de savoir comment stocker l’information. Un Object Relationship Mapper s'assure de faire le lien entre un modèle objet et une base de données relationnelle. Le lien peut se faire dans 2 directions:
- Créer automatiquement des classes objets à partir d'une base de données existante.
- Créer des classes objets et demander la génération automatique d'une base de données relationnelle qui stockera ces objets.
C'est cette seconde possibilité que nous allons utiliser dans notre application.
pom.xml : EclipseLink
EclipseLink est l'implémentation de référence de la norme JPA. Il s'agit donc d'un des nombreux moteurs permettant de stocker des objets en base de données. Il existe d'autres implémentations, la plus connue étant certainement Hibernate. Afin d'inclure EclipseLink, il va nous falloir ajouter un repository dans notre pom.xml. Ajoutez la balise suivante juste avant la balise dependencies de votre pom.xml:
<repositories> <repository> <id>eclipselink</id> <url>http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo/</url> </repository> </repositories>
Ensuite, ajoutez la dépendance suivante:
<dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.4.0</version> </dependency>
pom.xml : Derby (Apache)
Apache Derby est une base de données qui peut être embarquée. Autrement dit, elle se lance quand le serveur est lancé. Nous l'utiliserons ici pour simplifier puisqu'il n'y a pas besoin d'installer de serveur de base de données séparé.
<dependency> <groupId>org.apache.derby</groupId> <artifactId>derby</artifactId> <version>10.9.1.0</version> </dependency> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derbyclient</artifactId> <version>10.9.1.0</version> </dependency>JPA, première entité
JPA fonctionne en déclarant des classes comme des entités. Une entité va être un classe Java pour laquelle nous allons déclarer un champ identifiant. Voici le code de notre première entité:
package com.deguet.model;
import java.io.Serializable;
import javax.persistence.*;
@Entity
public class Test implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String content;
public int getId(){return this.id;}
public void setId(int idImages) {this.id = idImages;}
public String getContent() {return content;}
public void setContent(String content) {this.content = content;}
}
Cette classe est placée dans le package com.deguet.model. La différence la plus importante est ici la présence d'un identifiant id. En effet, la base de données a besoin d'un identifiant explicite. (ce n'est pas le cas en objet, l'objet étant identifié par sa référence, implicite).
persistence.xml
JPA se repose sur le fichier persistence.xml pour décrire la base de données à utiliser et les classe Java faisant partie du modèle. Le fichier persistence.xml doit se trouver dans WEB-INF/classes/META-INF/persistence.xml.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="RestoPresto">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.deguet.model.Test</class>
<properties>
<property name="javax.persistence.jdbc.password" value="app" />
<property name="javax.persistence.jdbc.user" value="app" />
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:derby:databasederby/resto;create=true" />
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.drop-ddl-jdbc-file-name" value="ddl.jdbc"/>
<property name="eclipselink.ddl-generation.output-mode" value="both" />
<property name="eclipselink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
</persistence>
Nous avons défini une unité de persistence. Vous remarquerez les points suivants:
- Chaque classe d'entité (ici Test) doit être déclarée dans le fichier.
- l'URL pour la base de données derby est en fait un chemin vers le répertoire databasederby qui sera créé dans le répertoire de votre projet.
- la propriété ddl-generation indique à EclipseLink qu'il doit détruire et recréer la base de données à chaque exécution (drop and create).
- la propriété drop-ddl-jdbc-file-name permet de récupérer les scripts de création de la base (dans le fichier ddl.jdbc) afin de déboguer un éventuel problème à la génération de la base.
Facade CRUD pour notre entité
JPA se repose sur un EntityManager pour effectuer les opérations en base de données.
Les opérations CRUD (Create Retrieve Update Delete) nécessite d'accéder à un EntityManager afin d'exécuter les requêtes correspondantes. Afin de faciliter la compréhension voici une classe permettant d'effectuer les opérations de base (création, mise à jour, récupération ou suppression) pour une entité T:
package com.deguet;
import java.util.List;
import javax.persistence.*;
public class Facade<T> {
Class<T> entityClass;
@PersistenceContext(unitName = "RestoPresto")
private static EntityManager em;
protected EntityManager getEntityManager() {return em;}
public Facade(Class<T> entityClass) {
if (em == null){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("RestoPresto");
em = emf.createEntityManager();
}
this.entityClass = entityClass;
}
public void create(T entity) {
EntityManager em = getEntityManager();
em.getTransaction().begin();
if (!em.contains(entity)) {
em.persist(entity);
em.flush();
}
em.getTransaction().commit();
}
public void edit(T entity) {
EntityManager em = getEntityManager();
em.getTransaction().begin();
em.merge(entity);
em.flush();
em.getTransaction().commit();
}
public void remove(T entity) {
EntityManager em = getEntityManager();
em.getTransaction().begin();
T toDelete = em.merge(entity);
em.remove(toDelete);
em.flush();
em.getTransaction().commit();
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
public int count() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
javax.persistence.criteria.Root<t> rt = cq.from(entityClass);
cq.select(getEntityManager().getCriteriaBuilder().count(rt));
javax.persistence.Query q = getEntityManager().createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
}
}
Test dans le contrôleur
Pour tester que tout fonctionne correctement, nous allons maintenant tester la création d'un objet puis la récupération de la liste d'objets dans un nouveau motif URL dans notre contrôleur.
Tout d'abord vous devez créer une facade pour notre entité avec la ligne suivante:
Facade<Test> facade = new Facade<Test>(Test.class);
Ensuite il faut créer le motif URL permettant de déclencher la création d'un nouvel objet, sa sauvegarde puis la récupération de la liste complète.
if (action.equals("/testCharge")){
System.out.println("Controler GET acheter ");
Test t = new Test();
t.setContent("bli blo " + System.currentTimeMillis());
facade.create(t);
List<Test> tests = facade.findAll();
for (Test test : tests){
System.out.println("Le test est " + test);
}
return;
}
En rechargeant plusieurs fois la page, http://localhost:7070/testCharge vous verrez la liste d'entités s'allonger.
Fichiers du projet avec une entité
Vous trouverez le projet avec l'écriture d'une entité en base de données ici.
Aucun commentaire:
Enregistrer un commentaire