Université Alioune Diop de Bambey
Département Technologies de l'Information et de la
Communication
Master 1 - Systèmes d'Information
Cours Complet
Spring Boot
De Débutant à Expert
Spring
Rédigé par
Modou DIAGNE
Étudiant en Master 1 Systèmes d'Information
Email: [email protected]
Tél: +221 78 464 37 40
Année Universitaire 2025-2026
2
Cours Spring Boot - Modou DIAGNE - UAD
Table des matières
Introduction 11
I Fondamentaux de Spring Boot 13
1 Prérequis Java 15
1.1 Programmation Orientée Objet (POO) . . . . . . . . . . . . . . . . . . . . 15
1.1.1 Les 4 piliers de la POO . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.1.2 Exemple : Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . 15
1.1.3 Exemple : Interfaces et Polymorphisme . . . . . . . . . . . . . . . . 16
1.2 Java Collections Framework . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.2.1 Les principales collections . . . . . . . . . . . . . . . . . . . . . . . 17
1.3 Lambda et Stream API (Java 8+) . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.1 Expressions Lambda . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.2 Stream API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.4 Optional (Java 8+) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.5 Annotations Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.6 Questions d'entretien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2 Introduction à Spring et Spring Boot 23
2.1 Qu'est-ce que Spring ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.1.1 Problèmes résolus par Spring . . . . . . . . . . . . . . . . . . . . . 23
2.1.2 Inversion de Contrôle (IoC) . . . . . . . . . . . . . . . . . . . . . . 23
2.2 Qu'est-ce que Spring Boot ? . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.2.1 Spring vs Spring Boot . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.2.2 Avantages de Spring Boot . . . . . . . . . . . . . . . . . . . . . . . 24
2.3 Architecture d'une application Spring Boot . . . . . . . . . . . . . . . . . . 25
2.4 Création d'un projet Spring Boot . . . . . . . . . . . . . . . . . . . . . . . 25
2.4.1 Avec Spring Initializr . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4.2 Structure du projet . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4.3 Le chier pom.xml . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.4.4 Classe principale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.5 Premier endpoint REST . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.5.1 Tester l'application . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.6 Questions d'entretien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3
4 TABLE DES MATIÈRES
II Développement Web REST 31
3 API REST - Concepts et Principes 33
3.1 Qu'est-ce qu'une API REST ? . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.1.1 Les 6 contraintes REST . . . . . . . . . . . . . . . . . . . . . . . . 33
3.1.2 Méthodes HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.1.3 Codes de statut HTTP . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.1.4 Design des URLs RESTful . . . . . . . . . . . . . . . . . . . . . . . 34
3.2 Format JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4 Controllers et Services Spring 37
4.1 Annotations des Controllers . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.1 @RestController . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.2 Mapping des requêtes . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.3 ResponseEntity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.2 La couche Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.2.1 Responsabilités du Service . . . . . . . . . . . . . . . . . . . . . . . 39
4.3 DTOs (Data Transfer Objects) . . . . . . . . . . . . . . . . . . . . . . . . 41
4.4 Validation avec Bean Validation . . . . . . . . . . . . . . . . . . . . . . . . 42
4.5 Questions d'entretien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
III Persistance des Données avec JPA 45
5 JPA et Hibernate - Fondamentaux 47
5.1 Introduction à JPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.1.1 Qu'est-ce que JPA ? . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.1.2 Avantages de JPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.2 Conguration Spring Data JPA . . . . . . . . . . . . . . . . . . . . . . . . 47
5.2.1 Dépendances Maven . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.2.2 Conguration application.properties . . . . . . . . . . . . . . . . . . 48
5.3 Les Entités JPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.3.1 Création d'une entité . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.3.2 Annotations JPA principales . . . . . . . . . . . . . . . . . . . . . . 51
5.3.3 Stratégies de génération d'ID . . . . . . . . . . . . . . . . . . . . . 51
5.4 Spring Data JPA Repositories . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.4.1 JpaRepository . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.4.2 Query Methods - Mots-clés . . . . . . . . . . . . . . . . . . . . . . . 53
5.4.3 Requêtes JPQL personnalisées . . . . . . . . . . . . . . . . . . . . . 53
5.5 Pagination et Tri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6 Relations JPA 57
6.1 Types de relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6.2 Relation OneToMany / ManyToOne . . . . . . . . . . . . . . . . . . . . . 57
6.3 Relation ManyToMany . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
6.4 Fetch Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.5 Cascade Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.6 Questions d'entretien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Cours Spring Boot - Modou DIAGNE - UAD
TABLE DES MATIÈRES 5
IV Sécurité avec Spring Security 63
7 Spring Security - Fondamentaux 65
7.1 Introduction à Spring Security . . . . . . . . . . . . . . . . . . . . . . . . . 65
7.1.1 Dépendance Maven . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
7.2 Architecture de Spring Security . . . . . . . . . . . . . . . . . . . . . . . . 65
7.2.1 Composants principaux . . . . . . . . . . . . . . . . . . . . . . . . . 66
7.3 Conguration de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
7.4 UserDetailsService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.4.1 Entité User implémentant UserDetails . . . . . . . . . . . . . . . . 68
7.5 Autorisation par méthode . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
8 Authentication JWT 71
8.1 Introduction à JWT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
8.1.1 Structure d'un JWT . . . . . . . . . . . . . . . . . . . . . . . . . . 71
8.2 Implémentation JWT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.2.1 Dépendances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.2.2 Conguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.2.3 Service JWT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.2.4 Filtre JWT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
8.2.5 Conguration Security avec JWT . . . . . . . . . . . . . . . . . . . 76
8.3 Controller d'authentication . . . . . . . . . . . . . . . . . . . . . . . . . . 77
8.4 Questions d'entretien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
V Production et Bonnes Pratiques 81
9 Documentation API avec OpenAPI 83
9.1 Introduction à OpenAPI/Swagger . . . . . . . . . . . . . . . . . . . . . . . 83
9.1.1 Dépendance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
9.1.2 Conguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
9.1.3 Conguration Java . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
9.2 Annotations OpenAPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
9.2.1 Documentation des DTOs . . . . . . . . . . . . . . . . . . . . . . . 85
10 Bonnes Pratiques de Production 87
10.1 Structure de projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
10.2 Gestion des erreurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
10.3 Prols Spring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
10.4 Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
11 Spring Boot Actuator 93
11.1 Conguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
11.2 Endpoints Actuator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
11.3 Health Indicator personnalisé . . . . . . . . . . . . . . . . . . . . . . . . . 94
11.4 Questions d'entretien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Cours Spring Boot - Modou DIAGNE - UAD
6 TABLE DES MATIÈRES
A Cheatsheet Spring Boot 97
A.1 Annotations principales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
A.1.1 Conguration et Composants . . . . . . . . . . . . . . . . . . . . . 97
A.1.2 Mapping HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
A.1.3 JPA / Hibernate . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
A.1.4 Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
A.1.5 Spring Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
A.2 Commandes Maven . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
A.3 Conguration application.properties . . . . . . . . . . . . . . . . . . . . . . 99
A.4 Template de projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
A.4.1 Entité de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
A.4.2 Repository . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
A.4.3 Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
A.4.4 Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
B Glossaire 103
C Ressources supplémentaires 105
C.1 Documentation ocielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
C.2 Tutoriels recommandés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
C.3 Outils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Références 107
Cours Spring Boot - Modou DIAGNE - UAD
Table des gures
2.1 Inversion de Contrôle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.2 Architecture en couches d'une application Spring Boot . . . . . . . . . . . 25
5.1 Fonctionnement de JPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
7.1 Architecture Spring Security . . . . . . . . . . . . . . . . . . . . . . . . . . 65
8.1 Flux d'authentication JWT . . . . . . . . . . . . . . . . . . . . . . . . . . 72
7
8 TABLE DES FIGURES
Cours Spring Boot - Modou DIAGNE - UAD
Liste des tableaux
1.1 Les 4 piliers de la POO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.2 Collections Java les plus utilisées . . . . . . . . . . . . . . . . . . . . . . . 17
2.1 Comparaison Spring Framework vs Spring Boot . . . . . . . . . . . . . . . 24
3.1 Les 6 contraintes de l'architecture REST . . . . . . . . . . . . . . . . . . . 33
3.2 Méthodes HTTP et leurs usages . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3 Codes HTTP courants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.4 Bonnes pratiques pour les URLs REST . . . . . . . . . . . . . . . . . . . . 34
5.1 Options de hibernate.ddl-auto . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.2 Annotations JPA essentielles . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.3 Mots-clés pour les Query Methods . . . . . . . . . . . . . . . . . . . . . . . 53
6.1 Types de relations JPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6.2 Stratégies de chargement . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.3 Types de cascade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
7.1 Composants de Spring Security . . . . . . . . . . . . . . . . . . . . . . . . 66
10.1 Niveaux de log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
11.1 Endpoints Actuator principaux . . . . . . . . . . . . . . . . . . . . . . . . 93
9
10 LISTE DES TABLEAUX
Cours Spring Boot - Modou DIAGNE - UAD
Introduction
Ce cours a été conçu pour fournir une formation complète et progressive sur Spring
Boot, le framework Java le plus populaire pour le développement d'applications d'entre-
prise et de microservices.
À qui s'adresse ce cours ?
Ce cours est destiné à :
Les étudiants en informatique souhaitant maîtriser le développement backend
Les développeurs Java débutants ou intermédiaires
Les professionnels préparant des entretiens techniques
Toute personne souhaitant créer des API REST professionnelles
Prérequis
Connaissances de base en programmation Java (OOP, Collections)
Notions de base en SQL
Familiarité avec un IDE (IntelliJ IDEA ou VS Code recommandé)
Structure du cours
Le cours est organisé en 5 parties progressives :
1. Fondamentaux : Introduction à Spring et Spring Boot
2. Développement Web : Création d'API REST
3. Persistance des données : JPA et Hibernate
4. Sécurité : Spring Security et JWT
5. Production : Bonnes pratiques et monitoring
Conseil
Chaque chapitre contient des exercices pratiques et des questions d'entretien pour
consolider vos connaissances.
11
12 LISTE DES TABLEAUX
Cours Spring Boot - Modou DIAGNE - UAD
Première partie
Fondamentaux de Spring Boot
13
Chapitre 1
Prérequis Java
Avant de commencer avec Spring Boot, il est essentiel de maîtriser certains concepts
Java modernes qui sont largement utilisés dans le framework.
1.1 Programmation Orientée Objet (POO)
1.1.1 Les 4 piliers de la POO
Table 1.1 Les 4 piliers de la POO
Pilier Description Exemple
Encapsulation Cacher les détails internes Attributs private + getters/set-
ters
Héritage Réutiliser le code d'une classe pa- class Dog extends Animal
rente
Polymorphisme Un objet peut prendre plusieurs Interface avec plusieurs implé-
formes mentations
Abstraction Dénir un contrat sans implé- Classes abstraites et interfaces
mentation
1.1.2 Exemple : Encapsulation
1 public class User {
2 // Attributs prives ( encapsulation )
3 private Long id ;
4 private String email ;
5 private String password ;
6
7 // Constructeur
8 public User ( String email , String password ) {
9 this . email = email ;
10 this . password = password ;
11 }
12
13 // Getters
15
16 CHAPITRE 1. PRÉREQUIS JAVA
14 public Long getId () { return id ; }
15 public String getEmail () { return email ; }
16
17 // Setters avec validation
18 public void setEmail ( String email ) {
19 if ( email != null && email . contains (" @")) {
20 this . email = email ;
21 }
22 }
23 }
Listing 1.1 Exemple d'encapsulation en Java
1.1.3 Exemple : Interfaces et Polymorphisme
1 // Interface - contrat
2 public interface PaymentService {
3 void processPayment ( double amount );
4 boolean refund ( String transactionId );
5 }
6
7 // Implementation 1
8 public class StripePaymentService implements PaymentService {
9 @Override
10 public void processPayment ( double amount ) {
11 System . out . println (" Paiement Stripe : " + amount ) ;
12 }
13
14 @Override
15 public boolean refund ( String transactionId ) {
16 // Logique de remboursement Stripe
17 return true ;
18 }
19 }
20
21 // Implementation 2
22 public class PayPalPaymentService implements PaymentService {
23 @Override
24 public void processPayment ( double amount ) {
25 System . out . println (" Paiement PayPal : " + amount ) ;
26 }
27
28 @Override
29 public boolean refund ( String transactionId ) {
30 // Logique de remboursement PayPal
31 return true ;
32 }
33 }
Listing 1.2 Interfaces en Java
Cours Spring Boot - Modou DIAGNE - UAD
1.2. JAVA COLLECTIONS FRAMEWORK 17
Information
Spring Boot utilise massivement les interfaces pour permettre l'injection de dépen-
dances et le découplage des composants.
1.2 Java Collections Framework
1.2.1 Les principales collections
Table 1.2 Collections Java les plus utilisées
Interface Implémentation Caractéristiques
List ArrayList Liste ordonnée, accès par index, doublons permis
List LinkedList Liste chaînée, insertion/suppression rapide
Set HashSet Ensemble sans doublons, non ordonné
Set TreeSet Ensemble trié, sans doublons
Map HashMap Clé-valeur, accès O(1), non ordonné
Map TreeMap Clé-valeur, clés triées
1 import java . util .*;
2
3 public class CollectionsDemo {
4 public static void main ( String [] args ) {
5 // List - elements ordonnes avec doublons
6 List < String > fruits = new ArrayList < >() ;
7 fruits . add ( " Pomme ");
8 fruits . add ( " Banane ") ;
9 fruits . add ( " Pomme "); // Doublon autorise
10
11 // Set - elements uniques
12 Set < String > uniqueFruits = new HashSet < >( fruits );
13 // Resultat : [ Pomme , Banane ]
14
15 // Map - paires cle - valeur
16 Map < String , Integer > stock = new HashMap < >() ;
17 stock . put ( " Pomme " , 100) ;
18 stock . put ( " Banane " , 50) ;
19
20 // Iteration
21 for ( Map . Entry < String , Integer > entry : stock . entrySet () ) {
22 System . out . println ( entry . getKey () + " : " + entry .
getValue () );
23 }
24 }
25 }
Listing 1.3 Utilisation des collections
Cours Spring Boot - Modou DIAGNE - UAD
18 CHAPITRE 1. PRÉREQUIS JAVA
1.3 Lambda et Stream API (Java 8+)
1.3.1 Expressions Lambda
Les lambdas permettent d'écrire des fonctions anonymes de manière concise.
1 // Sans lambda ( classe anonyme )
2 Comparator < String > comparatorOld = new Comparator < String >() {
3 @Override
4 public int compare ( String s1 , String s2 ) {
5 return s1 . length () - s2 . length () ;
6 }
7 };
8
9 // Avec lambda
10 Comparator < String > comparatorNew = (s1 , s2 ) -> s1 . length () - s2 .
length () ;
11
12 // Interfaces fonctionnelles courantes
13 Consumer < String > printer = s -> System . out . println (s );
14 Predicate < Integer > isPositive = n -> n > 0;
15 Function < String , Integer > length = s -> s. length () ;
16 Supplier < Double > random = () -> Math . random () ;
Listing 1.4 Expressions Lambda
1.3.2 Stream API
1 List < User > users = Arrays . asList (
2 new User ( " alice@mail . com " , 25) ,
3 new User ( " bob@mail . com " , 30) ,
4 new User ( " charlie@mail . com " , 22)
5 );
6
7 // Filtrer et transformer
8 List < String > adultEmails = users . stream ()
9 . filter ( u -> u. getAge () >= 18) // Filtrer
10 . map ( User :: getEmail ) // Transformer
11 . sorted () // Trier
12 . collect ( Collectors . toList () ); // Collecter
13
14 // Trouver un element
15 Optional < User > found = users . stream ()
16 . filter ( u -> u. getEmail () . equals (" bob@mail . com " ))
17 . findFirst () ;
18
19 // Statistiques
20 double averageAge = users . stream ()
21 . mapToInt ( User :: getAge )
22 . average ()
23 . orElse (0.0) ;
Cours Spring Boot - Modou DIAGNE - UAD
1.4. OPTIONAL (JAVA 8+) 19
24
25 // Grouper par critere
26 Map < Boolean , List < User > > byAge = users . stream ()
27 . collect ( Collectors . groupingBy (u -> u. getAge () >= 25) );
Listing 1.5 Stream API - Opérations courantes
Conseil
Les Streams sont paresseux (lazy) : les opérations intermédiaires ne sont exécutées
que lorsqu'une opération terminale est appelée.
1.4 Optional (Java 8+)
Optional permet de gérer proprement les valeurs potentiellement nulles.
1 public class UserService {
2
3 public Optional < User > findByEmail ( String email ) {
4 User user = userRepository . findByEmail ( email ) ;
5 return Optional . ofNullable ( user );
6 }
7
8 public void processUser ( String email ) {
9 // Mauvaise pratique ( avant Optional )
10 User user = findByEmail ( email );
11 if ( user != null ) {
12 System . out . println ( user . getName () );
13 }
14
15 // Bonne pratique ( avec Optional )
16 findByEmail ( email )
17 . map ( User :: getName )
18 . ifPresent ( System . out :: println );
19
20 // Valeur par defaut
21 String name = findByEmail ( email )
22 . map ( User :: getName )
23 . orElse ( " Utilisateur inconnu ");
24
25 // Lever une exception si absent
26 User user = findByEmail ( email )
27 . orElseThrow (() -> new UserNotFoundException ( email ) );
28 }
29 }
Listing 1.6 Utilisation d'Optional
Cours Spring Boot - Modou DIAGNE - UAD
20 CHAPITRE 1. PRÉREQUIS JAVA
Attention
Ne jamais appeler .get() sur un Optional sans vérier sa présence avec
.isPresent() ou utiliser les méthodes .orElse(), .orElseThrow().
1.5 Annotations Java
Les annotations sont omniprésentes dans Spring Boot.
1 // Annotation standard
2 @Override // Indique qu 'on redefinit une methode
3 public String toString () {
4 return " User { email =" + email + "} ";
5 }
6
7 @Deprecated // Marque comme obsolete
8 public void oldMethod () { }
9
10 @SuppressWarnings (" unchecked ") // Supprime les avertissements
11 public void method () { }
12
13 // Annotations Spring ( apercu )
14 @RestController // Controleur REST
15 @Service // Service metier
16 @Repository // Acces aux donnees
17 @Component // Composant generique
18 @Autowired // Injection de dependance
19 @Configuration // Classe de configuration
Listing 1.7 Annotations Java courantes
1.6 Questions d'entretien
Question d'entretien
Q1 : Quelle est la diérence entre une classe abstraite et une interface ?
Réponse :
Classe abstraite : peut avoir des attributs, des méthodes concrètes et abs-
traites. Une classe ne peut hériter que d'une seule classe abstraite.
Interface : depuis Java 8, peut avoir des méthodes default et static. Une
classe peut implémenter plusieurs interfaces.
En Spring, on préfère les interfaces pour le découplage et l'injection de dépendances.
Question d'entretien
Q2 : Quelle est la diérence entre == et .equals() ?
Réponse :
Cours Spring Boot - Modou DIAGNE - UAD
1.6. QUESTIONS D'ENTRETIEN 21
== compare les références (adresses mémoire)
.equals() compare le contenu (doit être redéni)
1 String s1 = new String ( " hello ");
2 String s2 = new String ( " hello ");
3 s1 == s2 ; // false ( references differentes )
4 s1 . equals ( s2 ); // true ( contenu identique )
Question d'entretien
Q3 : Qu'est-ce qu'un Stream en Java ?
Réponse : Un Stream est une séquence d'éléments supportant des opérations de
traitement fonctionnel (lter, map, reduce). Les streams sont :
Paresseux : calcul diéré jusqu'à l'opération terminale
Non réutilisables : un stream ne peut être consommé qu'une fois
Potentiellement innis : Stream.iterate(), Stream.generate()
Cours Spring Boot - Modou DIAGNE - UAD
22 CHAPITRE 1. PRÉREQUIS JAVA
Cours Spring Boot - Modou DIAGNE - UAD
Chapitre 2
Introduction à Spring et Spring Boot
2.1 Qu'est-ce que Spring ?
Spring Framework est un framework Java open-source créé en 2003 par Rod John-
son. Il fournit une infrastructure complète pour le développement d'applications Java
d'entreprise.
2.1.1 Problèmes résolus par Spring
1. Couplage fort : Sans Spring, les classes créent directement leurs dépendances,
rendant le code dicile à tester et maintenir.
2. Code boilerplate : Beaucoup de code répétitif pour les tâches communes (tran-
sactions, sécurité, etc.).
3. Conguration complexe : Les applications Java EE nécessitaient des chiers
XML volumineux.
2.1.2 Inversion de Contrôle (IoC)
L'IoC est le principe fondamental de Spring : au lieu de créer vos dépendances, vous
les recevez.
1 // SANS Spring - Couplage fort
2 public class OrderService {
3 private PaymentService paymentService ;
4
5 public OrderService () {
6 // Creation directe = couplage fort
7 this . paymentService = new StripePaymentService () ;
8 }
9 }
10
11 // AVEC Spring - Injection de dependances
12 @Service
13 public class OrderService {
14 private final PaymentService paymentService ;
15
16 // Spring injecte automatiquement l ' implementation
23
24 CHAPITRE 2. INTRODUCTION À SPRING ET SPRING BOOT
17 @Autowired
18 public OrderService ( PaymentService paymentService ) {
19 this . paymentService = paymentService ;
20 }
21 }
Listing 2.1 Sans Spring vs Avec Spring
Sans IoC Avec IoC (Spring)
OrderService Spring Container
new injecte crée
StripePayment
OrderService PaymentService
(créé directement)
Figure 2.1 Inversion de Contrôle
2.2 Qu'est-ce que Spring Boot ?
Spring Boot est une extension de Spring Framework qui simplie la création d'ap-
plications Spring en éliminant la conguration complexe.
2.2.1 Spring vs Spring Boot
Table 2.1 Comparaison Spring Framework vs Spring Boot
Aspect Spring Framework Spring Boot
Conguration Manuelle (XML ou Java) Auto-conguration
Serveur Déploiement sur Tomcat externe Serveur embarqué
Dépendances Gestion manuelle des versions Starters pré-congurés
Démarrage Conguration longue Démarrage en minutes
Production Conguration manuelle Actuator intégré
2.2.2 Avantages de Spring Boot
1. Auto-conguration : Spring Boot congure automatiquement l'application en
fonction des dépendances présentes.
2. Starters : Des ensembles de dépendances pré-congurées.
3. Serveur embarqué : Tomcat, Jetty ou Undertow intégré.
4. Pas de XML : Conguration 100% Java ou YAML.
5. Production-ready : Métriques, health checks avec Actuator.
Cours Spring Boot - Modou DIAGNE - UAD
2.3. ARCHITECTURE D'UNE APPLICATION SPRING BOOT 25
2.3 Architecture d'une application Spring Boot
HTTP Request
Controller (Couche Présentation)
@RestController, @GetMapping, @PostMapping
Business Logic
Service (Couche Métier)
@Service, @Transactional
Repository (Couche Accès Données)
Data Access
@Repository, JpaRepository
Storage
Base de données
MySQL, PostgreSQL, H2
Figure 2.2 Architecture en couches d'une application Spring Boot
2.4 Création d'un projet Spring Boot
2.4.1 Avec Spring Initializr
1. Aller sur https://start.spring.io
2. Congurer :
Project : Maven
Language : Java
Spring Boot : 3.2.x
Group : com.example
Artifact : demo
Java : 17
3. Ajouter les dépendances :
Spring Web
Spring Data JPA
H2 Database
4. Cliquer sur "Generate"
2.4.2 Structure du projet
Listing 2.2 Structure d'un projet Spring Boot
mon - projet /
|- - src /
| |-- main /
Cours Spring Boot - Modou DIAGNE - UAD
26 CHAPITRE 2. INTRODUCTION À SPRING ET SPRING BOOT
| | | -- java /
| | | |- - com / example / demo /
| | | | -- DemoApplication . java
| | | | -- controller /
| | | | -- service /
| | | | -- repository /
| | | | -- entity /
| | | -- resources /
| | |-- application . properties
| | |-- static /
| | |-- templates /
| |-- test /
| |- - java /
|- - pom . xml
2.4.3 Le chier pom.xml
Listing 2.3 pom.xml minimal
<? xml version =" 1.0 " encoding = " UTF -8 "? >
< project xmlns =" http: // maven . apache . org / POM /4.0.0 "
xmlns:xsi =" http: // www . w3 . org /2001/ XMLSchema - instance "
xsi:schemaLocation =" http: // maven . apache . org / POM /4.0.0
https: // maven . apache . org / xsd / maven -4.0.0. xsd " >
< modelVersion > 4.0.0 </ modelVersion >
< parent >
< groupId > org . springframework . boot </ groupId >
< artifactId > spring - boot - starter - parent </ artifactId >
< version > 3.2.0 </ version >
</ parent >
< groupId > com . example </ groupId >
< artifactId > demo </ artifactId >
< version > 1.0.0 </ version >
< name > Demo Application </ name >
< properties >
< java . version >17 </ java . version >
</ properties >
< dependencies >
<! -- Spring Web -- >
< dependency >
< groupId > org . springframework . boot </ groupId >
< artifactId > spring - boot - starter - web </ artifactId >
</ dependency >
<! -- Spring Data JPA -- >
< dependency >
Cours Spring Boot - Modou DIAGNE - UAD
2.4. CRÉATION D'UN PROJET SPRING BOOT 27
< groupId > org . springframework . boot </ groupId >
< artifactId > spring - boot - starter - data - jpa </ artifactId >
</ dependency >
<! -- H2 Database -- >
< dependency >
< groupId > com . h2database </ groupId >
< artifactId > h2 </ artifactId >
< scope > runtime </ scope >
</ dependency >
<! -- Test -- >
< dependency >
< groupId > org . springframework . boot </ groupId >
< artifactId > spring - boot - starter - test </ artifactId >
< scope > test </ scope >
</ dependency >
</ dependencies >
< build >
< plugins >
< plugin >
< groupId > org . springframework . boot </ groupId >
< artifactId > spring - boot - maven - plugin </ artifactId >
</ plugin >
</ plugins >
</ build >
</ project >
2.4.4 Classe principale
1 package com . example . demo ;
2
3 import org . springframework . boot . SpringApplication ;
4 import org . springframework . boot . autoconfigure . SpringBootApplication
;
5
6 @SpringBootApplication
7 public class DemoApplication {
8
9 public static void main ( String [] args ) {
10 SpringApplication . run ( DemoApplication . class , args );
11 }
12 }
Listing 2.4 Classe principale Spring Boot
Cours Spring Boot - Modou DIAGNE - UAD
28 CHAPITRE 2. INTRODUCTION À SPRING ET SPRING BOOT
Information
@SpringBootApplication est une annotation composite qui combine :
@Configuration : Classe de conguration Spring
@EnableAutoConfiguration : Active l'auto-conguration
@ComponentScan : Scanne les composants dans le package courant
2.5 Premier endpoint REST
1 package com . example . demo . controller ;
2
3 import org . springframework . web . bind . annotation . GetMapping ;
4 import org . springframework . web . bind . annotation . RestController ;
5
6 @RestController
7 public class HelloController {
8
9 @GetMapping ( "/ hello ")
10 public String hello () {
11 return " Hello , Spring Boot !";
12 }
13
14 @GetMapping ( "/ hello /{ name }" )
15 public String helloName ( @PathVariable String name ) {
16 return " Hello , " + name + "! ";
17 }
18 }
Listing 2.5 Premier Controller REST
2.5.1 Tester l'application
Listing 2.6 Lancer et tester l'application
# Lancer l ' application
mvn spring - boot : run
# Tester avec curl
curl http :// localhost :8080/ hello
# Reponse : Hello , Spring Boot !
curl http :// localhost :8080/ hello / Modou
# Reponse : Hello , Modou !
Cours Spring Boot - Modou DIAGNE - UAD
2.6. QUESTIONS D'ENTRETIEN 29
2.6 Questions d'entretien
Question d'entretien
Q1 : Qu'est-ce que l'Inversion de Contrôle (IoC) ?
Réponse : L'IoC est un principe où le contrôle de la création et gestion des objets
est transféré au framework (conteneur Spring) au lieu du code applicatif. Avantages :
Découplage des composants
Facilité de test (injection de mocks)
Conguration centralisée
Question d'entretien
Q2 : Quelle est la diérence entre @Component, @Service, @Repository ?
Réponse : Ce sont tous des stéréotypes Spring qui marquent une classe comme
bean géré par Spring :
@Component : Composant générique
@Service : Logique métier (couche service)
@Repository : Accès aux données (gestion des exceptions de persistence)
@Controller : Contrôleur MVC
Fonctionnellement équivalents, mais la distinction sémantique améliore la lisibilité.
Question d'entretien
Q3 : Qu'est-ce que @SpringBootApplication ?
Réponse : C'est une méta-annotation qui combine :
@Configuration : Indique une classe de conguration
@EnableAutoConfiguration : Congure automatiquement les beans selon les
dépendances
@ComponentScan : Scanne le package courant et ses sous-packages
Cours Spring Boot - Modou DIAGNE - UAD
30 CHAPITRE 2. INTRODUCTION À SPRING ET SPRING BOOT
Cours Spring Boot - Modou DIAGNE - UAD
Deuxième partie
Développement Web REST
31
Chapitre 3
API REST - Concepts et Principes
3.1 Qu'est-ce qu'une API REST ?
REST (REpresentational State Transfer) est un style d'architecture pour concevoir
des services web. Une API REST permet à des applications de communiquer via le
protocole HTTP.
3.1.1 Les 6 contraintes REST
Table 3.1 Les 6 contraintes de l'architecture REST
Contrainte Description
Client-Serveur Séparation des responsabilités entre client et serveur
Sans état (Stateless) Chaque requête contient toutes les informations nécessaires
Cacheable Les réponses peuvent être mises en cache
Interface uniforme URLs cohérentes, méthodes HTTP standard
Système en couches Le client ne sait pas s'il communique directement avec le serveur
Code à la demande (Optionnel) Le serveur peut envoyer du code exécutable
3.1.2 Méthodes HTTP
Table 3.2 Méthodes HTTP et leurs usages
Méthode Action Description Idempotent
GET Read Récupérer une ressource Oui
POST Create Créer une nouvelle ressource Non
PUT Update Remplacer complètement une ressource Oui
PATCH Partial Update Modier partiellement une ressource Non
DELETE Delete Supprimer une ressource Oui
33
Information
Idempotent signie que plusieurs appels identiques produisent le même résultat.
GET, PUT et DELETE sont idempotents ; POST ne l'est pas (crée une nouvelle
34 ressource à chaque appel).CHAPITRE 3. API REST - CONCEPTS ET PRINCIPES
3.1.3 Codes de statut HTTP
Table 3.3 Codes HTTP courants
Code Nom Usage
2xx - Succès
200 OK Requête réussie (GET, PUT)
201 Created Ressource créée (POST)
204 No Content Succès sans contenu (DELETE)
4xx - Erreur client
400 Bad Request Requête invalide (validation)
401 Unauthorized Non authentié
403 Forbidden Non autorisé
404 Not Found Ressource non trouvée
409 Conict Conit (doublon)
5xx - Erreur serveur
500 Internal Server Error Erreur serveur
503 Service Unavailable Service indisponible
3.1.4 Design des URLs RESTful
Table 3.4 Bonnes pratiques pour les URLs REST
Méthode URL Description
GET /api/users Liste tous les utilisateurs
GET /api/users/{id} Récupère un utilisateur par ID
POST /api/users Crée un nouvel utilisateur
PUT /api/users/{id} Met à jour un utilisateur
DELETE /api/users/{id} Supprime un utilisateur
GET /api/users/{id}/orders Commandes d'un utilisateur
Conseil
Règles de nommage :
Utiliser des noms (pas de verbes) : /users et non /getUsers
Utiliser le pluriel : /users et non /user
Utiliser des minuscules et des tirets : /user-profiles
Versionner l'API : /api/v1/users
3.2 Format JSON
JSON (JavaScript Object Notation) est le format standard pour les API REST.
Cours Spring Boot - Modou DIAGNE - UAD
3.2. FORMAT JSON 35
1 {
2 " id ": 1,
3 " email ": " modou@uad . sn " ,
4 " firstName " : " Modou " ,
5 " lastName ": " DIAGNE " ,
6 " roles ": [" USER " , " ADMIN " ],
7 " createdAt " : " 2024 -01 -15 T10 :30:00 Z " ,
8 " address ": {
9 " city ": " Bambey " ,
10 " country ": " Senegal "
11 }
12 }
Listing 3.1 Exemple de réponse JSON
Cours Spring Boot - Modou DIAGNE - UAD
36 CHAPITRE 3. API REST - CONCEPTS ET PRINCIPES
Cours Spring Boot - Modou DIAGNE - UAD
Chapitre 4
Controllers et Services Spring
4.1 Annotations des Controllers
4.1.1 @RestController
1 // @RestController = @Controller + @ResponseBody
2 @RestController
3 @RequestMapping ("/ api / users " )
4 public class UserController {
5
6 @GetMapping // Equivalent a @GetMapping ("/")
7 public List < User > getAllUsers () {
8 return userService . findAll () ;
9 }
10 }
11
12 // Equivalent avec @Controller
13 @Controller
14 @RequestMapping ("/ api / users " )
15 public class UserController {
16
17 @GetMapping
18 @ResponseBody // Necessaire pour retourner du JSON
19 public List < User > getAllUsers () {
20 return userService . findAll () ;
21 }
22 }
Listing 4.1 @RestController vs @Controller
4.1.2 Mapping des requêtes
1 @RestController
2 @RequestMapping ("/ api / products " )
3 public class ProductController {
4
5 // GET / api / products
37
38 CHAPITRE 4. CONTROLLERS ET SERVICES SPRING
6 @GetMapping
7 public List < Product > getAll () { ... }
8
9 // GET / api / products /123
10 @GetMapping ( " /{ id } ")
11 public Product getById ( @PathVariable Long id ) { ... }
12
13 // GET / api / products / search ? name = phone & minPrice =100
14 @GetMapping ( "/ search " )
15 public List < Product > search (
16 @RequestParam String name ,
17 @RequestParam ( required = false , defaultValue = "0" )
Double minPrice ) {
18 ...
19 }
20
21 // POST / api / products
22 @PostMapping
23 public Product create ( @RequestBody ProductDTO dto ) { ... }
24
25 // PUT / api / products /123
26 @PutMapping ( " /{ id } ")
27 public Product update (
28 @PathVariable Long id ,
29 @RequestBody ProductDTO dto ) { ... }
30
31 // DELETE / api / products /123
32 @DeleteMapping (" /{ id }")
33 public void delete ( @PathVariable Long id ) { ... }
34 }
Listing 4.2 Annotations de mapping HTTP
4.1.3 ResponseEntity
ResponseEntity permet de contrôler la réponse HTTP complète (status, headers,
body).
1 @RestController
2 @RequestMapping ("/ api / users " )
3 public class UserController {
4
5 private final UserService userService ;
6
7 // Injection par constructeur
8 public UserController ( UserService userService ) {
9 this . userService = userService ;
10 }
11
12 // GET - 200 OK
13 @GetMapping
Cours Spring Boot - Modou DIAGNE - UAD
4.2. LA COUCHE SERVICE 39
14 public ResponseEntity < List < User >> getAll () {
15 return ResponseEntity . ok ( userService . findAll () );
16 }
17
18 // GET by ID - 200 ou 404
19 @GetMapping ( " /{ id } ")
20 public ResponseEntity < User > getById ( @PathVariable Long id ) {
21 return userService . findById ( id )
22 . map ( ResponseEntity :: ok )
23 . orElse ( ResponseEntity . notFound () . build () );
24 }
25
26 // POST - 201 Created avec Location header
27 @PostMapping
28 public ResponseEntity < User > create ( @Valid @RequestBody
CreateUserDTO dto ) {
29 User created = userService . create ( dto ) ;
30 URI location = URI . create ( "/ api / users / " + created . getId () ) ;
31 return ResponseEntity . created ( location ). body ( created );
32 }
33
34 // PUT - 200 OK
35 @PutMapping ( " /{ id } ")
36 public ResponseEntity < User > update (
37 @PathVariable Long id ,
38 @Valid @RequestBody UpdateUserDTO dto ) {
39 return ResponseEntity . ok ( userService . update (id , dto )) ;
40 }
41
42 // DELETE - 204 No Content
43 @DeleteMapping (" /{ id }")
44 public ResponseEntity < Void > delete ( @PathVariable Long id ) {
45 userService . delete ( id );
46 return ResponseEntity . noContent () . build () ;
47 }
48 }
Listing 4.3 Utilisation de ResponseEntity
4.2 La couche Service
4.2.1 Responsabilités du Service
Contenir la logique métier
Orchestrer les appels aux repositories
Gérer les transactions
Convertir les entités en DTOs
1 package com . example . service ;
Cours Spring Boot - Modou DIAGNE - UAD
40 CHAPITRE 4. CONTROLLERS ET SERVICES SPRING
2
3 import com . example . dto . CreateUserDTO ;
4 import com . example . dto . UpdateUserDTO ;
5 import com . example . entity . User ;
6 import com . example . exception . ResourceNotFoundException ;
7 import com . example . repository . UserRepository ;
8 import org . springframework . stereotype . Service ;
9 import org . springframework . transaction . annotation . Transactional ;
10
11 import java . util . List ;
12 import java . util . Optional ;
13
14 @Service
15 @Transactional
16 public class UserService {
17
18 private final UserRepository userRepository ;
19
20 public UserService ( UserRepository userRepository ) {
21 this . userRepository = userRepository ;
22 }
23
24 @Transactional ( readOnly = true )
25 public List < User > findAll () {
26 return userRepository . findAll () ;
27 }
28
29 @Transactional ( readOnly = true )
30 public Optional < User > findById ( Long id ) {
31 return userRepository . findById ( id ) ;
32 }
33
34 public User create ( CreateUserDTO dto ) {
35 // Verifier si l ' email existe deja
36 if ( userRepository . existsByEmail ( dto . getEmail () )) {
37 throw new IllegalArgumentException (" Email deja utilise "
);
38 }
39
40 User user = new User () ;
41 user . setEmail ( dto . getEmail () );
42 user . setFirstName ( dto . getFirstName () );
43 user . setLastName ( dto . getLastName () );
44
45 return userRepository . save ( user );
46 }
47
48 public User update ( Long id , UpdateUserDTO dto ) {
49 User user = userRepository . findById ( id )
50 . orElseThrow (() -> new ResourceNotFoundException (" User "
, id ));
Cours Spring Boot - Modou DIAGNE - UAD
4.3. DTOS (DATA TRANSFER OBJECTS) 41
51
52 user . setFirstName ( dto . getFirstName () );
53 user . setLastName ( dto . getLastName () );
54
55 return userRepository . save ( user );
56 }
57
58 public void delete ( Long id ) {
59 if (! userRepository . existsById ( id )) {
60 throw new ResourceNotFoundException ( " User " , id );
61 }
62 userRepository . deleteById ( id ) ;
63 }
64 }
Listing 4.4 Exemple de Service
4.3 DTOs (Data Transfer Objects)
Les DTOs sont des objets utilisés pour transférer des données entre les couches.
1 // DTO pour la creation
2 public class CreateUserDTO {
3
4 @NotBlank ( message = "L ' email est obligatoire ")
5 @Email ( message = " Format d ' email invalide " )
6 private String email ;
7
8 @NotBlank ( message = " Le prenom est obligatoire " )
9 @Size ( min = 2, max = 50)
10 private String firstName ;
11
12 @NotBlank ( message = " Le nom est obligatoire " )
13 @Size ( min = 2, max = 50)
14 private String lastName ;
15
16 @NotBlank ( message = " Le mot de passe est obligatoire ")
17 @Size ( min = 8, message = " Le mot de passe doit avoir au moins 8
caracteres ")
18 private String password ;
19
20 // Getters et Setters
21 }
22
23 // DTO pour la reponse
24 public class UserDTO {
25
26 private Long id ;
27 private String email ;
28 private String firstName ;
29 private String lastName ;
Cours Spring Boot - Modou DIAGNE - UAD
42 CHAPITRE 4. CONTROLLERS ET SERVICES SPRING
30 private LocalDateTime createdAt ;
31
32 // Constructeur depuis l ' entite
33 public static UserDTO fromEntity ( User user ) {
34 UserDTO dto = new UserDTO () ;
35 dto . id = user . getId () ;
36 dto . email = user . getEmail () ;
37 dto . firstName = user . getFirstName () ;
38 dto . lastName = user . getLastName () ;
39 dto . createdAt = user . getCreatedAt () ;
40 return dto ;
41 }
42
43 // Getters
44 }
Listing 4.5 Exemple de DTOs
Attention
Pourquoi utiliser des DTOs ?
Ne pas exposer les entités JPA directement (sécurité)
Contrôler les données envoyées/reçues
Éviter les problèmes de lazy loading
Permettre diérentes vues d'une même entité
4.4 Validation avec Bean Validation
1 public class ProductDTO {
2
3 @NotBlank ( message = " Le nom est obligatoire " )
4 @Size ( min = 2, max = 100 , message = " Le nom doit avoir entre 2
et 100 caracteres ")
5 private String name ;
6
7 @Size ( max = 500 , message = " Description trop longue " )
8 private String description ;
9
10 @NotNull ( message = " Le prix est obligatoire ")
11 @DecimalMin ( value = " 0.01 " , message = " Le prix doit etre
positif " )
12 @DecimalMax ( value = " 99999.99 " , message = " Prix trop eleve ")
13 private BigDecimal price ;
14
15 @Min ( value = 0, message = " Le stock ne peut pas etre negatif ")
16 private Integer stock ;
17
18 @Email ( message = " Email invalide ")
Cours Spring Boot - Modou DIAGNE - UAD
4.5. QUESTIONS D'ENTRETIEN 43
19 private String supplierEmail ;
20
21 @Pattern ( regexp = " ^[A - Z ]{2}[0 -9]{6} $" , message = " Reference
invalide " )
22 private String reference ;
23 }
24
25 // Dans le controller
26 @PostMapping
27 public ResponseEntity < Product > create ( @Valid @RequestBody
ProductDTO dto ) {
28 // Si validation echoue -> MethodArgumentNotValidException ->
400 Bad Request
29 return ResponseEntity . ok ( productService . create ( dto )) ;
30 }
Listing 4.6 Annotations de validation
4.5 Questions d'entretien
Question d'entretien
Q1 : Quelle est la diérence entre @Controller et @RestController ?
Réponse :
@Controller : Retourne des vues (HTML, Thymeleaf)
@RestController : Retourne directement des données (JSON/XML). C'est
l'équivalent de @Controller + @ResponseBody.
Question d'entretien
Q2 : Quelle est la diérence entre @PathVariable et @RequestParam ?
Réponse :
@PathVariable : Extrait une valeur de l'URL
Exemple : GET /users/123
@PathVariable Long id
@RequestParam : Extrait un paramètre de requête
Exemple : GET /users?page=1&size=10
@RequestParam int page
Question d'entretien
Q3 : Pourquoi utiliser des DTOs au lieu des entités ?
Réponse :
1. Sécurité : Ne pas exposer la structure interne de la base de données
2. Flexibilité : Diérentes représentations d'une même entité
3. Performance : Éviter le lazy loading et les relations non souhaitées
4. Validation : Valider les données en entrée avant traitement
Cours Spring Boot - Modou DIAGNE - UAD
44 CHAPITRE 4. CONTROLLERS ET SERVICES SPRING
Question d'entretien
Q4 : Qu'est-ce qu'une API REST idempotente ?
Réponse : Une opération idempotente produit le même résultat quel que soit le
nombre de fois qu'elle est exécutée :
GET /users/1 : Toujours le même résultat Idempotent
DELETE /users/1 : Supprime une fois, les appels suivants ne changent rien
Idempotent
POST /users : Crée un nouvel utilisateur à chaque appel NON idem-
potent
Cours Spring Boot - Modou DIAGNE - UAD
Troisième partie
Persistance des Données avec JPA
45
Chapitre 5
JPA et Hibernate - Fondamentaux
5.1 Introduction à JPA
5.1.1 Qu'est-ce que JPA ?
JPA (Java Persistence API) est une spécication Java pour la persistance des données.
Elle dénit un standard pour mapper des objets Java vers des tables de base de données
relationnelles (ORM - Object-Relational Mapping).
Hibernate est l'implémentation JPA la plus populaire, et c'est celle utilisée par défaut
dans Spring Boot.
Objets Java Mapping SQL Base de données
JPA/Hibernate
(Entity) (Tables)
Figure 5.1 Fonctionnement de JPA
5.1.2 Avantages de JPA
1. Abstraction : Pas besoin d'écrire de SQL (dans la plupart des cas)
2. Portabilité : Changer de base de données facilement
3. Productivité : Moins de code boilerplate
4. Cache : Gestion automatique du cache de premier niveau
5. Transactions : Gestion simpliée des transactions
5.2 Conguration Spring Data JPA
5.2.1 Dépendances Maven
Listing 5.1 Dépendances JPA dans pom.xml
<! -- Spring Data JPA -- >
< dependency >
< groupId > org . springframework . boot </ groupId >
< artifactId > spring - boot - starter - data - jpa </ artifactId >
47
48 CHAPITRE 5. JPA ET HIBERNATE - FONDAMENTAUX
</ dependency >
<! -- H2 Database ( developpement ) -- >
< dependency >
< groupId > com . h2database </ groupId >
< artifactId >h2 </ artifactId >
< scope > runtime </ scope >
</ dependency >
<! -- PostgreSQL ( production ) -- >
< dependency >
< groupId > org . postgresql </ groupId >
< artifactId > postgresql </ artifactId >
< scope > runtime </ scope >
</ dependency >
5.2.2 Conguration application.properties
Listing 5.2 Conguration JPA
# Configuration H2 ( developpement )
spring . datasource . url = jdbc : h2 : mem : testdb
spring . datasource . driverClassName = org . h2 . Driver
spring . datasource . username = sa
spring . datasource . password =
spring . h2 . console . enabled = true
spring . h2 . console . path =/ h2 - console
# Configuration JPA
spring . jpa . hibernate . ddl - auto = create - drop
spring . jpa . show - sql = true
spring . jpa . properties . hibernate . format_sql = true
# Configuration PostgreSQL ( production )
# spring . datasource . url = jdbc : postgresql :// localhost :5432/ mydb
# spring . datasource . username = postgres
# spring . datasource . password = password
# spring . jpa . hibernate . ddl - auto = validate
Table 5.1 Options de hibernate.ddl-auto
Valeur Description
none Aucune action
validate Valide le schéma, ne fait aucune modication
update Met à jour le schéma (ajoute colonnes/tables)
create Crée le schéma (supprime les données existantes)
create-drop Crée au démarrage, supprime à l'arrêt
Cours Spring Boot - Modou DIAGNE - UAD
5.3. LES ENTITÉS JPA 49
Attention
En production, utilisez toujours validate ou none et gérez les migrations avec
Flyway ou Liquibase.
5.3 Les Entités JPA
5.3.1 Création d'une entité
1 package com . example . entity ;
2
3 import jakarta . persistence .*;
4 import java . time . LocalDateTime ;
5
6 @Entity
7 @Table ( name = " users ")
8 public class User {
9
10 @Id
11 @GeneratedValue ( strategy = GenerationType . IDENTITY )
12 private Long id ;
13
14 @Column ( name = " email " , unique = true , nullable = false , length
= 100)
15 private String email ;
16
17 @Column ( nullable = false )
18 private String password ;
19
20 @Column ( name = " first_name " , length = 50)
21 private String firstName ;
22
23 @Column ( name = " last_name " , length = 50)
24 private String lastName ;
25
26 @Column ( name = " is_active ")
27 private boolean active = true ;
28
29 @Column ( name = " created_at " , updatable = false )
30 private LocalDateTime createdAt ;
31
32 @Column ( name = " updated_at ")
33 private LocalDateTime updatedAt ;
34
35 // Callbacks JPA
36 @PrePersist
37 protected void onCreate () {
38 createdAt = LocalDateTime . now () ;
39 updatedAt = LocalDateTime . now () ;
Cours Spring Boot - Modou DIAGNE - UAD
50 CHAPITRE 5. JPA ET HIBERNATE - FONDAMENTAUX
40 }
41
42 @PreUpdate
43 protected void onUpdate () {
44 updatedAt = LocalDateTime . now () ;
45 }
46
47 // Constructeurs
48 public User () {}
49
50 public User ( String email , String password ) {
51 this . email = email ;
52 this . password = password ;
53 }
54
55 // Getters et Setters
56 public Long getId () { return id ; }
57 public void setId ( Long id ) { this . id = id ; }
58
59 public String getEmail () { return email ; }
60 public void setEmail ( String email ) { this . email = email ; }
61
62 public String getPassword () { return password ; }
63 public void setPassword ( String password ) { this . password =
password ; }
64
65 public String getFirstName () { return firstName ; }
66 public void setFirstName ( String firstName ) { this . firstName =
firstName ; }
67
68 public String getLastName () { return lastName ; }
69 public void setLastName ( String lastName ) { this . lastName =
lastName ; }
70
71 public boolean isActive () { return active ; }
72 public void setActive ( boolean active ) { this . active = active ; }
73
74 public LocalDateTime getCreatedAt () { return createdAt ; }
75 public LocalDateTime getUpdatedAt () { return updatedAt ; }
76 }
Listing 5.3 Entité JPA complète
Cours Spring Boot - Modou DIAGNE - UAD
5.4. SPRING DATA JPA REPOSITORIES 51
5.3.2 Annotations JPA principales
Table 5.2 Annotations JPA essentielles
Annotation Description
@Entity Marque la classe comme entité JPA
@Table Personnalise le nom de la table
@Id Dénit la clé primaire
@GeneratedValue Stratégie de génération de l'ID
@Column Personnalise la colonne (nom, contraintes)
@Transient Champ non persisté en base
@Temporal Type temporel (DATE, TIME, TIMESTAMP)
@Enumerated Persistance des enums (ORDINAL ou STRING)
@Lob Large Object (texte long, binaire)
5.3.3 Stratégies de génération d'ID
1 // AUTO - Hibernate choisit la strategie
2 @GeneratedValue ( strategy = GenerationType . AUTO )
3 private Long id ;
4
5 // IDENTITY - Auto - increment de la base ( MySQL , PostgreSQL )
6 @GeneratedValue ( strategy = GenerationType . IDENTITY )
7 private Long id ;
8
9 // SEQUENCE - Sequence de la base ( Oracle , PostgreSQL )
10 @GeneratedValue ( strategy = GenerationType . SEQUENCE , generator = "
user_seq " )
11 @SequenceGenerator ( name = " user_seq " , sequenceName = " user_sequence
" , allocationSize = 1)
12 private Long id ;
13
14 // TABLE - Table de sequences ( portable mais moins performant )
15 @GeneratedValue ( strategy = GenerationType . TABLE )
16 private Long id ;
17
18 // UUID - Identifiant unique universel
19 @Id
20 @GeneratedValue ( strategy = GenerationType . UUID )
21 private UUID id ;
Listing 5.4 Stratégies GenerationType
5.4 Spring Data JPA Repositories
5.4.1 JpaRepository
Cours Spring Boot - Modou DIAGNE - UAD
52 CHAPITRE 5. JPA ET HIBERNATE - FONDAMENTAUX
1 package com . example . repository ;
2
3 import com . example . entity . User ;
4 import org . springframework . data . jpa . repository . JpaRepository ;
5 import org . springframework . stereotype . Repository ;
6
7 import java . util . List ;
8 import java . util . Optional ;
9
10 @Repository
11 public interface UserRepository extends JpaRepository < User , Long > {
12
13 // Methodes heritees de JpaRepository :
14 // - save ( entity )
15 // - findById ( id )
16 // - findAll ()
17 // - deleteById ( id )
18 // - count ()
19 // - existsById ( id )
20
21 // Methodes derivees du nom ( Query Methods )
22 Optional < User > findByEmail ( String email );
23
24 List < User > findByActiveTrue () ;
25
26 List < User > findByFirstNameContainingIgnoreCase ( String name );
27
28 List < User > findByFirstNameAndLastName ( String firstName , String
lastName ) ;
29
30 boolean existsByEmail ( String email );
31
32 long countByActiveTrue () ;
33
34 void deleteByEmail ( String email );
35 }
Listing 5.5 Repository Spring Data JPA
Cours Spring Boot - Modou DIAGNE - UAD
5.4. SPRING DATA JPA REPOSITORIES 53
5.4.2 Query Methods - Mots-clés
Table 5.3 Mots-clés pour les Query Methods
Mot-clé Exemple
And findByFirstNameAndLastName(String, String)
Or findByFirstNameOrLastName(String, String)
Between findByAgeBetween(int, int)
LessThan findByAgeLessThan(int)
GreaterThan findByAgeGreaterThan(int)
Like findByEmailLike(String)
Containing findByNameContaining(String)
StartingWith findByNameStartingWith(String)
OrderBy findByActiveOrderByCreatedAtDesc(boolean)
Not findByStatusNot(Status)
In findByStatusIn(Collection<Status>)
True/False findByActiveTrue()
IsNull findByDeletedAtIsNull()
5.4.3 Requêtes JPQL personnalisées
1 @Repository
2 public interface UserRepository extends JpaRepository < User , Long > {
3
4 // JPQL - Java Persistence Query Language
5 @Query (" SELECT u FROM User u WHERE u. email = : email AND u.
active = true ")
6 Optional < User > findActiveByEmail ( @Param ( " email ") String email );
7
8 // JPQL avec JOIN
9 @Query (" SELECT u FROM User u JOIN u. orders o WHERE o. total > :
minTotal " )
10 List < User > findUsersWithOrdersAbove ( @Param (" minTotal " )
BigDecimal minTotal );
11
12 // SQL natif
13 @Query ( value = " SELECT * FROM users WHERE LOWER ( email ) LIKE %:
pattern % " ,
14 nativeQuery = true )
15 List < User > searchByEmailNative ( @Param ( " pattern " ) String pattern
);
16
17 // Requete de modification
18 @Modifying
19 @Transactional
20 @Query (" UPDATE User u SET u. active = false WHERE u. lastLogin <
: date ")
21 int deactivateInactiveUsers ( @Param (" date ") LocalDateTime date );
22
Cours Spring Boot - Modou DIAGNE - UAD
54 CHAPITRE 5. JPA ET HIBERNATE - FONDAMENTAUX
23 // Requete de suppression
24 @Modifying
25 @Transactional
26 @Query (" DELETE FROM User u WHERE u. active = false " )
27 void deleteInactiveUsers () ;
28 }
Listing 5.6 Requêtes JPQL avec @Query
5.5 Pagination et Tri
1 @Repository
2 public interface ProductRepository extends JpaRepository < Product ,
Long > {
3
4 // Pagination
5 Page < Product > findByCategory ( String category , Pageable pageable
);
6
7 // Slice ( plus leger que Page )
8 Slice < Product > findByActiveTrue ( Pageable pageable );
9 }
10
11 // Utilisation dans le Service
12 @Service
13 public class ProductService {
14
15 public Page < Product > getProducts ( int page , int size , String
sortBy ) {
16 Pageable pageable = PageRequest . of ( page , size , Sort . by (
sortBy ). descending () ) ;
17 return productRepository . findAll ( pageable );
18 }
19
20 public Page < Product > getProductsByCategory ( String category , int
page , int size ) {
21 Pageable pageable = PageRequest . of ( page , size ) ;
22 return productRepository . findByCategory ( category , pageable )
;
23 }
24 }
25
26 // Dans le Controller
27 @GetMapping
28 public ResponseEntity < Page < Product >> getProducts (
29 @RequestParam ( defaultValue = "0" ) int page ,
30 @RequestParam ( defaultValue = " 10 ") int size ,
31 @RequestParam ( defaultValue = " id ") String sortBy ) {
32 return ResponseEntity . ok ( productService . getProducts ( page , size ,
sortBy )) ;
Cours Spring Boot - Modou DIAGNE - UAD
5.5. PAGINATION ET TRI 55
33 }
Listing 5.7 Pagination avec Spring Data
Cours Spring Boot - Modou DIAGNE - UAD
56 CHAPITRE 5. JPA ET HIBERNATE - FONDAMENTAUX
Cours Spring Boot - Modou DIAGNE - UAD
Chapitre 6
Relations JPA
6.1 Types de relations
Table 6.1 Types de relations JPA
Relation Description Exemple
@OneToOne 1 :1 User Prole
@OneToMany 1 :N User Orders
@ManyToOne N :1 Order User
@ManyToMany N :N Student Course
6.2 Relation OneToMany / ManyToOne
1 // Cote " One " - User possede plusieurs Orders
2 @Entity
3 @Table ( name = " users ")
4 public class User {
5
6 @Id
7 @GeneratedValue ( strategy = GenerationType . IDENTITY )
8 private Long id ;
9
10 private String email ;
11
12 @OneToMany ( mappedBy = " user " , cascade = CascadeType . ALL ,
orphanRemoval = true )
13 private List < Order > orders = new ArrayList < >() ;
14
15 // Methodes utilitaires pour maintenir la coherence
16 public void addOrder ( Order order ) {
17 orders . add ( order ) ;
18 order . setUser ( this ) ;
19 }
20
21 public void removeOrder ( Order order ) {
57
58 CHAPITRE 6. RELATIONS JPA
22 orders . remove ( order ) ;
23 order . setUser ( null ) ;
24 }
25 }
26
27 // Cote " Many " - Order appartient a un User
28 @Entity
29 @Table ( name = " orders " )
30 public class Order {
31
32 @Id
33 @GeneratedValue ( strategy = GenerationType . IDENTITY )
34 private Long id ;
35
36 private BigDecimal total ;
37
38 @ManyToOne ( fetch = FetchType . LAZY )
39 @JoinColumn ( name = " user_id " , nullable = false )
40 private User user ;
41 }
Listing 6.1 Relation OneToMany / ManyToOne
Information
mappedBy indique le côté inverse (non propriétaire) de la relation. La clé étrangère
est gérée par l'entité propriétaire (Order dans cet exemple).
6.3 Relation ManyToMany
1 @Entity
2 public class Student {
3
4 @Id
5 @GeneratedValue ( strategy = GenerationType . IDENTITY )
6 private Long id ;
7
8 private String name ;
9
10 @ManyToMany ( cascade = { CascadeType . PERSIST , CascadeType . MERGE })
11 @JoinTable (
12 name = " student_course " ,
13 joinColumns = @JoinColumn ( name = " student_id ") ,
14 inverseJoinColumns = @JoinColumn ( name = " course_id ")
15 )
16 private Set < Course > courses = new HashSet < >() ;
17
18 // Methodes utilitaires
19 public void enrollCourse ( Course course ) {
Cours Spring Boot - Modou DIAGNE - UAD
6.4. FETCH TYPES 59
20 courses . add ( course );
21 course . getStudents () . add ( this ) ;
22 }
23
24 public void dropCourse ( Course course ) {
25 courses . remove ( course );
26 course . getStudents () . remove ( this ) ;
27 }
28 }
29
30 @Entity
31 public class Course {
32
33 @Id
34 @GeneratedValue ( strategy = GenerationType . IDENTITY )
35 private Long id ;
36
37 private String title ;
38
39 @ManyToMany ( mappedBy = " courses " )
40 private Set < Student > students = new HashSet < >() ;
41 }
Listing 6.2 Relation ManyToMany
6.4 Fetch Types
Table 6.2 Stratégies de chargement
Type Description Par défaut
EAGER Charge immédiatement avec l'entité pa- @ManyToOne, @OneToOne
rente
LAZY Charge uniquement quand accédé @OneToMany, @ManyToMany
Attention
Problème N+1 : Avec LAZY loading, si vous accédez aux relations dans une
boucle, Hibernate exécute N requêtes supplémentaires. Solution : utiliser JOIN
FETCH dans les requêtes JPQL.
1 @Repository
2 public interface UserRepository extends JpaRepository < User , Long > {
3
4 // Sans JOIN FETCH - Probleme N +1
5 // SELECT * FROM users
6 // puis N x SELECT * FROM orders WHERE user_id = ?
7 List < User > findAll () ;
8
Cours Spring Boot - Modou DIAGNE - UAD
60 CHAPITRE 6. RELATIONS JPA
9 // Avec JOIN FETCH - Une seule requete
10 @Query (" SELECT u FROM User u LEFT JOIN FETCH u. orders " )
11 List < User > findAllWithOrders () ;
12
13 // Avec EntityGraph
14 @EntityGraph ( attributePaths = { " orders " , " orders . items " })
15 @Query (" SELECT u FROM User u WHERE u. id = : id ")
16 Optional < User > findByIdWithOrdersAndItems ( @Param ( " id " ) Long id )
;
17 }
Listing 6.3 Résoudre le problème N+1 avec JOIN FETCH
6.5 Cascade Types
Table 6.3 Types de cascade
Type Description
PERSIST Sauvegarde aussi les entités enfants
MERGE Met à jour aussi les entités enfants
REMOVE Supprime aussi les entités enfants
REFRESH Rafraîchit aussi les entités enfants
DETACH Détache aussi les entités enfants
ALL Toutes les opérations ci-dessus
6.6 Questions d'entretien
Question d'entretien
Q1 : Quelle est la diérence entre JPA et Hibernate ?
Réponse :
JPA est une spécication (interface/standard)
Hibernate est une implémentation de JPA
JPA dénit les annotations et interfaces ; Hibernate fournit l'implémentation
concrète. Spring Boot utilise Hibernate par défaut.
Question d'entretien
Q2 : Qu'est-ce que le problème N+1 et comment le résoudre ?
Réponse : Le problème N+1 survient quand Hibernate exécute 1 requête principale
+ N requêtes pour charger les relations.
Solutions :
1. JOIN FETCH dans les requêtes JPQL
2. @EntityGraph pour dénir les relations à charger
3. @BatchSize pour charger par lots
Cours Spring Boot - Modou DIAGNE - UAD
6.6. QUESTIONS D'ENTRETIEN 61
Question d'entretien
Q3 : Quelle est la diérence entre EAGER et LAZY loading ?
Réponse :
EAGER : La relation est chargée immédiatement avec l'entité parente (une
seule requête avec JOIN)
LAZY : La relation est chargée uniquement quand on y accède (requête
supplémentaire)
Recommandation : Utiliser LAZY par défaut et charger explicitement avec JOIN
FETCH quand nécessaire.
Question d'entretien
Q4 : À quoi sert l'annotation @Transactional ?
Réponse : @Transactional gère automatiquement les transactions :
Ouvre une transaction au début de la méthode
Commit si succès, Rollback si exception
Paramètres : readOnly, propagation, isolation, rollbackFor
Cours Spring Boot - Modou DIAGNE - UAD
62 CHAPITRE 6. RELATIONS JPA
Cours Spring Boot - Modou DIAGNE - UAD
Quatrième partie
Sécurité avec Spring Security
63
Chapitre 7
Spring Security - Fondamentaux
7.1 Introduction à Spring Security
Spring Security est le framework de sécurité de référence pour les applications
Spring. Il fournit :
Authentication : Vérier l'identité de l'utilisateur
Autorisation : Vérier les droits d'accès
Protection : CSRF, CORS, XSS, injection SQL
7.1.1 Dépendance Maven
Listing 7.1 Dépendance Spring Security
< dependency >
< groupId > org . springframework . boot </ groupId >
< artifactId > spring - boot - starter - security </ artifactId >
</ dependency >
Information
Dès que cette dépendance est ajoutée, toutes les URLs sont protégées par
défaut. Un mot de passe est généré automatiquement dans la console au démarrage.
7.2 Architecture de Spring Security
HTTP Request Security Authentication Authentication
Filter Chain Manager Provider
Password UserDetails
Encoder Service
Figure 7.1 Architecture Spring Security
65
66 CHAPITRE 7. SPRING SECURITY - FONDAMENTAUX
7.2.1 Composants principaux
Table 7.1 Composants de Spring Security
Composant Rôle
SecurityFilterChain Chaîne de ltres qui intercepte les requêtes
AuthenticationManager Gère le processus d'authentication
AuthenticationProvider Vérie les credentials (mot de passe)
UserDetailsService Charge les informations utilisateur depuis la source de don-
nées
PasswordEncoder Encode et vérie les mots de passe (BCrypt)
SecurityContext Stocke les informations de l'utilisateur authentié
7.3 Conguration de base
1 package com . example . config ;
2
3 import org . springframework . context . annotation . Bean ;
4 import org . springframework . context . annotation . Configuration ;
5 import org . springframework . security . config . annotation . method .
configuration . EnableMethodSecurity ;
6 import org . springframework . security . config . annotation . web . builders .
HttpSecurity ;
7 import org . springframework . security . config . annotation . web .
configuration . EnableWebSecurity ;
8 import org . springframework . security . config . http .
SessionCreationPolicy ;
9 import org . springframework . security . crypto . bcrypt .
BCryptPasswordEncoder ;
10 import org . springframework . security . crypto . password . PasswordEncoder
;
11 import org . springframework . security . web . SecurityFilterChain ;
12
13 @Configuration
14 @EnableWebSecurity
15 @EnableMethodSecurity // Active @PreAuthorize , @PostAuthorize
16 public class SecurityConfig {
17
18 @Bean
19 public SecurityFilterChain securityFilterChain ( HttpSecurity
http ) throws Exception {
20 return http
21 // Desactiver CSRF pour les API REST ( stateless )
22 . csrf ( csrf -> csrf . disable () )
23
24 // Configuration des autorisations
25 . authorizeHttpRequests ( auth -> auth
26 // Endpoints publics
27 . requestMatchers (" / api / auth /** "). permitAll ()
Cours Spring Boot - Modou DIAGNE - UAD
7.4. USERDETAILSSERVICE 67
28 . requestMatchers (" / api / public /** " ). permitAll ()
29 . requestMatchers (" / swagger - ui /** " , "/ v3 / api - docs /**
") . permitAll ()
30
31 // Endpoints selon les roles
32 . requestMatchers (" / api / admin /** ") . hasRole (" ADMIN " )
33 . requestMatchers (" / api / users /** ") . hasAnyRole (" USER "
, " ADMIN ")
34
35 // Tout le reste necessite une authentification
36 . anyRequest () . authenticated ()
37 )
38
39 // Mode stateless pour JWT
40 . sessionManagement ( session ->
41 session . sessionCreationPolicy ( SessionCreationPolicy
. STATELESS )
42 )
43
44 . build () ;
45 }
46
47 @Bean
48 public PasswordEncoder passwordEncoder () {
49 return new BCryptPasswordEncoder () ;
50 }
51 }
Listing 7.2 Conguration Spring Security
7.4 UserDetailsService
1 package com . example . service ;
2
3 import com . example . entity . User ;
4 import com . example . repository . UserRepository ;
5 import org . springframework . security . core . userdetails . UserDetails ;
6 import org . springframework . security . core . userdetails .
UserDetailsService ;
7 import org . springframework . security . core . userdetails .
UsernameNotFoundException ;
8 import org . springframework . stereotype . Service ;
9
10 @Service
11 public class CustomUserDetailsService implements UserDetailsService
{
12
13 private final UserRepository userRepository ;
14
Cours Spring Boot - Modou DIAGNE - UAD
68 CHAPITRE 7. SPRING SECURITY - FONDAMENTAUX
15 public CustomUserDetailsService ( UserRepository userRepository )
{
16 this . userRepository = userRepository ;
17 }
18
19 @Override
20 public UserDetails loadUserByUsername ( String email )
21 throws UsernameNotFoundException {
22 return userRepository . findByEmail ( email )
23 . orElseThrow (() -> new UsernameNotFoundException (
24 " Utilisateur non trouve : " + email
25 )) ;
26 }
27 }
Listing 7.3 Implémentation de UserDetailsService
7.4.1 Entité User implémentant UserDetails
1 @Entity
2 @Table ( name = " users ")
3 public class User implements UserDetails {
4
5 @Id
6 @GeneratedValue ( strategy = GenerationType . IDENTITY )
7 private Long id ;
8
9 @Column ( unique = true , nullable = false )
10 private String email ;
11
12 @Column ( nullable = false )
13 private String password ;
14
15 @Enumerated ( EnumType . STRING )
16 private Role role = Role . USER ;
17
18 public enum Role {
19 USER , ADMIN
20 }
21
22 // Implementation de UserDetails
23 @Override
24 public Collection <? extends GrantedAuthority > getAuthorities ()
{
25 return List . of ( new SimpleGrantedAuthority (" ROLE_ " + role .
name () )) ;
26 }
27
28 @Override
29 public String getUsername () {
30 return email ; // On utilise l ' email comme username
Cours Spring Boot - Modou DIAGNE - UAD
7.5. AUTORISATION PAR MÉTHODE 69
31 }
32
33 @Override
34 public String getPassword () {
35 return password ;
36 }
37
38 @Override
39 public boolean isAccountNonExpired () { return true ; }
40
41 @Override
42 public boolean isAccountNonLocked () { return true ; }
43
44 @Override
45 public boolean isCredentialsNonExpired () { return true ; }
46
47 @Override
48 public boolean isEnabled () { return true ; }
49
50 // Getters et Setters standards ...
51 }
Listing 7.4 User avec UserDetails
7.5 Autorisation par méthode
1 @RestController
2 @RequestMapping ("/ api / users " )
3 public class UserController {
4
5 // Accessible a tous les utilisateurs authentifies
6 @GetMapping ( "/ me ")
7 public ResponseEntity < UserDTO > getCurrentUser (
8 @AuthenticationPrincipal User user ) {
9 return ResponseEntity . ok ( UserDTO . fromEntity ( user ) );
10 }
11
12 // Accessible uniquement aux ADMIN
13 @PreAuthorize (" hasRole (' ADMIN ') ")
14 @GetMapping
15 public ResponseEntity < List < UserDTO >> getAllUsers () {
16 return ResponseEntity . ok ( userService . findAll () );
17 }
18
19 // Accessible au proprietaire ou aux ADMIN
20 @PreAuthorize (" hasRole (' ADMIN ') or # id == authentication .
principal . id ")
21 @GetMapping ( " /{ id } ")
22 public ResponseEntity < UserDTO > getUser ( @PathVariable Long id ) {
23 return ResponseEntity . ok ( userService . findById ( id ) );
Cours Spring Boot - Modou DIAGNE - UAD
70 CHAPITRE 7. SPRING SECURITY - FONDAMENTAUX
24 }
25
26 // Verification personnalisee
27 @PreAuthorize (" @securityService . canAccessResource (# id ,
authentication )")
28 @DeleteMapping (" /{ id }")
29 public ResponseEntity < Void > deleteUser ( @PathVariable Long id ) {
30 userService . delete ( id );
31 return ResponseEntity . noContent () . build () ;
32 }
33 }
Listing 7.5 Autorisation avec @PreAuthorize
Cours Spring Boot - Modou DIAGNE - UAD
Chapitre 8
Authentication JWT
8.1 Introduction à JWT
JWT (JSON Web Token) est un standard ouvert (RFC 7519) pour transmettre des
informations de manière sécurisée entre parties sous forme de token.
8.1.1 Structure d'un JWT
Un JWT est composé de 3 parties séparées par des points :
Listing 8.1 Structure d'un JWT
xxxxx . yyyyy . zzzzz
| | |
| | +- - Signature
| +- --- --- -- Payload ( donnees )
+- --- --- --- --- --- Header ( algorithme )
1 // HEADER
2 {
3 " alg " : " HS256 " ,
4 " typ " : " JWT "
5 }
6
7 // PAYLOAD
8 {
9 " sub " : " user@example . com " , // Subject ( identifiant )
10 " iat " : 1704063600 , // Issued At ( date creation )
11 " exp " : 1704150000 , // Expiration
12 " roles ": [" USER " , " ADMIN " ] // Claims personnalises
13 }
14
15 // SIGNATURE
16 HMACSHA256 (
17 base64UrlEncode ( header ) + "." + base64UrlEncode ( payload ) ,
18 secret_key
19 )
Listing 8.2 Contenu d'un JWT décodé
71
72 CHAPITRE 8. AUTHENTIFICATION JWT
1. Login 2. Serveur 3. Génère
email/password vérie JWT
4. Client 5. Requêtes avec
stocke JWT Authorization : Bearer
Figure 8.1 Flux d'authentication JWT
8.2 Implémentation JWT
8.2.1 Dépendances
Listing 8.3 Dépendances JWT (jjwt)
< dependency >
< groupId >io . jsonwebtoken </ groupId >
< artifactId >jjwt - api </ artifactId >
< version > 0.12.3 </ version >
</ dependency >
< dependency >
< groupId >io . jsonwebtoken </ groupId >
< artifactId >jjwt - impl </ artifactId >
< version > 0.12.3 </ version >
< scope > runtime </ scope >
</ dependency >
< dependency >
< groupId >io . jsonwebtoken </ groupId >
< artifactId >jjwt - jackson </ artifactId >
< version > 0.12.3 </ version >
< scope > runtime </ scope >
</ dependency >
8.2.2 Conguration
Listing 8.4 Conguration JWT
# application . properties
jwt . secret =
MonSecretTresLongDauMoins256BitsPoUrHS256Algorithm123456789
jwt . expiration =86400000
jwt . refresh - expiration =604800000
8.2.3 Service JWT
1 package com . example . security ;
2
Cours Spring Boot - Modou DIAGNE - UAD
8.2. IMPLÉMENTATION JWT 73
3 import io . jsonwebtoken .*;
4 import io . jsonwebtoken . security . Keys ;
5 import org . springframework . beans . factory . annotation . Value ;
6 import org . springframework . security . core . userdetails . UserDetails ;
7 import org . springframework . stereotype . Service ;
8
9 import javax . crypto . SecretKey ;
10 import java . util . Date ;
11 import java . util . HashMap ;
12 import java . util . Map ;
13 import java . util . function . Function ;
14
15 @Service
16 public class JwtService {
17
18 @Value (" ${ jwt . secret }")
19 private String secret ;
20
21 @Value (" ${ jwt . expiration }")
22 private long expiration ;
23
24 // Generer un token
25 public String generateToken ( UserDetails userDetails ) {
26 Map < String , Object > claims = new HashMap < >() ;
27 claims . put ( " roles " , userDetails . getAuthorities () ) ;
28 return createToken ( claims , userDetails . getUsername () ) ;
29 }
30
31 private String createToken ( Map < String , Object > claims , String
subject ) {
32 return Jwts . builder ()
33 . claims ( claims )
34 . subject ( subject )
35 . issuedAt ( new Date () )
36 . expiration ( new Date ( System . currentTimeMillis () +
expiration ))
37 . signWith ( getSigningKey () )
38 . compact () ;
39 }
40
41 // Extraire le username du token
42 public String extractUsername ( String token ) {
43 return extractClaim ( token , Claims :: getSubject );
44 }
45
46 // Extraire la date d ' expiration
47 public Date extractExpiration ( String token ) {
48 return extractClaim ( token , Claims :: getExpiration );
49 }
50
51 // Extraire un claim specifique
Cours Spring Boot - Modou DIAGNE - UAD
74 CHAPITRE 8. AUTHENTIFICATION JWT
52 public <T > T extractClaim ( String token , Function < Claims , T >
claimsResolver ) {
53 final Claims claims = extractAllClaims ( token );
54 return claimsResolver . apply ( claims );
55 }
56
57 private Claims extractAllClaims ( String token ) {
58 return Jwts . parser ()
59 . verifyWith ( getSigningKey () )
60 . build ()
61 . parseSignedClaims ( token )
62 . getPayload () ;
63 }
64
65 // Verifier si le token est valide
66 public boolean isTokenValid ( String token , UserDetails
userDetails ) {
67 final String username = extractUsername ( token );
68 return username . equals ( userDetails . getUsername () ) && !
isTokenExpired ( token );
69 }
70
71 private boolean isTokenExpired ( String token ) {
72 return extractExpiration ( token ). before ( new Date () ) ;
73 }
74
75 private SecretKey getSigningKey () {
76 return Keys . hmacShaKeyFor ( secret . getBytes () );
77 }
78 }
Listing 8.5 JwtService complet
8.2.4 Filtre JWT
1 package com . example . security ;
2
3 import jakarta . servlet . FilterChain ;
4 import jakarta . servlet . ServletException ;
5 import jakarta . servlet . http . HttpServletRequest ;
6 import jakarta . servlet . http . HttpServletResponse ;
7 import org . springframework . security . authentication .
UsernamePasswordAuthenticationToken ;
8 import org . springframework . security . core . context .
SecurityContextHolder ;
9 import org . springframework . security . core . userdetails . UserDetails ;
10 import org . springframework . security . core . userdetails .
UserDetailsService ;
11 import org . springframework . security . web . authentication .
WebAuthenticationDetailsSource ;
12 import org . springframework . stereotype . Component ;
Cours Spring Boot - Modou DIAGNE - UAD
8.2. IMPLÉMENTATION JWT 75
13 import org . springframework . web . filter . OncePerRequestFilter ;
14
15 import java . io . IOException ;
16
17 @Component
18 public class JwtAuthenticationFilter extends OncePerRequestFilter {
19
20 private final JwtService jwtService ;
21 private final UserDetailsService userDetailsService ;
22
23 public JwtAuthenticationFilter ( JwtService jwtService ,
24 UserDetailsService
userDetailsService ) {
25 this . jwtService = jwtService ;
26 this . userDetailsService = userDetailsService ;
27 }
28
29 @Override
30 protected void doFilterInternal ( HttpServletRequest request ,
31 HttpServletResponse response ,
32 FilterChain filterChain )
33 throws ServletException , IOException {
34
35 // Extraire le header Authorization
36 final String authHeader = request . getHeader ( " Authorization "
);
37
38 // Verifier le format " Bearer < token >"
39 if ( authHeader == null || ! authHeader . startsWith (" Bearer ")
) {
40 filterChain . doFilter ( request , response );
41 return ;
42 }
43
44 // Extraire le token
45 final String jwt = authHeader . substring (7) ;
46 final String username = jwtService . extractUsername ( jwt );
47
48 // Verifier si l ' utilisateur n ' est pas deja authentifie
49 if ( username != null &&
50 SecurityContextHolder . getContext () . getAuthentication ()
== null ) {
51
52 UserDetails userDetails = userDetailsService .
loadUserByUsername ( username ) ;
53
54 // Valider le token
55 if ( jwtService . isTokenValid ( jwt , userDetails ) ) {
56 UsernamePasswordAuthenticationToken authToken =
57 new UsernamePasswordAuthenticationToken (
58 userDetails ,
Cours Spring Boot - Modou DIAGNE - UAD
76 CHAPITRE 8. AUTHENTIFICATION JWT
59 null ,
60 userDetails . getAuthorities ()
61 );
62
63 authToken . setDetails (
64 new WebAuthenticationDetailsSource () .
buildDetails ( request )
65 );
66
67 // Mettre a jour le SecurityContext
68 SecurityContextHolder . getContext () .
setAuthentication ( authToken );
69 }
70 }
71
72 filterChain . doFilter ( request , response );
73 }
74 }
Listing 8.6 JwtAuthenticationFilter
8.2.5 Conguration Security avec JWT
1 @Configuration
2 @EnableWebSecurity
3 @EnableMethodSecurity
4 public class SecurityConfig {
5
6 private final JwtAuthenticationFilter jwtAuthFilter ;
7 private final AuthenticationProvider authenticationProvider ;
8
9 public SecurityConfig ( JwtAuthenticationFilter jwtAuthFilter ,
10 AuthenticationProvider
authenticationProvider ) {
11 this . jwtAuthFilter = jwtAuthFilter ;
12 this . authenticationProvider = authenticationProvider ;
13 }
14
15 @Bean
16 public SecurityFilterChain securityFilterChain ( HttpSecurity
http ) throws Exception {
17 return http
18 . csrf ( csrf -> csrf . disable () )
19 . authorizeHttpRequests ( auth -> auth
20 . requestMatchers (" / api / auth /** "). permitAll ()
21 . requestMatchers (" / swagger - ui /** " , "/ v3 / api - docs /**
") . permitAll ()
22 . requestMatchers (" / api / admin /** ") . hasRole (" ADMIN " )
23 . anyRequest () . authenticated ()
24 )
25 . sessionManagement ( session ->
Cours Spring Boot - Modou DIAGNE - UAD
8.3. CONTROLLER D'AUTHENTIFICATION 77
26 session . sessionCreationPolicy ( SessionCreationPolicy
. STATELESS )
27 )
28 . authenticationProvider ( authenticationProvider )
29 . addFilterBefore ( jwtAuthFilter ,
UsernamePasswordAuthenticationFilter . class )
30 . build () ;
31 }
32 }
Listing 8.7 SecurityCong avec JWT
8.3 Controller d'authentication
1 @RestController
2 @RequestMapping ("/ api / auth ")
3 @Tag ( name = " Authentication " , description = " Endpoints d '
authentification " )
4 public class AuthController {
5
6 private final AuthService authService ;
7
8 public AuthController ( AuthService authService ) {
9 this . authService = authService ;
10 }
11
12 @PostMapping (" / register ")
13 @Operation ( summary = " Inscription d 'un nouvel utilisateur ")
14 public ResponseEntity < AuthResponse > register (
15 @Valid @RequestBody RegisterRequest request ) {
16 return ResponseEntity . ok ( authService . register ( request )) ;
17 }
18
19 @PostMapping (" / login ")
20 @Operation ( summary = " Connexion utilisateur ")
21 public ResponseEntity < AuthResponse > login (
22 @Valid @RequestBody LoginRequest request ) {
23 return ResponseEntity . ok ( authService . login ( request )) ;
24 }
25
26 @PostMapping (" / refresh " )
27 @Operation ( summary = " Rafraichir le token ")
28 public ResponseEntity < AuthResponse > refresh (
29 @RequestBody RefreshTokenRequest request ) {
30 return ResponseEntity . ok ( authService . refreshToken ( request ) )
;
31 }
32 }
33
34 // DTOs
Cours Spring Boot - Modou DIAGNE - UAD
78 CHAPITRE 8. AUTHENTIFICATION JWT
35 public class LoginRequest {
36 @NotBlank @Email
37 private String email ;
38
39 @NotBlank
40 private String password ;
41 }
42
43 public class AuthResponse {
44 private String accessToken ;
45 private String refreshToken ;
46 private String tokenType = " Bearer " ;
47 private long expiresIn ;
48 }
Listing 8.8 AuthController
8.4 Questions d'entretien
Question d'entretien
Q1 : Quelle est la diérence entre Authentication et Autorisation ?
Réponse :
Authentication : Vérie qui est l'utilisateur (identité)
Autorisation : Vérie ce que l'utilisateur peut faire (permissions)
Spring Security gère les deux : d'abord authentication (JWT, login), puis autori-
sation (rôles, @PreAuthorize).
Question d'entretien
Q2 : Pourquoi utiliser JWT plutôt que les sessions ?
Réponse :
Stateless : Le serveur n'a pas besoin de stocker l'état de session
Scalabilité : Fonctionne avec plusieurs serveurs sans partage de session
Microservices : Un token peut être validé par plusieurs services
Mobile/SPA : Plus adapté aux clients non-browser
Question d'entretien
Q3 : Comment sécuriser un JWT ?
Réponse :
1. Secret fort : Au moins 256 bits pour HS256
2. Expiration courte : 15-60 minutes pour l'access token
3. Refresh token : Pour renouveler sans re-login
4. HTTPS : Toujours transmettre en HTTPS
Cours Spring Boot - Modou DIAGNE - UAD
8.4. QUESTIONS D'ENTRETIEN 79
5. Stockage client : HttpOnly cookie plutôt que localStorage
6. Blacklist : Pour invalider les tokens (logout)
Question d'entretien
Q4 : Comment fonctionne @PreAuthorize ?
Réponse : @PreAuthorize est une annotation qui vérie les autorisations avant
l'exécution de la méthode. Elle utilise SpEL (Spring Expression Language) :
1 @PreAuthorize (" hasRole (' ADMIN ') ") // Role ADMIN
2 @PreAuthorize (" hasAnyRole (' USER ', ' ADMIN ')") // USER ou
ADMIN
3 @PreAuthorize (" hasAuthority ( ' WRITE_PRIVILEGE ')" ) // Permission
specifique
4 @PreAuthorize ("# id == authentication . principal . id ") //
Verification custom
Nécessite @EnableMethodSecurity dans la conguration.
Cours Spring Boot - Modou DIAGNE - UAD
80 CHAPITRE 8. AUTHENTIFICATION JWT
Cours Spring Boot - Modou DIAGNE - UAD
Cinquième partie
Production et Bonnes Pratiques
81
Chapitre 9
Documentation API avec OpenAPI
9.1 Introduction à OpenAPI/Swagger
OpenAPI (anciennement Swagger) est un standard pour décrire les API REST.
SpringDoc est la bibliothèque qui génère automatiquement cette documentation pour
Spring Boot.
9.1.1 Dépendance
Listing 9.1 Dépendance SpringDoc OpenAPI
< dependency >
< groupId > org . springdoc </ groupId >
< artifactId > springdoc - openapi - starter - webmvc - ui </ artifactId >
< version > 2.3.0 </ version >
</ dependency >
9.1.2 Conguration
Listing 9.2 Conguration SpringDoc
# application . properties
springdoc . api - docs . path =/ v3 / api - docs
springdoc . swagger - ui . path =/ swagger - ui . html
springdoc . swagger - ui . operationsSorter = method
springdoc . swagger - ui . tagsSorter = alpha
9.1.3 Conguration Java
1 @Configuration
2 public class OpenAPIConfig {
3
4 @Bean
5 public OpenAPI customOpenAPI () {
6 return new OpenAPI ()
83
84 CHAPITRE 9. DOCUMENTATION API AVEC OPENAPI
7 . info ( new Info ()
8 . title (" API de Gestion de Taches " )
9 . version (" 1.0.0 ")
10 . description (" Documentation de l ' API Task Manager ")
11 . contact ( new Contact ()
12 . name (" Modou DIAGNE ")
13 . email (" modou@uad . sn " ))
14 . license ( new License ()
15 . name (" Apache 2.0 " )
16 . url ( " http :// www . apache . org / licenses / LICENSE
-2.0 " )))
17 . addSecurityItem ( new SecurityRequirement () . addList ("
bearerAuth ") )
18 . components ( new Components ()
19 . addSecuritySchemes (" bearerAuth " ,
20 new SecurityScheme ()
21 . name (" bearerAuth " )
22 . type ( SecurityScheme . Type . HTTP )
23 . scheme ( " bearer ")
24 . bearerFormat ( " JWT ")) );
25 }
26 }
Listing 9.3 Conguration OpenAPI
9.2 Annotations OpenAPI
1 @RestController
2 @RequestMapping ("/ api / products " )
3 @Tag ( name = " Products " , description = " Gestion des produits " )
4 public class ProductController {
5
6 @Operation (
7 summary = " Liste des produits " ,
8 description = " Retourne tous les produits avec pagination "
9 )
10 @ApiResponses ( value = {
11 @ApiResponse ( responseCode = " 200 " , description = " Liste des
produits " ,
12 content = @Content ( schema = @Schema ( implementation =
Page . class ) )) ,
13 @ApiResponse ( responseCode = " 401 " , description = " Non
authentifie " )
14 })
15 @GetMapping
16 public ResponseEntity < Page < ProductDTO >> getAll (
17 @Parameter ( description = " Numero de page ")
18 @RequestParam ( defaultValue = "0" ) int page ,
19 @Parameter ( description = " Taille de page ")
20 @RequestParam ( defaultValue = " 10 ") int size ) {
Cours Spring Boot - Modou DIAGNE - UAD
9.2. ANNOTATIONS OPENAPI 85
21 return ResponseEntity . ok ( productService . findAll ( page , size )
);
22 }
23
24 @Operation ( summary = " Creer un produit ")
25 @ApiResponse ( responseCode = " 201 " , description = " Produit cree "
)
26 @PostMapping
27 public ResponseEntity < ProductDTO > create (
28 @io . swagger . v3 . oas . annotations . parameters . RequestBody (
29 description = " Donnees du produit " ,
30 required = true ,
31 content = @Content ( schema = @Schema ( implementation
= CreateProductDTO . class ) )
32 )
33 @Valid @RequestBody CreateProductDTO dto ) {
34 return ResponseEntity . status (201) . body ( productService .
create ( dto ) );
35 }
36 }
Listing 9.4 Documentation d'un Controller
9.2.1 Documentation des DTOs
1 @Schema ( description = " Donnees pour creer un produit ")
2 public class CreateProductDTO {
3
4 @Schema (
5 description = " Nom du produit " ,
6 example = " iPhone 15 Pro " ,
7 minLength = 2,
8 maxLength = 100 ,
9 required = true
10 )
11 @NotBlank
12 @Size ( min = 2, max = 100)
13 private String name ;
14
15 @Schema (
16 description = " Prix en euros " ,
17 example = " 1199.99 " ,
18 minimum = " 0.01 "
19 )
20 @NotNull
21 @DecimalMin ( " 0.01 " )
22 private BigDecimal price ;
23
24 @Schema (
25 description = " Categorie du produit " ,
26 example = " ELECTRONICS " ,
Cours Spring Boot - Modou DIAGNE - UAD
86 CHAPITRE 9. DOCUMENTATION API AVEC OPENAPI
27 allowableValues = {" ELECTRONICS " , " CLOTHING " , " FOOD " }
28 )
29 private Category category ;
30 }
Listing 9.5 Documentation d'un DTO
Cours Spring Boot - Modou DIAGNE - UAD
Chapitre 10
Bonnes Pratiques de Production
10.1 Structure de projet
Listing 10.1 Structure recommandée
src / main / java / com / example / myapp /
|- - MyAppApplication . java
|
|- - config / # Configuration
| |-- SecurityConfig . java
| |-- OpenAPIConfig . java
|
|- - controller / # Couche Presentation
| |-- AuthController . java
| |-- UserController . java
|
|- - service / # Couche Metier
| |-- AuthService . java
| |-- UserService . java
|
|- - repository / # Couche Acces Donnees
| |-- UserRepository . java
|
|- - entity / # Entites JPA
| |-- User . java
|
|- - dto / # Data Transfer Objects
| |-- request /
| | | -- LoginRequest . java
| |-- response /
| |- - UserResponse . java
|
|- - exception / # Gestion des erreurs
| |-- GlobalExceptionHandler . java
| |-- ResourceNotFoundException . java
|
|- - security / # Securite
| |-- JwtService . java
87
88 CHAPITRE 10. BONNES PRATIQUES DE PRODUCTION
| |-- JwtAuthFilter . java
10.2 Gestion des erreurs
1 @RestControllerAdvice
2 public class GlobalExceptionHandler {
3
4 private static final Logger log = LoggerFactory . getLogger (
GlobalExceptionHandler . class );
5
6 @ExceptionHandler ( ResourceNotFoundException . class )
7 public ResponseEntity < ErrorResponse > handleNotFound (
8 ResourceNotFoundException ex ,
9 HttpServletRequest request ) {
10
11 log . warn (" Resource not found : {} " , ex . getMessage () ) ;
12
13 ErrorResponse error = new ErrorResponse (
14 HttpStatus . NOT_FOUND . value () ,
15 " Not Found " ,
16 ex . getMessage () ,
17 request . getRequestURI ()
18 );
19
20 return ResponseEntity . status ( HttpStatus . NOT_FOUND ). body (
error );
21 }
22
23 @ExceptionHandler ( MethodArgumentNotValidException . class )
24 public ResponseEntity < ErrorResponse > handleValidation (
25 MethodArgumentNotValidException ex ,
26 HttpServletRequest request ) {
27
28 Map < String , String > errors = new HashMap < >() ;
29 ex . getBindingResult () . getFieldErrors () . forEach ( error ->
30 errors . put ( error . getField () , error . getDefaultMessage () )
31 );
32
33 ErrorResponse errorResponse = new ErrorResponse (
34 HttpStatus . BAD_REQUEST . value () ,
35 " Validation Error " ,
36 " Donnees invalides " ,
37 request . getRequestURI ()
38 );
39 errorResponse . setValidationErrors ( errors );
40
41 return ResponseEntity . badRequest () . body ( errorResponse );
42 }
43
Cours Spring Boot - Modou DIAGNE - UAD
10.3. PROFILS SPRING 89
44 @ExceptionHandler ( Exception . class )
45 public ResponseEntity < ErrorResponse > handleAll (
46 Exception ex ,
47 HttpServletRequest request ) {
48
49 log . error (" Unexpected error " , ex );
50
51 ErrorResponse error = new ErrorResponse (
52 HttpStatus . INTERNAL_SERVER_ERROR . value () ,
53 " Internal Server Error " ,
54 " Une erreur inattendue s ' est produite " ,
55 request . getRequestURI ()
56 );
57
58 return ResponseEntity . status ( HttpStatus .
INTERNAL_SERVER_ERROR ). body ( error );
59 }
60 }
Listing 10.2 GlobalExceptionHandler
10.3 Prols Spring
Listing 10.3 application-dev.properties
# ========== DEV ==========
server . port =8080
# H2 Database
spring . datasource . url = jdbc : h2 : mem : devdb
spring . h2 . console . enabled = true
spring . jpa . show - sql = true
spring . jpa . hibernate . ddl - auto = create - drop
# Swagger active
springdoc . swagger - ui . enabled = true
# Logging verbose
logging . level . com . example = DEBUG
logging . level . org . hibernate . SQL = DEBUG
Listing 10.4 application-prod.properties
# ========== PROD ==========
server . port =${ PORT :8080}
# PostgreSQL
spring . datasource . url =${ DATABASE_URL }
spring . datasource . username = ${ DATABASE_USER }
spring . datasource . password = ${ DATABASE_PASSWORD }
Cours Spring Boot - Modou DIAGNE - UAD
90 CHAPITRE 10. BONNES PRATIQUES DE PRODUCTION
spring . jpa . show - sql = false
spring . jpa . hibernate . ddl - auto = validate
# Swagger desactive
springdoc . swagger - ui . enabled = false
springdoc . api - docs . enabled = false
# JWT secret ( variable d ' environnement )
jwt . secret = ${ JWT_SECRET }
# Logging production
logging . level . root = WARN
logging . level . com . example = INFO
10.4 Logging
1 import org . slf4j . Logger ;
2 import org . slf4j . LoggerFactory ;
3
4 @Service
5 public class UserService {
6
7 // Logger statique
8 private static final Logger log = LoggerFactory . getLogger (
UserService . class ) ;
9
10 public User findById ( Long id ) {
11 log . debug (" Recherche utilisateur avec ID : {} " , id );
12
13 return userRepository . findById ( id )
14 . orElseThrow (() -> {
15 log . warn (" Utilisateur non trouve : {} " , id ) ;
16 return new ResourceNotFoundException ( " User " , id );
17 }) ;
18 }
19
20 public User create ( CreateUserDTO dto ) {
21 log . info (" Creation utilisateur : {} " , dto . getEmail () );
22
23 try {
24 User user = new User () ;
25 // ...
26 User saved = userRepository . save ( user ) ;
27 log . info (" Utilisateur cree avec ID : {} " , saved . getId () )
;
28 return saved ;
29 } catch ( Exception e ) {
30 log . error (" Erreur creation utilisateur : {} " , dto .
getEmail () , e );
Cours Spring Boot - Modou DIAGNE - UAD
10.4. LOGGING 91
31 throw e ;
32 }
33 }
34 }
Listing 10.5 Bonnes pratiques de logging
Table 10.1 Niveaux de log
Niveau Usage
TRACE Très détaillé (debug avancé)
DEBUG Informations de développement
INFO Événements normaux importants
WARN Situations anormales mais gérées
ERROR Erreurs nécessitant une attention
Cours Spring Boot - Modou DIAGNE - UAD
92 CHAPITRE 10. BONNES PRATIQUES DE PRODUCTION
Cours Spring Boot - Modou DIAGNE - UAD
Chapitre 11
Spring Boot Actuator
11.1 Conguration
Listing 11.1 Dépendance Actuator
< dependency >
< groupId > org . springframework . boot </ groupId >
< artifactId > spring - boot - starter - actuator </ artifactId >
</ dependency >
Listing 11.2 Conguration Actuator
# Endpoints exposes
management . endpoints . web . exposure . include = health , info , metrics
# Details du health check
management . endpoint . health . show - details = when - authorized
# Info
management . info . env . enabled = true
info . app . name = Task Manager API
info . app . version =1.0.0
11.2 Endpoints Actuator
Table 11.1 Endpoints Actuator principaux
Endpoint Description
/actuator/health État de l'application
/actuator/info Informations sur l'application
/actuator/metrics Liste des métriques
/actuator/env Variables d'environnement
/actuator/loggers Conguration des logs
93
94 CHAPITRE 11. SPRING BOOT ACTUATOR
11.3 Health Indicator personnalisé
1 @Component
2 public class DatabaseHealthIndicator implements HealthIndicator {
3
4 private final DataSource dataSource ;
5
6 public DatabaseHealthIndicator ( DataSource dataSource ) {
7 this . dataSource = dataSource ;
8 }
9
10 @Override
11 public Health health () {
12 try ( Connection conn = dataSource . getConnection () ) {
13 if ( conn . isValid (5) ) {
14 return Health . up ()
15 . withDetail ( " database " , conn . getMetaData () .
getDatabaseProductName () )
16 . withDetail ( " status " , " Connected ")
17 . build () ;
18 }
19 } catch ( SQLException e ) {
20 return Health . down ()
21 . withDetail ( " error " , e . getMessage () )
22 . build () ;
23 }
24 return Health . down () . build () ;
25 }
26 }
Listing 11.3 Custom HealthIndicator
11.4 Questions d'entretien
Question d'entretien
Q1 : Comment gérer les diérents environnements (dev, prod) ?
Réponse : Avec les prols Spring :
application-dev.properties pour le développement
application-prod.properties pour la production
Activation via spring.profiles.active=prod
Variables d'environnement pour les secrets
Question d'entretien
Q2 : Pourquoi utiliser des DTOs ?
Réponse :
Cours Spring Boot - Modou DIAGNE - UAD
11.4. QUESTIONS D'ENTRETIEN 95
1. Sécurité : Ne pas exposer les entités JPA
2. Flexibilité : Diérentes vues des mêmes données
3. Validation : Annotations sur les DTOs en entrée
4. Performance : Éviter le lazy loading accidentel
5. Découplage : API indépendante du modèle de données
Question d'entretien
Q3 : Comment gérer les erreurs globalement dans Spring Boot ?
Réponse : Avec @RestControllerAdvice :
Centralise la gestion d'erreurs
@ExceptionHandler pour chaque type d'exception
Réponse d'erreur standardisée (timestamp, status, message)
Logging approprié des erreurs
Question d'entretien
Q4 : Qu'est-ce que Spring Boot Actuator ?
Réponse : Actuator fournit des endpoints pour le monitoring en production :
/health : État de l'application et dépendances
/metrics : Métriques (CPU, mémoire, requêtes HTTP)
/info : Informations sur l'application
Important de sécuriser ces endpoints en production.
Cours Spring Boot - Modou DIAGNE - UAD
96 CHAPITRE 11. SPRING BOOT ACTUATOR
Cours Spring Boot - Modou DIAGNE - UAD
Annexe A
Cheatsheet Spring Boot
Cette annexe regroupe les commandes, annotations et congurations les plus utilisées.
A.1 Annotations principales
A.1.1 Conguration et Composants
Annotation Description
@SpringBootApplication Point d'entrée de l'application
@Configuration Classe de conguration Spring
@Component Composant générique géré par Spring
@Service Service métier
@Repository Accès aux données
@Controller Contrôleur MVC
@RestController Contrôleur REST (= @Controller + @ResponseBody)
@Bean Dénit un bean dans une classe @Conguration
@Autowired Injection de dépendance
A.1.2 Mapping HTTP
Annotation Description
@RequestMapping Mapping général (classe ou méthode)
@GetMapping HTTP GET
@PostMapping HTTP POST
@PutMapping HTTP PUT
@DeleteMapping HTTP DELETE
@PatchMapping HTTP PATCH
@PathVariable Paramètre dans l'URL (/users/{id})
@RequestParam Paramètre de requête ( ?page=1)
@RequestBody Corps de la requête (JSON)
@ResponseStatus Code HTTP de la réponse
97
98 ANNEXE A. CHEATSHEET SPRING BOOT
A.1.3 JPA / Hibernate
Annotation Description
@Entity Classe entité JPA
@Table Nom de la table
@Id Clé primaire
@GeneratedValue Génération automatique de l'ID
@Column Conguration de colonne
@OneToMany Relation 1 :N
@ManyToOne Relation N :1
@ManyToMany Relation N :N
@JoinColumn Colonne de jointure
@Transactional Gestion des transactions
@Query Requête JPQL personnalisée
A.1.4 Validation
Annotation Description
@Valid Active la validation sur l'objet
@NotNull Ne peut pas être null
@NotBlank Non null et non vide (String)
@NotEmpty Non null et non vide (Collection)
@Size(min, max) Taille min/max
@Min / @Max Valeur numérique min/max
@Email Format email valide
@Pattern Expression régulière
A.1.5 Spring Security
Annotation Description
@EnableWebSecurity Active Spring Security
@EnableMethodSecurity Active @PreAuthorize
@PreAuthorize Vérication avant exécution
@PostAuthorize Vérication après exécution
@Secured Rôles requis (simple)
@AuthenticationPrincipal Injecte l'utilisateur courant
A.2 Commandes Maven
Listing A.1 Commandes Maven courantes
# Compiler le projet
mvn compile
Cours Spring Boot - Modou DIAGNE - UAD
A.3. CONFIGURATION APPLICATION.PROPERTIES 99
# Lancer les tests
mvn test
# Packager l ' application
mvn package
# Packager sans tests
mvn package - DskipTests
# Lancer l ' application
mvn spring - boot : run
# Lancer avec un profil
mvn spring - boot : run - Dspring - boot . run . profiles = prod
# Nettoyer et rebuilder
mvn clean install
A.3 Conguration application.properties
Listing A.2 Conguration complète
# ========== SERVER ==========
server . port =8080
server . servlet . context - path =/ api
# ========== DATABASE ==========
# H2 ( dev )
spring . datasource . url = jdbc : h2 : mem : testdb
spring . datasource . driverClassName = org . h2 . Driver
spring . datasource . username = sa
spring . datasource . password =
spring . h2 . console . enabled = true
# PostgreSQL ( prod )
# spring . datasource . url = jdbc : postgresql :// localhost :5432/ mydb
# spring . datasource . username = postgres
# spring . datasource . password = password
# ========== JPA ==========
spring . jpa . hibernate . ddl - auto = create - drop
spring . jpa . show - sql = true
spring . jpa . properties . hibernate . format_sql = true
# ========== SECURITY ==========
jwt . secret = your -256 - bit - secret - key - here
jwt . expiration =86400000
# ========== ACTUATOR ==========
management . endpoints . web . exposure . include = health , info , metrics
Cours Spring Boot - Modou DIAGNE - UAD
100 ANNEXE A. CHEATSHEET SPRING BOOT
management . endpoint . health . show - details = when - authorized
# ========== SWAGGER ==========
springdoc . swagger - ui . enabled = true
springdoc . swagger - ui . path =/ swagger - ui . html
# ========== LOGGING ==========
logging . level . root = INFO
logging . level . com . example = DEBUG
logging . level . org . hibernate . SQL = DEBUG
A.4 Template de projet
A.4.1 Entité de base
1 @Entity
2 @Table ( name = " items ")
3 public class Item {
4
5 @Id
6 @GeneratedValue ( strategy = GenerationType . IDENTITY )
7 private Long id ;
8
9 @Column ( nullable = false )
10 private String name ;
11
12 @Column ( name = " created_at " , updatable = false )
13 private LocalDateTime createdAt ;
14
15 @Column ( name = " updated_at ")
16 private LocalDateTime updatedAt ;
17
18 @PrePersist
19 protected void onCreate () {
20 createdAt = LocalDateTime . now () ;
21 updatedAt = LocalDateTime . now () ;
22 }
23
24 @PreUpdate
25 protected void onUpdate () {
26 updatedAt = LocalDateTime . now () ;
27 }
28
29 // Constructeurs , Getters , Setters
30 }
Listing A.3 Template d'entité
Cours Spring Boot - Modou DIAGNE - UAD
A.4. TEMPLATE DE PROJET 101
A.4.2 Repository
1 @Repository
2 public interface ItemRepository extends JpaRepository < Item , Long > {
3
4 Optional < Item > findByName ( String name ) ;
5
6 List < Item > findByNameContainingIgnoreCase ( String name ) ;
7
8 @Query (" SELECT i FROM Item i WHERE i. createdAt > : date ")
9 List < Item > findRecentItems ( @Param (" date ") LocalDateTime date ) ;
10 }
Listing A.4 Template de Repository
A.4.3 Service
1 @Service
2 @Transactional
3 public class ItemService {
4
5 private final ItemRepository itemRepository ;
6
7 public ItemService ( ItemRepository itemRepository ) {
8 this . itemRepository = itemRepository ;
9 }
10
11 @Transactional ( readOnly = true )
12 public List < ItemDTO > findAll () {
13 return itemRepository . findAll () . stream ()
14 . map ( ItemDTO :: fromEntity )
15 . collect ( Collectors . toList () );
16 }
17
18 @Transactional ( readOnly = true )
19 public ItemDTO findById ( Long id ) {
20 return itemRepository . findById ( id )
21 . map ( ItemDTO :: fromEntity )
22 . orElseThrow (() -> new ResourceNotFoundException (" Item "
, id ));
23 }
24
25 public ItemDTO create ( CreateItemDTO dto ) {
26 Item item = new Item () ;
27 item . setName ( dto . getName () ) ;
28 return ItemDTO . fromEntity ( itemRepository . save ( item )) ;
29 }
30
31 public void delete ( Long id ) {
32 if (! itemRepository . existsById ( id )) {
Cours Spring Boot - Modou DIAGNE - UAD
102 ANNEXE A. CHEATSHEET SPRING BOOT
33 throw new ResourceNotFoundException ( " Item " , id );
34 }
35 itemRepository . deleteById ( id ) ;
36 }
37 }
Listing A.5 Template de Service
A.4.4 Controller
1 @RestController
2 @RequestMapping ("/ api / items " )
3 @Tag ( name = " Items " , description = " Gestion des items " )
4 public class ItemController {
5
6 private final ItemService itemService ;
7
8 public ItemController ( ItemService itemService ) {
9 this . itemService = itemService ;
10 }
11
12 @GetMapping
13 @Operation ( summary = " Liste tous les items ")
14 public ResponseEntity < List < ItemDTO >> getAll () {
15 return ResponseEntity . ok ( itemService . findAll () );
16 }
17
18 @GetMapping ( " /{ id } ")
19 @Operation ( summary = " Recupere un item par ID ")
20 public ResponseEntity < ItemDTO > getById ( @PathVariable Long id ) {
21 return ResponseEntity . ok ( itemService . findById ( id ) );
22 }
23
24 @PostMapping
25 @Operation ( summary = " Cree un nouvel item ")
26 public ResponseEntity < ItemDTO > create ( @Valid @RequestBody
CreateItemDTO dto ) {
27 ItemDTO created = itemService . create ( dto ) ;
28 URI location = URI . create ( "/ api / items / " + created . getId () ) ;
29 return ResponseEntity . created ( location ). body ( created );
30 }
31
32 @DeleteMapping (" /{ id }")
33 @Operation ( summary = " Supprime un item ")
34 public ResponseEntity < Void > delete ( @PathVariable Long id ) {
35 itemService . delete ( id );
36 return ResponseEntity . noContent () . build () ;
37 }
38 }
Listing A.6 Template de Controller
Cours Spring Boot - Modou DIAGNE - UAD
Annexe B
Glossaire
API Application Programming Interface - Interface de programmation
REST REpresentational State Transfer - Style d'architecture pour les services web
JSON JavaScript Object Notation - Format d'échange de données
JPA Java Persistence API - Spécication pour l'ORM en Java
ORM Object-Relational Mapping - Mapping objet-relationnel
DTO Data Transfer Object - Objet de transfert de données
JWT JSON Web Token - Standard pour les tokens d'authentication
CRUD Create, Read, Update, Delete - Opérations de base sur les données
IoC Inversion of Control - Principe d'inversion de contrôle
DI Dependency Injection - Injection de dépendances
CSRF Cross-Site Request Forgery - Attaque de falsication de requête
CORS Cross-Origin Resource Sharing - Partage de ressources entre origines
Bean Objet géré par le conteneur Spring
Starter Ensemble de dépendances pré-congurées Spring Boot
103
104 ANNEXE B. GLOSSAIRE
Cours Spring Boot - Modou DIAGNE - UAD
Annexe C
Ressources supplémentaires
C.1 Documentation ocielle
Spring Boot : https://spring.io/projects/spring-boot
Spring Security : https://spring.io/projects/spring-security
Spring Data JPA : https://spring.io/projects/spring-data-jpa
Spring Guides : https://spring.io/guides
C.2 Tutoriels recommandés
Baeldung : https://www.baeldung.com/
Spring.io Tutorials : https://spring.io/guides
JetBrains Academy : https://www.jetbrains.com/academy/
C.3 Outils
Spring Initializr : https://start.spring.io
Postman : https://www.postman.com/
IntelliJ IDEA : https://www.jetbrains.com/idea/
VS Code + Spring Boot Extension Pack
105
106 ANNEXE C. RESSOURCES SUPPLÉMENTAIRES
Cours Spring Boot - Modou DIAGNE - UAD
Références
1. Documentation ocielle Spring Boot : https://spring.io/projects/spring-boot
2. Spring Guides : https://spring.io/guides
3. Baeldung Spring Tutorials : https://www.baeldung.com/
4. Documentation Spring Security : https://spring.io/projects/spring-security
5. Documentation Spring Data JPA : https://spring.io/projects/spring-data-jpa
107