Ressource

Rappel

Dans la section dédiée au transaction JPA nous avons souligné deux cas

  • si nous sommes dans un contexte Java SE (l’ensemble des TP précédent) nous devions gérer les transactions et l’injection de dépendances
  • si nous utilisons un container EE, alors nous pouvons nous passer de la gestion des transactions et déléguer l’injection au CDI

L’objectif de ce TP est donc de découvrir ces concepts en implémentant une architecture en couche tout en factorisant le code nécessaire.

1. Installer TomEE et lancer le projet

Pour ce projet, nous avons besoin d’un container EE, nous allons utiliser TomEE.

  1. Installer TomEE et l’intégrer avec Eclipse ou IntelliJ

  2. Télécharger et importer le projet Maven dans Eclipse

  3. Lancer Docker Desktop + docker compose up pour la base de données

  4. Lancer en mode debug pour bénéficier du How Swap

  5. Rendez-vous sur l’url pour voir si tout fonctionne (attention au port)

    • http://localhost:9080/jpa-ee-container/helloworld

2. Consignes

Note : pour créer des objets JSON vous pouvez regarder

Partie 1. GenericDAO

  • Créer une entité générique BaseEntity qui contiendra l’identifiant commun à toutes les entités.
  • Créer une classe générique GenericDAO<T> pour gérer les opérations CRUD.
    • Injecter l’entityManager avec @PersistenceContext(unitName = "myPU")
    • Coder les méthodes create(), find(), delete() et findAll()
  • Créer une entité Student avec les annotations JPA.
  • Créer un DAO spécifique StudentDAO qui hérite du GenericDAO.
  • Créer un service StudentService sous forme d’un EJB pour gérer les étudiants.
  • Créer une ressource REST StudentController pour exposer les opérations via une API REST.

Exemple curl -X GET "http://localhost:8080/jpa-ee-container/students" -H "Accept: application/json"

Partie 1b. Rajouter les Soirées

Les étudiants peuvent participer à des soirées; lorsqu’on récupère un étudiant nous souhaitons lister les soirées où il a participer.

— M’appeler

  • comment régler les références circulaires ?
  • comment éviter la LazyInitializationException

Partie 2. Pagination

L’objectif de cette deuxième partie est d’ajouter une fonctionnalité de pagination aux requêtes de récupération des données dans notre GenericDAO.

  • Ajouter la méthode List<T> findAllPaginated(int page, int size)
  • Ajouter la méthode long count()

Modifier en conséquence StudentService pour exploiter la pagination et StudentController

// Controller
Response getAllStudents(@QueryParam("page") @DefaultValue("0") int page, @QueryParam("size") @DefaultValue("10") int size) {
}

— M’appeler

  • à quoi ressemble le retour de l’API ?

Partie 3. Spécification/Criteria API

Nous allons ajouter une méthode findByCriteria(Map<String, Object> criteria) qui permet de rechercher des entités selon des conditions dynamiques.

  • Dans GenericDAO nous allons coder cette fonction. On peut s’appuyer la notion de predicate qui peuvent être chaînés via and ou or (nous on fera du and). Exemple 1
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Predicate predicate1 = cb.equal(pet.get(Pet_.name), "Fido");  // création d'un prédicat
Predicate predicate2 = cb.equal(pet.get(Pet_.color), "brown"); // création d'un second prédicat
cq.where(predicate1.and(predicate2)); // chaine via and
  • Puis dans les classes concrètent qui hérite de GenericDAO nous allons créer nos Prédicats puis appeler cette méthode
    • Coder List<Student> searchStudents(String name, Integer age)
    • qui va créer un prédicat puis appeler la méthode findByCriteria

Complément

Pour ce qui ont fini, vous pouvez rajouter la notion d’héritage

  • Étudiant et Professeurs sont des Personnes
  • Les Personnes peuvent participer à des soirées

Footnotes

  1. https://stackoverflow.com/a/47604610/9399016