Dans le chapitre précédent, vous avez découvert qu’avec Spring Data JPA, il suffit de créer des interfaces pour interagir avec la base de données.
Cependant, nous n’avons pas encore interagi concrètement avec la base de données. Nous allons remédier à cela en commençant par la récupération de données.
L’un des rôles fondamentaux d’une base de données est de donner accès à ses données à ceux qui y sont autorisés. Imaginez une boîte scellée impossible à ouvrir, même si cette boîte renferme un contenu précieux, elle nous serait malheureusement complètement inutile !
Dans le cadre des applications Java, accéder aux données va rendre nos applications dynamiques. En fonction des données récupérées, on pourra adapter le comportement de l’application !
Pour récupérer ces données, nous allons modifier les classes :
com.openclassrooms.datalayer.service.ProductService ;
com.openclassrooms.datalayer.DataLayerApplication.
L’objectif étant de pouvoir afficher le résultat de nos opérations dans la console.
Commençons par adapter la classe DataLayerApplication :
package com.openclassrooms.datalayer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.openclassrooms.datalayer.service.ProductService;
@SpringBootApplication
public class DataLayerApplication implements CommandLineRunner {
@Autowired
private ProductService productService;
public static void main(String[] args) {
SpringApplication.run(DataLayerApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
}
}
Les modifications sont les suivantes :
La classe implémente désormais l’interface CommandLineRunner (ligne 11).
La classe implémente à la ligne 21 une méthode public void run(String... args) throws Exception : c’est le résultat de l’implémentation de l’interface précédente.
La classe possède un attribut de type ProductService et annoté @Autowired (lignes 13-14). On obtient ainsi un objet instancié correspondant à la classe ProductService.
Récupérez un ensemble de données
L’application Carlib Assurances doit pouvoir afficher la liste de tous les produits enregistrés en base de données. C’est un grand classique dans le développement logiciel que d’afficher toutes les valeurs d’une table !
Pour implémenter cette fonctionnalité, dans la classe ProductService, nous allons :
Ajouter un attribut de type ProductRepository avec un @Autowired.
Ajouter une nouvelle méthode : getProducts().
Au sein de cette méthode, nous utilisons l’attribut productRepository.
Notez les méthodes de l’objet auxquelles nous accédons via l'autocomplétion de l’IDE sur productRepository :
L’interface ‘CrudRepository’ donne accès à de nombreuses méthodes comme count, delete, findAll, save, etc.
Les méthodes liées à la lecture de données commencent par le mot clé find et sont au nombre de 3 :
findAll : permet de récupérer toutes les données de la table associée.
findAllById : permet de récupérer un ensemble de données à partir d’une liste d’id.
findById : permet de récupérer une ligne de la table à partir de l’id.
Utilisons donc findAll pour la fonctionnalité que nous sommes en train d’implémenter.
Retrouvez-moi dans le screencast qui suit :
package com.openclassrooms.datalayer.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.openclassrooms.datalayer.model.Product;
import com.openclassrooms.datalayer.repository.ProductRepository;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Iterable<Product> getProducts() {
return productRepository.findAll();
}
}
Le contenu de la méthode est assez simple. Il s’agit de retourner le résultat de l’appel à findAll().
Maintenant, adaptons le comportement de la classe DataLayerApplication pour tester cette nouvelle méthode :
package com.openclassrooms.datalayer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.openclassrooms.datalayer.model.Product;
import com.openclassrooms.datalayer.service.ProductService;
@SpringBootApplication
public class DataLayerApplication implements CommandLineRunner {
@Autowired
private ProductService productService;
public static void main(String[] args) {
SpringApplication.run(DataLayerApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
Iterable<Product> products = productService.getProducts();
products.forEach(product -> System.out.println(product.getName()));
}
}
Ligne 24, nous affectons le résultat de l’appel à la méthode getProducts à une variable de type Iterable<Product>.
Ligne 25, grâce à la méthode forEach, nous parcourons la liste et affichons le nom de chaque produit.
À vous de jouer !
Répétez cette opération pour Category et Comment.
Pour la correction, vous pouvez retrouver le code dans le repository du cours à la branche p2c2.
Récupérez une donnée de façon unitaire
Vous êtes désormais capable de récupérer tous les produits, mais l’application Carlib Assurances doit également afficher chaque produit de façon unitaire.
Pour éviter ce problème, nous devons être capables de récupérer un produit via un critère qui lui est propre. Au sein des bases de données relationnelles, ce critère est l’ID. Nous allons donc apprendre à récupérer un produit par son id.
Sachez d’ailleurs que récupérer une donnée de façon unitaire à partir d’un critère (ou de plusieurs critères) est l’une des opérations les plus communes.
Dans la classe ProductService, nous allons ajouter une nouvelle méthode public Optional<Product> getProductById(Integer id) qui tirera profit de la méthode findById (énoncée précédemment).
Voyons cela :
package com.openclassrooms.datalayer.service;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.openclassrooms.datalayer.model.Product;
import com.openclassrooms.datalayer.repository.ProductRepository;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Iterable<Product> getProducts() {
return productRepository.findAll();
}
public Optional<Product> getProductById(Integer id) {
return productRepository.findById(id);
}
}
Notons qu’encore une fois, la méthode getProduct sert uniquement à contacter la couche Repository et à retourner la valeur obtenue.
Adaptons maintenant le code de la classe DataLayerApplication :
package com.openclassrooms.datalayer;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.openclassrooms.datalayer.model.Product;
import com.openclassrooms.datalayer.service.ProductService;
@SpringBootApplication
public class DataLayerApplication implements CommandLineRunner {
@Autowired
private ProductService productService;
public static void main(String[] args) {
SpringApplication.run(DataLayerApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
Optional<Product> optProduct = productService.getProductById(1);
Product productId1 = optProduct.get();
System.out.println(productId1.getName());
}
}
Quelques explications supplémentaires sont nécessaires :
Ligne 26 : la méthode getProductById renvoie un objet de type Optional. Cet objet permet d’encapsuler le résultat de la requête à la base de données. Dans le cas où la BDD contient un produit avec l’ID demandé, alors un objet Product sera instancié et encapsulé dans l’objet Optional. Dans le cas inverse, l’objet Optional est tout de même instancié, mais il contient un objet null.
Ligne 27 : pour récupérer l’objet encapsulé, j’utilise la méthode get().
À vous de jouer !
À l’aide des interfaces et des classes que vous avez créées dans le chapitre précédent pour les entités Category et Comment, implémentez la récupération unitaire d’une catégorie et d’un commentaire !
Encore une fois, vous avez pu observer qu’il n’y a quasiment aucune différence entre récupérer de façon unitaire un produit, une catégorie ou bien un commentaire.
Pour la correction, vous pouvez regarder le code du repository du cours à la branche p2c2.
En résumé
L’interface CrudRepository donne accès à de nombreuses méthodes pour interagir avec la base de données.
Pour récupérer un ensemble de données, nous avons utilisé findAll() qui renvoie une liste d’objets correspondant à toutes les données de la table associée à l’entité concernée.
Pour récupérer une donnée précise, nous avons utilisé findById(Integer id), qui renvoie un unique objet correspondant à l’ID demandé.
Tout cela à l’air presque trop facile ! Ne vous inquiétez pas, on va ajouter un peu de complexité avec les relations ! Découvrons-les ensemble dans le prochain chapitre !