
Transmission de données à la vue (`Model`, `ModelAndView`)
Apprenez comment les contrôleurs Spring MVC transmettent des données aux vues en utilisant les objets Model et ModelAndView pour le rendu dynamique.
Le besoin de communiquer : Du contrôleur à la vue
Dans une application web MVC traditionnelle, le contrôleur exécute la logique métier et prépare les informations qui doivent être présentées à l'utilisateur. La vue (par exemple, une page HTML générée par Thymeleaf) est responsable de la mise en forme et de l'affichage de ces informations. Il est donc essentiel d'avoir un mécanisme pour que le contrôleur puisse transmettre ces données dynamiques à la vue.
Spring MVC offre principalement deux approches pour réaliser cette transmission de données : en utilisant l'interface org.springframework.ui.Model ou la classe org.springframework.web.servlet.ModelAndView. Ces deux mécanismes permettent d'ajouter des attributs (paires clé-valeur) qui seront ensuite accessibles depuis la technologie de vue choisie.
Utilisation de l'interface `Model`
L'approche la plus courante et souvent considérée comme la plus propre dans les applications Spring modernes consiste à utiliser l'interface Model. Vous pouvez simplement déclarer un paramètre de type Model dans la signature de votre méthode de handler (annotée avec @GetMapping, @PostMapping, etc.) dans un @Controller.
Spring MVC injectera automatiquement une instance de Model (ou une de ses implémentations comme ModelMap) dans ce paramètre avant d'appeler votre méthode. Vous pouvez ensuite utiliser la méthode addAttribute(String attributeName, Object attributeValue) pour ajouter les données que vous souhaitez rendre accessibles à la vue.
La méthode de handler retourne ensuite typiquement un String représentant le nom logique de la vue. Spring MVC s'assure que les attributs ajoutés au Model sont disponibles lorsque cette vue est rendue.
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Arrays;
import java.util.List;
@Controller
public class ProductController {
@GetMapping("/products")
public String listProducts(@RequestParam(required = false, defaultValue = "all") String category, Model model) {
// Simuler la récupération de données (ex: depuis un service)
List products = Arrays.asList("Laptop", "Mouse", "Keyboard");
String pageTitle = "Product Catalog - " + category;
// Ajouter les données au modèle
model.addAttribute("productList", products);
model.addAttribute("title", pageTitle);
model.addAttribute("selectedCategory", category);
// Retourner le nom logique de la vue (ex: /templates/productList.html)
return "productList";
}
}
Dans la vue (par exemple, un fichier Thymeleaf nommé productList.html), vous pourrez accéder à ces données en utilisant les noms d'attributs spécifiés (productList, title, selectedCategory).
Notez que vous pouvez également utiliser java.util.Map ou org.springframework.ui.ModelMap comme type de paramètre, ils fonctionnent de manière similaire à Model.
Utilisation de la classe `ModelAndView`
Une alternative à l'utilisation de Model comme paramètre est de faire en sorte que votre méthode de handler retourne un objet ModelAndView. Cette classe agit comme un conteneur qui détient à la fois les données du modèle et les informations sur la vue (son nom logique ou une instance de View).
Dans ce cas, vous créez une instance de ModelAndView à l'intérieur de votre méthode, vous y ajoutez les données du modèle en utilisant la méthode addObject(String attributeName, Object attributeValue), et vous définissez la vue en utilisant setViewName(String viewName). L'objet ModelAndView complet est ensuite retourné par la méthode.
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class OrderController {
@GetMapping("/orders/{orderId}")
public ModelAndView viewOrder(@PathVariable Long orderId) {
// Simuler la récupération de données
Order orderDetails = // ... récupérer les détails de la commande 'orderId'
Customer customerInfo = // ... récupérer les infos client associées
// Créer l'objet ModelAndView
ModelAndView mav = new ModelAndView();
// Ajouter les données au modèle
mav.addObject("order", orderDetails);
mav.addObject("customer", customerInfo);
// Définir le nom logique de la vue
mav.setViewName("orderDetails"); // ex: /templates/orderDetails.html
// Retourner l'objet ModelAndView
return mav;
}
}
ModelAndView offre également des constructeurs pratiques pour initialiser le nom de la vue et/ou les données du modèle directement :
// Constructeur avec nom de vue, nom d'attribut et valeur
ModelAndView mav1 = new ModelAndView("orderDetails", "order", orderDetails);
// Constructeur avec nom de vue et une Map pour le modèle
Map modelData = new HashMap<>();
modelData.put("order", orderDetails);
modelData.put("customer", customerInfo);
ModelAndView mav2 = new ModelAndView("orderDetails", modelData);
`Model` vs `ModelAndView` : Lequel choisir ?
Les deux approches, Model en paramètre + retour String et retour ModelAndView, permettent d'atteindre le même objectif : passer des données à la vue. Le choix dépend souvent des préférences personnelles et du contexte.
Model+String: Souvent préféré pour sa clarté. La signature de la méthode montre explicitement que le modèle est utilisé, et le retourStringindique clairement la vue cible. Cela sépare la préparation des données de la sélection de la vue. C'est généralement l'approche la plus courante dans les projets récents.ModelAndView: Regroupe modèle et vue en un seul objet. Peut être légèrement plus concis dans certains cas ou utile si le nom de la vue doit être déterminé dynamiquement à l'intérieur de la méthode. Cela peut sembler plus familier aux développeurs ayant utilisé des versions plus anciennes de Spring MVC.
Il est bon de savoir qu'en interne, Spring MVC convertit souvent l'approche Model + String en un ModelAndView avant de poursuivre le traitement. Les deux sont donc des citoyens de première classe dans le framework.
Quelle que soit l'approche choisie, le résultat final est le même : les données ajoutées (via addAttribute ou addObject) sont placées dans une structure de données (souvent une Map) qui est ensuite exposée à la technologie de vue pour le rendu final de la page HTML.