Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 25

Pagination et tri des résultats de requête

Recommended resources

Bonjour ! Dans la leçon précédente, nous avons appris à écrire des requêtes personnalisées puissantes et sécurisées avec JPQL et l'annotation @Query. Vous avez même eu un aperçu du paramètre Pageable, qui est la transition parfaite pour notre sujet du jour.

Lorsque votre application gère des milliers, voire des millions d'enregistrements, renvoyer toutes les données en une seule fois est une très mauvaise pratique. Cela sature le serveur, le réseau et le client. L'objectif de cette leçon est donc d'implémenter la pagination et le tri sur les résultats de requêtes. C'est une compétence fondamentale pour tout développeur backend souhaitant construire des API REST professionnelles, performantes et évolutives.

Nous verrons comment Spring Data JPA rend cette tâche remarquablement simple et élégante.

1. Les concepts clés : Pageable, Sort et Page

Avant de coder, comprenons les trois principaux outils que Spring Data met à notre disposition. Votre expérience en développement vous a sûrement déjà confronté à la nécessité de paginer des résultats, par exemple en utilisant LIMIT et OFFSET en SQL. L'approche de Spring Data est plus structurée et orientée objet.

Pour une introduction claire à ces concepts, je vous propose de lire la première partie de l'article suivant.

Maîtriser Spring Data JPA – Pagination, tri et requêtes personnalisées

Cet article, intitulé "Maîtriser Spring Data JPA", explique de manière très concise les concepts de pagination et de tri. Il vous donnera les bases théoriques nécessaires pour la suite.

Lisez la section 1, intitulée "Pagination et tri – Gérer efficacement de grands ensembles de données". Concentrez-vous sur la définition des termes Pagination, PagingAndSortingRepository, et Classement (Sorting).

