Aller au contenu principal

Enregistrer des données

Notions théoriques

Le repository : interface entre Java et la base de données

En Spring Boot, on ne manipule pas directement SQL pour sauvegarder des objets. On utilise un repository, une interface qui hérite de JpaRepository. Spring génère automatiquement l'implémentation.

Comparaison avec Doctrine
Doctrine (Symfony)JPA (Spring Boot)
$entityManager->persist($article)articleRepository.save(article)
$entityManager->flush()(inclus dans save())
$articleRepository->find($id)articleRepository.findById(id)
$articleRepository->findAll()articleRepository.findAll()

Créer un repository avec JpaRepository

package org.joliciel.monblog.repository;

import org.joliciel.monblog.entity.Article;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ArticleRepository extends JpaRepository<Article, Long> {
// Spring génère automatiquement toutes les méthodes CRUD de base
}

JpaRepository<Article, Long> prend deux paramètres de type :

  • Article : le type de l'entité gérée
  • Long : le type de la clé primaire (@Id)

Les méthodes disponibles sans rien écrire :

MéthodeDescription
save(article)Crée ou met à jour un article
findById(id)Cherche par id, retourne Optional<Article>
findAll()Retourne toutes les lignes sous forme de List<Article>
delete(article)Supprime un article
deleteById(id)Supprime par id
count()Nombre total de lignes
existsById(id)Vérifie si un id existe

Injecter le repository dans un contrôleur

La manière recommandée est l'injection par constructeur (meilleure testabilité que @Autowired sur le champ) :

@Controller
public class ArticleController {

private final ArticleRepository articleRepository;

// Spring injecte automatiquement le repository via ce constructeur
public ArticleController(ArticleRepository articleRepository) {
this.articleRepository = articleRepository;
}
}
info

Avec Spring Boot, si le contrôleur n'a qu'un seul constructeur, l'annotation @Autowired sur ce constructeur est optionnelle. Spring la détecte automatiquement.

Contrôleur POST : recevoir un formulaire et sauvegarder

@PostMapping("/articles")
public String creerArticle(@ModelAttribute Article article,
RedirectAttributes redirectAttributes) {
articleRepository.save(article);
redirectAttributes.addFlashAttribute("message", "Article créé avec succès !");
return "redirect:/articles";
}
  • @PostMapping("/articles") : gère les requêtes HTTP POST sur /articles
  • @ModelAttribute Article article : Spring remplit automatiquement l'objet Article avec les champs du formulaire HTML (les noms des champs name="titre" doivent correspondre aux attributs Java)
  • articleRepository.save(article) : exécute un INSERT SQL si l'id est null, un UPDATE sinon
  • RedirectAttributes : permet de passer un message flash qui sera affiché après la redirection
  • return "redirect:/articles" : renvoie le navigateur vers /articles (patron Post/Redirect/Get)
Toujours rediriger après un POST

Ne retournez jamais directement une vue après un POST (return "articles/liste"). Utilisez toujours return "redirect:/...". Sans cela, si l'utilisateur actualise la page, le formulaire est soumis une deuxième fois, ce qui crée un doublon en base.

Messages flash avec RedirectAttributes

// Dans le contrôleur
redirectAttributes.addFlashAttribute("message", "Article créé !");

// Dans la vue Thymeleaf (articles/liste.html)
<div th:if="${message}" class="alert alert-success">
<span th:text="${message}"></span>
</div>

Les attributs flash sont stockés temporairement en session et supprimés automatiquement après un seul affichage.

Exemple pratique

Voici un contrôleur complet qui affiche le formulaire de création et sauvegarde l'article :

package org.joliciel.monblog.controller;

import org.joliciel.monblog.entity.Article;
import org.joliciel.monblog.repository.ArticleRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
@RequestMapping("/articles")
public class ArticleController {

private final ArticleRepository articleRepository;

public ArticleController(ArticleRepository articleRepository) {
this.articleRepository = articleRepository;
}

// Affiche le formulaire vide
@GetMapping("/nouveau")
public String afficherFormulaireCreation(Model model) {
model.addAttribute("article", new Article());
return "articles/nouveau";
}

// Reçoit le formulaire et sauvegarde
@PostMapping("/nouveau")
public String sauvegarderArticle(@ModelAttribute Article article,
RedirectAttributes redirectAttributes) {
articleRepository.save(article);
redirectAttributes.addFlashAttribute("message", "Article \"" + article.getTitre() + "\" créé avec succès !");
return "redirect:/articles";
}

// Liste tous les articles
@GetMapping
public String listerArticles(Model model) {
model.addAttribute("articles", articleRepository.findAll());
return "articles/liste";
}
}

Vue Thymeleaf templates/articles/nouveau.html :

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Nouvel article</title></head>
<body>
<h1>Créer un article</h1>
<form th:action="@{/articles/nouveau}" th:object="${article}" method="post">
<div>
<label for="titre">Titre</label>
<input type="text" id="titre" th:field="*{titre}" />
</div>
<div>
<label for="contenu">Contenu</label>
<textarea id="contenu" th:field="*{contenu}"></textarea>
</div>
<button type="submit">Publier</button>
</form>
</body>
</html>

Test de mémorisation/compréhension


De quelle interface un repository Spring Data JPA doit-il hériter ?


Que fait `articleRepository.save(article)` si l'article a un id null ?


Quelle annotation lie les champs d'un formulaire HTML à un objet Java dans le contrôleur ?


Pourquoi faut-il toujours rediriger après un POST ?


Que retourne `JpaRepository.findById(id)` ?


Quelle méthode de `RedirectAttributes` permet de passer un message après redirection ?


TP pour réfléchir et résoudre des problèmes

Dans ce TP, vous allez créer le formulaire de création d'un article dans le projet MonBlog.

Étape 1 — Créer le repository ArticleRepository

Créez une interface ArticleRepository dans le package repository.


Bonne pratique - Une interface vide est suffisante

Vous n'avez pas besoin d'écrire de code dans l'interface ArticleRepository. Spring génère automatiquement l'implémentation au démarrage de l'application. Toutes les méthodes CRUD (save, findAll, findById, delete...) sont déjà disponibles.

Étape 2 — Injecter le repository dans le contrôleur

Modifiez ArticleController pour injecter ArticleRepository par constructeur.


Bonne pratique - Injection par constructeur plutôt que par champ

Préférez toujours l'injection par constructeur (public ArticleController(ArticleRepository repo)) à l'injection par champ (@Autowired private ArticleRepository repo). L'injection par constructeur rend les dépendances explicites, facilite les tests unitaires et permet de déclarer l'attribut final (immuable après construction).

Étape 3 — Créer la méthode POST pour sauvegarder


Bonne pratique - Patron Post/Redirect/Get

Après un POST réussi, redirigez toujours l'utilisateur avec redirect:/.... Ce patron (PRG - Post/Redirect/Get) empêche la double soumission du formulaire si l'utilisateur appuie sur F5 (actualiser). Sans redirection, F5 renverrait la même requête POST et créerait un doublon en base.

📌 Une solution