Spring MVC avec URL REST

Ce post est un retour d'expérience sur le framework Spring MVC. En effet, cette année j'ai eu par 2 fois l'occasion de mettre en place ce framework web: la première fois dans le cadre d'une refonte technique d'un site internet grand publique qui s'appuyait sur des Servlets, la second pour une application "from scratch".

Après une courte présentation du framework, je m'attacherai à sa mise en place dans un projet Spring MVC en annotation avec des URL Rest: configuration Maven, web.xml, fichier de configuration Spring...

Spring MVC est une implémentation innovante du patron MVC, offerte par Spring.

Spring MVC profite des avantages de l’injection de dépendances et offre, depuis la version 2.5, une intéressante flexibilité grâce aux annotations Java 5. Ce module permet dès lors de s’abstraire de l’API Servlet de Java EE, les informations souhaitées étant automatiquement mises à disposition en tant que paramètres des méthodes des contrôleurs.

Schema Spring MVC

Spring MVC s'appuie sur :

  • une servlet principale appelée Dispatcher Servlet qui va gérer l'intégralité des requêtes HTTP reçues
  • un handler mapping qui va faire le lien entre l'URI appelée et le contrôleur MVC
  • le Controller qui va gérer le rôle du contrôleur MVC et qui va solliciter le modèle
  • View Resolver qui va préparer la vue en fonction du code retour du Controller
  • la View qui assure le rôle de vue au sens MVC

Il existe plusieurs type de HandlerMapping et de View Resolver.
L'implémentation proposée ci-dessous s'appuie sur les annotations Spring

Dépendance Maven

         <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-webmvc</artifactId>
              <version>3.0.5.RELEASE</version>
         </dependency>

Web.xml

         <?xml version="1.0" encoding="UTF-8"?>
         <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns="http://java.sun.com/xml/ns/javaee"
                  xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
                  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
                  id="testMVC"
                  version="2.5">   
               <display-name>Test MVC</display-name>
               <description>Test Spring MVC</description>
               <context-param>
                     <param-name>contextConfigLocation</param-name>
                     <param-value>
                           classpath:dispatcher-servlet.xml
                     </param-value>
               </context-param>
               <listener>
                     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
               </listener>
               <servlet>
                     <servlet-name>dispatcher</servlet-name>
                 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                 <load-on-startup>1</load-on-startup>
               </servlet>
               <servlet-mapping>
                 <servlet-name>dispatcher</servlet-name>
                 <url-pattern>/premier-pas/*</url-pattern>
               </servlet-mapping>
         </web-app>

La configuration de Spring MVC est donc dans le fichier dispatcher-servlet.xml

Dispatcher-servlet.xml

C'est dans ce fichier que seront définies les spécificités de l'implémentation Spring MVC.
Voici un exemple simple:

         <?xml version="1.0" encoding="UTF-8"?>
         <beans xmlns="http://www.springframework.org/schema/beans"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns:context="http://www.springframework.org/schema/context"
                  xmlns:mvc="http://www.springframework.org/schema/mvc"
                  xmlns:p="http://www.springframework.org/schema/p"
                  xsi:schemaLocation="
                      http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
                        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
               <!-- Indique le package et ses sous-packages à scanner pour
                      détecter des classes annotées afin que Spring les instancie-->
               <context:component-scan base-package="fr.netapsys.test" />
               <!-- Se substitue au Handler resolver.
                      Indique que les annotations dans les contrôleurs configureront
                      les appels de méthodes -->
               <mvc:annotation-driven />
               <mvc:interceptors>      
                     <bean id="localeChangeInterceptor"
                       class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lg"/>
               </mvc:interceptors>
               <!-- Définition du 
                             ViewResolver -->
               <bean
                     class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                     <property name="prefix" value="/WEB-INF/pages/" />
                     <property name="suffix" value=".jsp" />
               </bean>
         </beans>

On voit que le type de Handler mapping n'est pas à définir et qu'aucun fichier de configuration n'est nécessaire.

Pour l'exemple, un ViewResolver de type InternalResourceViewResolver permet de résoudre la vue en fonction du retour de mon contrôleur. Ce dernier renverra une String qui, concaténée avec le préfixe et le suffixe indiqués, nous permettra de savoir quelle sera la vue à afficher.
Ex: retour de mon contrôleur "welcome" => la vue sera "/WEB-INF/pages/welcome.jsp"

Contrôleurs

Dans le fichier précédent, la balise <context:component-scan base-package="fr.netapsys.test" /> indique que le projet scan le package "fr.netapsys.test" et ses sous packages sont scannés par Spring. Le simple fait d'ajouter une annotation Spring (ou stéréotype) permettra la prise en compte de la classe par Spring.
Ainsi pour nos contrôleurs, l'utilisation de l'annotation @Controller est évidente.

         package fr.netapsys.test;
         import org.springframework.stereotype.Controller;
         @Controller
         public class TestController {
                   ...
         }

Cette classe comportera des méthodes qui configureront leurs URI d'appel. L'avantage de ce genre d'implémentation est la flexibilité des paramètres d'entrée. On peut avoir aucun comme tous les paramètres passées à la DispatchServlet (Model, HttpServletRequest, HttpServletResponse, les objets passés par méthodes GET et ceux par méthode POST)

   @RequestMapping(value = "/welcome/{name}", method = RequestMethod.GET)
   public String welcome(@PathVariable("name") String name, Model model) {
       model.addAttribute("name", name);
       return "welcome";
   }

L'annotation @RequestMapping indique l'URI par laquelle la méthode doit être appelée ainsi que sa méthode d'appel (GET ou POST). On remarque que l'URI comporte une valeur {name}: cette valeur est en fait une variable. Toutes les URI de type /welcome/* permettront d'appeler le traitement de la méthode welcome.
Cette variable est récupérée dans la méthode via l'annotation @PathVariable. L'utilisation de @PathVariable(*), où * est le nom de la variable définie dans le RequestMapping est inutile si le nom de la variable de l'URI et de la méthode sont identiques.
Le Model lui permet de mettre et récupérer des éléments du contexte de la requête. Si un objet est ajouté dans le modèle, il est récupérable via une JSTL ou directement dans la requête HTTP.
Enfin, la méthode doit renvoyer le nom de la JSP qui permettra de récupérer le fichier correspondant tel que défini par le View Resolver.

Conclusion

Spring MVC est un framework Web très puissant, rapide à mettre en œuvre et surtout à prendre en main. Il s'intègre d'autant mieux dans des projets où Spring est déjà présent. Un autre de ces avantages est le fait que même la couche présentation d'une application est testable. On peut donc utiliser des solutions type JUnit de façon standard, ce qui n'est pas possible sur des frameworks tel que Struts.

L'ensemble des éléments décrits ici est accessible via un micro projet que vous pourrez télécharger ci-dessous.
Projet de Test
L'archive du projet

Une fois votre projet installé sur un serveur d'application, il suffit de lancer l'URL suivante http://localhost:8080/test-mvc/premier-pas/welcome/Toto

3 commentaires

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.