Pour résumer et organiser ces informations :

  • Pageable: C'est une interface qui représente une demande de "page" d'informations. Elle contient typiquement :

    • Le numéro de la page (commençant à 0).
    • La taille de la page (le nombre d'éléments par page).
    • Les informations de tri (Sort).
  • Sort: Un objet qui encapsule les critères de tri. Vous pouvez spécifier une ou plusieurs propriétés sur lesquelles trier, ainsi que la direction (ascendante ASC ou descendante DESC).

  • Page<T>: C'est le type de retour pour une requête paginée. Il est plus riche qu'une simple List<T>. En plus de la liste des éléments pour la page courante, il contient des métadonnées cruciales :

    • Le nombre total d'éléments sur toutes les pages.
    • Le nombre total de pages.
    • Si c'est la première ou la dernière page.
API Response for Paginated Tutorials
Exemple de réponse JSON d'une API qui renvoie un objet `Page`. Notez les métadonnées comme `totalItems`, `totalPages` et `currentPage`, qui sont essentielles pour qu'un client (comme votre application React) puisse construire une interface de pagination.

2. La hiérarchie des Repositories

Vous avez déjà utilisé JpaRepository. Il est utile de comprendre d'où viennent ses capacités de pagination et de tri.

Spring Data Repository Interface Hierarchy
Cette image montre la chaîne d'héritage des interfaces de repository dans Spring Data. `JpaRepository` hérite de `PagingAndSortingRepository`, qui lui-même hérite de `CrudRepository`. C'est de `PagingAndSortingRepository` que proviennent les méthodes de base comme `findAll(Pageable pageable)`.

Grâce à cet héritage, toute interface qui étend JpaRepository (ou PagingAndSortingRepository) bénéficie automatiquement de la prise en charge de la pagination et du tri.


3. Implémentation pratique de la pagination et du tri

Passons maintenant à la pratique. La meilleure façon d'apprendre est de suivre un exemple complet. La vidéo suivante est un excellent guide pas à pas pour implémenter la pagination et le tri dans une application Spring Boot.

L'auteur construit une API pour gérer des produits, en ajoutant progressivement la pagination, le tri et le filtrage. Cela combine parfaitement ce que nous avons vu dans la leçon précédente et ce que nous apprenons aujourd'hui.

Spring Boot | Pagination et Filtre avec Spring Data JPA

Cette vidéo de Coding With Armand, "Spring Boot | Pagination et Filtre avec Spring Data JPA", est un cas pratique complet et très bien expliqué en français. Nous allons nous concentrer sur les parties qui implémentent la pagination et le tri.

Regardez la vidéo à partir de 04:59 jusqu'à la fin. L'auteur a déjà mis en place le projet et l'entité. Suivez attentivement les étapes suivantes : Couche Repository (04:59 - 08:58) : Observez comment le paramètre Pageable est ajouté aux méthodes du repository, y compris à une requête personnalisée @Query. Cela permet de dire à Spring Data que la requête doit être paginée. Couche Service (08:58 - 13:15) : C'est une partie cruciale. Voyez comment l'auteur construit un objet Sort à partir de paramètres de requête (chaînes de caractères) et ensuite un objet Pageable via PageRequest.of(). Couche Controller (13:15 - 18:01) : Notez l'utilisation de @RequestParam pour capturer les paramètres de pagination et de tri depuis l'URL (page, size, sortBy, sortOrder), en définissant des valeurs par défaut pour les rendre optionnels. Test avec Swagger UI (18:01 - 21:47) : Cette dernière partie vous montre le résultat concret. Voyez comment l'API est testée avec différentes valeurs de pagination et de tri, et analysez la structure de la réponse JSON paginée.


4. Analyse du code et des bonnes pratiques

Reprenons les points essentiels vus dans la vidéo.

Couche Repository

Pour rendre une méthode de repository paginable, il suffit d'ajouter un paramètre de type Pageable et de s'assurer que le type de retour est Page<T>.

// Dans ProductRepository.java
public interface ProductRepository extends JpaRepository<Product, Long> {

    // Requête dérivée qui devient paginable
    Page<Product> findByCategory(String category, Pageable pageable);

    // Requête JPQL personnalisée qui devient paginable
    @Query("SELECT p FROM Product p WHERE p.category = :category AND p.price BETWEEN :minPrice AND :maxPrice")
    Page<Product> findByCategoryAndPriceRange(
        @Param("category") String category,
        @Param("minPrice") BigDecimal minPrice,
        @Param("maxPrice") BigDecimal maxPrice,
        Pageable pageable
    );
}

Couche Service

Le service orchestre la création de l'objet Pageable.

// Dans ProductService.java
public Page<Product> getAllProducts(int page, int size, String sortBy, String sortOrder) {
    // 1. Créer l'objet Sort
    Sort sort = sortOrder.equalsIgnoreCase(Sort.Direction.ASC.name()) ?
                Sort.by(sortBy).ascending() : Sort.by(sortBy).descending();

    // 2. Créer l'objet Pageable avec PageRequest
    Pageable pageable = PageRequest.of(page, size, sort);

    // 3. Appeler le repository
    return productRepository.findAll(pageable);
}

Le code est clair : on transforme les chaînes de caractères sortBy et sortOrder en un objet Sort, puis on combine le tout avec la page et la taille pour créer le Pageable final.

Couche Controller

Le contrôleur expose ces options via les paramètres de l'URL. L'utilisation de defaultValue est une bonne pratique pour rendre l'API plus facile à utiliser.

// Dans ProductController.java
@GetMapping
public ResponseEntity<Page<Product>> getAllProducts(
    @RequestParam(defaultValue = "0") int page,
    @RequestParam(defaultValue = "10") int size,
    @RequestParam(defaultValue = "id") String sortBy,
    @RequestParam(defaultValue = "ASC") String sortOrder
) {
    Page<Product> products = productService.getAllProducts(page, size, sortBy, sortOrder);
    return ResponseEntity.ok(products);
}

Ainsi, un appel à /api/products?page=1&size=5&sortBy=price&sortOrder=DESC est géré de manière fluide et transparente.


Conclusion

Félicitations ! Vous maîtrisez maintenant l'une des techniques les plus importantes pour la conception d'API REST robustes. Vous êtes capable de gérer de grands volumes de données de manière efficace, en donnant au client le contrôle sur la portion de données qu'il souhaite recevoir et sur la manière dont elle doit être triée.

Points clés à retenir :

  • La pagination est essentielle pour la performance et l'évolutivité des API.
  • Spring Data utilise le trio Pageable (la demande), Sort (le tri), et Page (la réponse).
  • JpaRepository fournit findAll(Pageable pageable) prêt à l'emploi.
  • Vous pouvez rendre n'importe quelle requête (dérivée ou @Query) paginable en ajoutant un paramètre Pageable et en retournant un objet Page<T>.
  • Le flux typique est : Controller (@RequestParam) -> Service (PageRequest.of()) -> Repository.

Dans la prochaine leçon, nous allons explorer une autre facette de Spring Data en nous tournant vers le monde du NoSQL. Nous verrons comment intégrer Spring Data MongoDB pour gérer des données non structurées. Votre expérience avec MongoDB rendra cette transition particulièrement intéressante, car vous pourrez comparer l'approche de Spring Data avec les deux types de bases de données.