Introduction à Spring MVC
Par Michael Courcy le dimanche 13 avril 2008, 01:14 - Java - Lien permanent
Dans la guerre furieuse des frameworks MVC il y en a un qui se démarque par sa simplicité, sa facilité de prise en main et sa parfaite intégration à Spring : Spring MVC.
Certes Spring MVC n'est pas un framework événementiel comme pourraient l'être jsf, wicket, tapestry ou struts 2. Mais il possède de nombreux points d'extensions et utilisé avec Spring Web Flow il devient un framework très puissant.
Je vous propose ici une introduction des plus simples qui va consister à afficher une page Hello Spring MVC avec le framework Spring MVC.
Puis nous enrichirons progressivement notre application exemple avec de nouveaux tutoriels pour aboutir à l'utilisation de Spring Web Flow avec la gestion d'une transaction longue Hibernate.
Le projet est un projet Maven, tout ce qu'il y a de plus simple que vous pouvez télécharger ici.
Sinon je vous propose (et vous conseille) de le construire pas à pas avec moi :
Etape 1 : création du projet
Créons un projet web avec maven :
mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.netapsys.springmvc -DartifactId=spring-mvc-webapp
Pour pouvoir utiliser les annotations notre projet doit être un projet en java 1.5. Ouvrez le pom.xml situé dans le répertoire que vous venez de créér spring-mvc-webapp et ajoutez ces informations entre les balises build. Vous devriez obtenir ceci :
<build> <finalName>spring-mvc-webapp</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <artifactId>maven-eclipse-plugin</artifactId> <version>2.4</version> <configuration> <downloadSources>true</downloadSources> <downloadJavadocs>true</downloadJavadocs> </configuration> </plugin> </plugins> </build>
Pour bien faire, j'indique aussi au plugin eclipse que je souhaite disposer des codes sources, ce qui est toujours un très bon choix quand on travail avec du code open-source.
Ensuite il faut en faire un projet eclipse : allez dans le répertoire que vous venez de créér et lancez la commande maven eclipse:eclipse
cd spring-mvc-webapp
mvn eclipse:eclipse
Puis importez le projet dans eclipse en vous étant assuré que la variable M2_REPO pointe bien vers votre répertoire ~/.m2/repository Si ce n'est pas le cas : windows > preference > Java > Build Path > Class path variables puis New pour créer une nouvelle variable.
Par exemple pour moi M2_REPO = C:/Documents and Settings/michael_courcy/.m2/repository
Etape 2 : Exécution de l'application avec le serveur web jetty
Une fois notre projet créé nous allons modifier le pom.xml pour pouvoir exécuter ce projet sous le serveur web jetty :
Vous devriez obtenir ceci :
<build> <finalName>spring-mvc-webapp</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.0.1</version> <configuration> <scanIntervalSeconds>10</scanIntervalSeconds> </configuration> </plugin> </plugins> </build>
Remarquez qu'ici je n'ai fait que configurer jetty. Maven téléchargera lui-même jetty si nécessaire.
Vérifions que notre configuration fonctionne bien et exécutons l'application.
mvn jetty:run
Si vous n'avez pas l'habitude d'utiliser maven pour vos applications web, Maven téléchargera nécessairement de nombreuses dépendances transitives. C'est peut être l'occasion de prendre un café ...
Enfin, si tout s'est bien passé, vous pouvez vous connecter à l'url : http://localhost:8080/spring-mvc-webapp/
Pour y découvrir l'éternel Hello World.
Etape 3 : Branchement de Spring MVC
Spring mvc fonctionne par certains aspects de façon similaire à Struts : une servlet frontale va prendre l'ensemble des requêtes et les dispatcher à ses contrôleurs, ces contrôleurs sont des singletons issus d'une fabrique Spring.
Donc ce que je vais trouver dans web.xml :
- Une servlet pour dispatcher les requêtes aux contrôleurs.
- Un mapping de servlet
On aboutit à ce fichier web.xml :
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!-- déclare la servlet frontale (très similaire à struts) --> <servlet> <servlet-name>spring-mvc-webapp</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <!-- Toutes les requêtes se terminant par .html seront servis par la servlet frontal --> <servlet-mapping> <servlet-name>spring-mvc-webapp</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> </web-app>
Avant de recopier ce fichier, coupez jetty (Ctrl + C dans le terminal).
Ajoutez la dépendances à Spring et à spring-webmvc dans le pom.xml :
<dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.5.3</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>2.5.3</version> </dependency>
puis régénérez votre projet eclipse :
mvn eclipse:clean eclipse:eclipse
enfin rafraîchissez votre projet eclipse quand l'opération est finie pour voir apparaitre vos librairies et éventuellement consulter le code source.
On remarque immédiatement à la lecture de web.xml qu'on ne voit pas comment on informe la servlet frontale des contrôleurs auxquels elle va devoir redispatcher les requêtes.
Par convention, si la servlet s'appelle spring-mvc-webapp, alors elle ira chercher sa fabrique de contrôleurs dans WEB-INF/spring-mvc-webapp-servlet.xml. C'est une convention qui peut être surdéfinie mais que nous allons suivre ici.
Voici donc le fichier spring-mvc-webapp-servlet.xml. Les commentaires détaillent chaque élément : je vous invite à les lire.
<?xml version="1.0" encoding="UTF-8"?> <!-- - Contexte d'application pour spring-mvc-webapp. --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- - Tous les contrôleurs sont automatiquement détectés grâce à l'annotation @Controller. - On définit ici dans quel package le post processor doit chercher ces beans éventuellement annotés. --> <context:component-scan base-package="com.netapsys.springmvc.web"/> <!-- - Les controlleurs de cette application fournissent une annotation @RequestMapping - Qui peuvent être déclaré de deux manière différentes : - Au niveau de la classe par exemple : - @RequestMapping("/addVisit.html") - Pour ce type de controlleurs on peut annoter les méthodes pour qu'elles - prennent en charge une requête Post ou une requête Get - @RequestMapping(method = RequestMethod.GET) - Ou alors au niveau de chaque méthode, différents exemples seront fournis. --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> <!-- Ceci est le view resolver, il permet de définir la technologie de vue utilisée et comment sélectionner une vue. Ici on prendra la solution la plus simple, elle permet de mapper le nom de la vue retournée avec la sélection d'une jsp. Exemple si le nom de la vue retournée est "foo/bar/hello" alors on utilisera le fichier WEB-INF/jsp/foo/bar/hello.jsp pour constuire la vue. --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/> </beans>
Tout est en place maintenant pour écrire notre premier contrôleur et notre première jsp.
Etape 4 : Notre premier contrôleur
Créez le source folder /src/main/java/ et créez la classe HelloSpringMVC dans le package com.netapsys.springmvc.web
package com.netapsys.springmvc.web; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; /** * Contrôleur que l'on invoquera pour l'url /helloSpringMVC.html. * * @author Michael Courcy * */ @Controller @RequestMapping("/helloSpringMVC.html") public class HelloSpringMVC { /** * Handler de la méthode Get pour l'URL /helloSpringMVC.html. * * @param name le nom que l'on doit afficher dans la vue. * @param model une map de toutes les données qui seront utilisables dans la vue * @return le nom de la vue qu'il faudra utiliser. */ @RequestMapping(method = RequestMethod.GET) public String sayHelloWithSpringMVC( @RequestParam(value="name",required=false) String name, ModelMap model) { model.addAttribute("name",name); // on utilisera donc le fichier /WEB-INF/jsp/hello.jsp //au regard de la stratégie de résolution des vues //utilisée dans cette application. return "hello"; } }
Plusieurs remarques sont à faire à la lecture de ce contrôleur :
- Le contrôleur n'hérite d'aucune classe particulière, il est identifié comme contrôleur grâce à l'annotation @Controller
- C'est encore une annotation qui permet de savoir quelle méthode invoquer pour une requê
te de type Get : @RequestMapping(method = RequestMethod.GET)
- Notre méthode prend un paramètre supplémentaire ModelMap qui est en fait un HashMap amélioré dans lequel on place toutes les informations que l'on souhaite disponibles lors de la génération de la vue avec la jsp.
- Le code n'utilise pas directement l'objet HttpServletRequest mais il indique encore grâce aux annotations comment renseigner les paramètres à partir du contenu de l'objet HttpServletRequest @RequestParam(value="name",required=false)
Ce dernier point est très important : ne pas utiliser directement l'objet HttpServletRequest nous permet de créer des tests unitaires très simplement sans avoir à créer de request mock.
Créez le source folder /src/test/java et créez aussi le package com.netapsys.springmvc.web pour y placer le test suivant
package com.netapsys.springmvc.web; import org.springframework.ui.ModelMap; import junit.framework.TestCase; public class HelloSpringMCVTest extends TestCase { public void testSayHelloWithSpringMVC(){ HelloSpringMVC helloSpringMVC = new HelloSpringMVC(); ModelMap model = new ModelMap(); String view = helloSpringMVC.sayHelloWithSpringMVC("mic", model); //vérifions que c'est bien la vue hello qui est générée assertEquals("hello", view); //vérifions que le modele contient bien un attribut name assertTrue(model.containsAttribute("name")); //vérifions que cet attribut name est bien "mic" assertEquals("mic",model.get("name")); } }
Vous pouvez lancer ce test avec maven :
mvn -Dtest=HelloSpringMCVTest test
pour un test particulier ou alors
mvn test
pour refaire tous les tests.
Etape 5 : Notre propre jsp
Créez le fichier WEB-INF/jsp/hello.jsp :
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ page isELIgnored ="false" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Spring mvc hello !!</title> </head> <body> Hello spring mvc vous donne votre nom qui est : ${name} </body> </html>
Il ne vous reste plus qu'Ã tester
mvn jetty:run
Puis à essayer l'url suivante : http://localhost:8080/spring-mvc-webapp/helloSpringMVC.html?name=mic









Il y a 9 commentaires
Super Michael !
C'est exactement ce dont j'avais besoin !
Merci beaucoup pour cet excellent article et pour les éléments envoyés.
Bonjour,
Comment je fais pour recuperer la ressource demandee dans le controler. Par exempel avec l URl suivant:
http://localhost:8080/mywebapp/home...
J aimerais recuperer le nom de la ressouce qui dans ce cas est: home.html
Merci d avance.
Hello Sani
Lorsque http://localhost:8080/mywebapp/home... est invoqué, deux composants entrent en jeu : le controlleur et la vue.
Dans le contexte qui est le notre ici il faut que ton controller soit annoté pour répondre à cette url :
@RequestMapping("/home.html")
Puis au regard de la stratégie de résolution de vue il faut que la méthode invoquée retourne la chaine de caractere "home", alors la vue selectionnée sera /WEB-INF/jsp/home.jsp
Merci pour ce superbe tutoriel. Quelle simplicité, vraiment, de démarrer un projet avec maven...
Un tout petit détail, le 3ème commentaire du servlet.xml n'est pas correctement fermé : "->" au lieu de "-->".
Je serais très intéressé par une suite, avec par exemple l'ajout de Spring Web Flow, justement!
Merci encore!
Merci pour ce commentaire encourageant ! :-)
La coquille est corrigée.
Bravo
C'est bien écrit, très clair, cela donne envie de coder :)
Félicitation.
Bravo je vous invite à continuer en integrant la sécurité avec ACEGI, Hibernat pour la perssistance, invocation de service web ;-)
Félicitation.
Bonjour,
J'ai vraiment apprécié ce tuto: c'est simple, clair et facile à suivre!
Mais j'ai rencontré un problème à l'étape 3: après l'exécution de la commande "mvn eclipse:clean eclipse:eclipse", je n'ai pas trouvé de fichier nommé "spring-mvc-webapp.xml":(
Que quelqu'un m'aide...et merci d'avance!
Merci beaucoup pour ce tuto, il m'a permis de bien commencer mon apprentissage de Spring MVC avec ses merveilleuses annotations.
Aurais-tu une idée comment rajouter des contrôles sur les valeurs reçues ?
Merci.