Spring MVC

Introduction

Spring est un framework open source J2EE pour les applications n-tiers, dont il facilite le développement et les tests. Il est considéré comme un conteneur dit « léger », c’est-à-dire une infrastructure similaire à un serveur d’application J2EE. Il prend donc en charge la création d’objets et la mise en relation d’objets par l’intermédiaire d’un fichier de configuration qui décrit les objets à fabriquer et les relations de dépendances entre ces objets.

Le gros avantage par rapport aux serveurs d’application est qu’avec Spring, vos classes n’ont pas besoin d’implémenter une quelconque interface pour être prises en charge par le framework (au contraire des serveurs d’applications J2EE et des EJBs). C’est en ce sens que Spring est qualifié de conteneur « léger ».
Spring s’appuie principalement sur l’intégration de trois concepts clés :

  1. l’inversion de contrôle ou injection de dépendance (IoC).
  2. la programmation orientée aspect (AOP).
  3. une couche d’abstraction.

Ce framework, grâce à sa couche d’abstraction, ne concurrence pas d’autres frameworks dans une couche spécifique d’un modèle architectural MVC mais s’avère un framework multi-couches pouvant s’insérer au niveau de toutes les couches.

Nous avons vu dans les tutoriaux précédents Spring IoC et Spring AOP les concepts clés du framework Spring.
Nous allons aborder dans ce tutoriel la branche du framework Spring qui permet de donner une architecture MVC à la couche web d’une application 3tier.
Le module Web MVC du Framework Spring est construit autour d’un DispatcherServlet qui répartit les requêtes vers les handlers qui les prendront en charge.
Le handler par défaut est basé sur les annotations @Controller et @RequestMapping, permettant ainsi l’utilisation d’un large panel de méthodes.

Je vous invite à regarder les deux schémas consultables sur cette page de la documentation officielle de Spring qui permet de bien comprendre les mécanismes et la structure de Spring Web MVC.

Site Officiel

Vous trouverez le site officiel de Spring à l’adresse suivante : http://www.springsource.org/. Vous pouvez consulter la documentation de Spring Web MVC sur la page suivante

Wikipédia

Je vous invite à consulter les articles français et anglais de la célèbre encyclopédie Wikipédia à propos du Framework Spring.

Tutoriel

Avant d’entamer ce tutoriel, vérifiez que vous avez bien les pré requis :

  • Le JDK doit être installé sur votre machine.
  • Eclipse doit être installé sur votre machine (il est conseillé d’utiliser la version Eclipse IDE for Java EE Developers pour ce tutoriel)
  • Jetty doit être installé sur votre machine.
  • Avez vous réalisé le tutoriel sur Spring IOC?
  • Avez vous réalisé le tutoriel sur Spring AOP?
  • Connaissez vous le pattern MVC?

Il s’agit ici de montrer comment utiliser Spring Web MVC pour implémenter une interface Web. Dans un premier temps, on détaillera les bases du fonctionnement du module MVC de Spring pour ensuite faire nos premiers pas avec en réalisant une interface basique.

HelloWorld

Nous allons réaliser un exemple simple : un petit HelloWorld personnalisé sous forme d’interface Web. On accèdera à un formulaire où l’on saisira son prénom, son nom et un message, puis on validera et accèdera à une page qui affichera un message de bienvenue avec votre nom, prénom et le message que vous aurez saisi.

Création du projet

On commence par créer un nouveau projet dans Eclipse :

  1. Lancer Eclipse
  2. Menu File → New → Other
  3. Dans la fenêtre on saisit le mot clé web dans le champ, et on sélectionne ensuite Dynamic Web Project
  4. Dans la fenêtre New Dynamic Web Project, on indique le nom :
  5. sf-tutorial-spring-mvc
  6. On clique sur Next deux fois et on indique dans le champ Content Directory la valeur webapp
  7. On valide en cliquant sur Finish.
  8. Le projet a été créé, et on devrait alors avoir l’arborescence suivante :

Ajout des librairies

Vous devez télécharger les jars suivant et les ajouter à votre répertoire /sf-tutorial-spring-mvc/WebContent/WEB-INF/lib :

  • commons-logging.jar
  • servlet-api.jar
  • spring-asm-3.1.1.RELEASE.jar
  • spring-beans-3.1.1.RELEASE.jar
  • spring-context-3.1.1.RELEASE.jar
  • spring-core-3.1.2.RELEASE.jar
  • spring-expression-3.1.1.RELEASE.jar
  • spring-web-3.1.1.RELEASE.jar
  • spring-webmvc-3.1.1.RELEASE.jar
  • jstl.jar
  • standard.jar
  • validation-api-1.1.0.Beta2.jar

Il faut ensuite spécifier à Eclipse dans notre projet qu’on a ajouté une librairie pour pouvoir l’utiliser. On fait un clic droit sur le projet dans le package explorer qui ouvre un menu contextuel : on ouvre Build Path > Configure Build Path. On clic sur l’onglet Libraries, puis sur le bouton add JARS. Il suffit ensuite d’ajouter les bibliothèques ci-dessus.

Configuration de Spring

Afin de configurer notre application, nous allons créer un fichier web.xml dans le dossier WebContent/WEB-INF.
S
ur le dossier WEB-INF, clic droit puis New > Others. Dans la liste, choisissez XML File, et entrez web.xml comme nom.
Ensuite, ajoutez à ce fichier, les lignes suivantes :

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
	xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 
	<!-- On liste les pages d'accueil -->
	<welcome-file-list>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
 
	<!-- On déclare notre dispatcher -->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
 
	<!--
		On définit le modèle des url qui seront réparties par le dispatcher,
		dans notre exemple on filtre toutes les url se terminant par .mvc
	-->
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>*.mvc</url-pattern>
	</servlet-mapping>
 
</web-app>

On définit dans ce fichier :

  • la page d’accueil vers laquelle on sera redirigé
  • le DispatcherServlet
  • les différentes url à mapper : ici toutes les url se terminant par .mvc

 

Il faut maintenant créer un fichier au format XML qui porte le nom du <servlet-name> défini ci-dessus suivi du suffixe -servlet. Nous allons créer un fichier dispatcher-servlet.xml dans notre répertoire WEB-INF qui contiendra les lignes suivantes :

<?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">
 
	<!-- Les balises suivantes permettent de préciser que la configuration passe par les annotations  -->
	<context:annotation-config/> 
	<context:component-scan base-package= "com.scub.foundation.tutorial.spring.mvc.controller" />
	<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
 
 
   <!--
		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 /jsp/foo/bar/hello.jsp
		pour constuire la vue.
   -->
   <bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
   </bean>
 
 
   <!--
		Définition du controller qui va gérer le formulaire de la page d'index
		pour accéder à la page de bienvenue
   -->
   <bean name="indexController"
		class="com.scub.foundation.tutorial.spring.mvc.controller.IndexController">
		<property name="formView" value="pages/form" /> 
 		<property name="successView" value="pages/hello" /> 
		<property name="commandName" value="messagePersonneModel" />
   </bean>
 
</beans>

Les vues

Nous pouvons ensuite créer nos pages jsp.

La page d’accueil

Tout d’abord, nous devons créer une page d’accueil default.jsp dans le dossier WebContent qui va nous rediriger vers notre formulaire : Voici le code de la page :

<%
     response.sendRedirect("form.mvc");
%>

Cette page nous redirige automatiquement vers la page contenant le formulaire.

 

La page « formulaire »

Ensuite, ajoutons un dossier nommé « pages » dans le dossier WebContent/WEB-INF qui contiendra nos pages. La première page à créer s’appelle form.jsp. Elle sera un formulaire très simple, avec des champs pour saisir son nom, prénom ainsi qu’un message à afficher, et un bouton pour valider le formulaire: Voici le code de la page :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<HTML>
 
	<HEAD>
		<TITLE>Scub Foundation : Tutoriel Spring MVC</TITLE>
	</HEAD>
 
	<BODY>
		<!-- Titre -->
		<div id="title" align="center">
		<h1> Bienvenue dans le tutoriel de Scub Foundation sur Spring MVC </h1>
		</div>
		<hr/>
		<hr/>
 
		<h3>Renseignez les champs suivants : </h3>
		<div id="title" align="center">
		<form:form name="formulaire"commandName="messagePersonneModel" method="POST">
 
		    <table>
			    <tr>
			    	<td><label>Prenom : </label></td>
			        <td><form:input path="prenom" /></td>
			        <td><div style="color:red;"><form:errors path="prenom" /></div></td>
			    </tr>
			    <tr>
			    	<td><label>Nom : </label></td>
			        <td><form:input path="nom" /></td>
			    	<td><div style="color:red;"><form:errors path="nom" /></div></td>
			    </tr>
			    <tr>
			    	<td><label>Message : <label/></td>
			        <td><div style="color:red;"><form:input path="message" /></div></td>
			    </tr>
 
			    <tr>
			        <td colspan="2">
			            <input type="submit" value="Valider"/>
			        </td>
			    </tr>
			</table> 
 
		</form:form>
		</div>
 
	</BODY>
 
</HTML>
La page de message de bienvenue

A l’issue de ce formulaire, nous accéderons à une page hello.jsp, qui se trouve dans webapp/WEB-INF/pages/ et qui affichera un message de bienvenue avec le nom saisi dans le formulaire de la page form.jsp  et le message.

Voici le code de la page :

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ 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>Scub Foundation : Tutoriel Spring MVC</title>
	</HEAD>
 
	<BODY>
 
		<!-- ================================================================================================================ -->
		<!-- Titre -->
		<div id="title" align="center">
		<h1> Hello !</h1>
		</div>
		<!-- ================================================================================================================ -->
		<hr/>
		<hr/>
		<div align="center">
			Bonjour ${messagePersonneModel.prenom} ${messagePersonneModel.nom} ! 
			<br/>
			Votre message : ${messagePersonneModel.message}
		</div>
 
	</BODY>
</HTML>

Le modèle

On crée une classe MessagePersonneModel.java qui va représenter notre modèle :

package com.scub.foundation.tutorial.spring.mvc.model;
 
import java.io.Serializable;
 
/**
 * Command Class qui contient les informations utilisées dans le formulaire.
 * @author Scub-Foundation
 */
public class MessagePersonneModel implements Serializable {
 
	/** Identifiant unique généré. */
	private static final long serialVersionUID = -9110504410854001626L;
 
	/** Prénom de la personne. */
	private String prenom;
 
	/** Nom de la personne. */
	private String nom;
 
	/** Message adressé à la personne. */
	private String message;
 
	/**
	 * Accesseur en lecture
	 * @return le prenom
	 */
	public String getPrenom() {
		return prenom;
	}
 
	/**
	 * Accesseur en écriture
	 * @param prenom le nouveau prenom
	 */
	public void setPrenom(String prenom) {
		this.prenom = prenom;
	}
 
	/**
	 * Accesseur en lecture
	 * @return le nom
	 */
	public String getNom() {
		return nom;
	}
 
	/**
	 * Accesseur en écriture
	 * @param nom le nouveau nom
	 */
	public void setNom(String nom) {
		this.nom = nom;
	}
 
	/**
	 * Accesseur en lecture
	 * @return le message
	 */
	public String getMessage() {
		return message;
	}
 
	/**
	 * Accesseur en écriture
	 * @param message le nouveau message
	 */
	public void setMessage(String message) {
		this.message = message;
	}
}

Le contrôleur

Il faut maintenant définir notre contrôleur, une classe IndexController.java qui va être annotée :

package com.scub.foundation.tutorial.spring.mvc.controller;
 
import javax.validation.Valid;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
import com.scub.foundation.tutorial.spring.mvc.model.MessagePersonneModel;
import com.scub.foundation.tutorial.spring.mvc.validator.MessagePersonneValidator;
 
/**
 * @author Scub-Foundation
 */
@Controller
public class IndexController {
 
    /** Nom du model */
    private String commandName;
 
    /** Vue à afficher lorsque le formulaire est correctement rempli */
    private String successView;
 
    /** Vue contenant le formulaire */
    private String formView;
 
    /** Initialisation du validateur */
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new MessagePersonneValidator());
    }
 
    /**
     * Initialisation de la page de formulaire
     * @param model modele de la page
     * @return le nom de la page à afficher 
     */
    @RequestMapping(value = "form.mvc")
    public String initAccueil(final Model model) {
        MessagePersonneModel messagePersonneModel = new MessagePersonneModel();
 
        model.addAttribute(commandName, messagePersonneModel);
        return formView;
    }
 
    /**
     * Réception du résultat du formulaire
     * @param model modele de la page
     * @param messagePersonneModel Modele retourné par le formulaire
     * @param result Résultat du validateur
     * @return le nom de la page à afficher
     */
    @RequestMapping(value = "form.mvc", method = RequestMethod.POST)
    public String getInfoAccueil(final Model model, @Valid MessagePersonneModel messagePersonneModel, BindingResult result) {
        // S'il y a des erreurs, on reste sur le formulaire
        if (result.hasErrors())
            return formView;
        // Sinon, on passe à la page d'affichage des informations
        else {
            model.addAttribute("messagePersonneModel", messagePersonneModel);
            return successView;
        }
 
    }
 
    /** Setter sur le nom du modèle */
    public void setCommandName(String commandName) {
        this.commandName = commandName;
    }
 
    /** Setter du nom de la successView */
    public void setSuccessView(String successView) {
        this.successView = successView;
    }
 
    /** Setter du nom de la formView */
    public void setFormView(String formView) {
        this.formView = formView;
    } 
}
    • @Controller : permet de définir la classe en tant que controlleur
    • @RequestMapping : permet de configurer le mapping entre la vue et le controlleur par différents paramètres
        • value = « path » : indique à quel URI est liée la méthode
        • method = RequestMethod.POST : précise lorsque la requête est de type POST (ou GET via RequestMethod.GET).
    • @InitBinder : initialise et lie le validateur MessagePersonneValidator.java au controleur

Le validateur

Il est important lorsqu’on produit un formulaire de vérifier le contenu des informations saisies pour s’assurer de leur validité. Pour cela Spring propose une interface Validator.
C’est pourquoi nous allons créer une classe MessagePersonneValidator.java qui implémentera cette interface. On associe le validateur au contrôleur via la méthode initBinder de la classe IndexController.java. Voici le code source de notre validateur commenté :

package com.scub.foundation.tutorial.spring.mvc.validator;
 
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
 
import com.scub.foundation.tutorial.spring.mvc.model.MessagePersonneModel;
 
/**
 * Validateur pour le contenu de notre formulaire.
 * @author Scub-Foundation
 */
public class MessagePersonneValidator implements Validator {
 
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean supports(Class<?> clazz) {
		// Déclare les classes supportées par ce validateur
		return MessagePersonneModel.class.isAssignableFrom(clazz);
	}
 
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void validate(Object target, Errors errors) {
		// On spécifie ici que le champ du formulaire "prenom" est requis
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "prenom", null, "Champ obligatoire : veuillez saisir un prénom");
		// On spécifie ici que le champ du formulaire "nom" est requis
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "nom", null, "Champ obligatoire : veuillez saisir un nom");
	}
}

 

Exporter l’application au format war et la déployer sur le serveur Jetty

Maintenant que notre code est achevé pour notre exemple, il faut le “packager” sous la forme d’un fichier war, qu’on déploiera ensuite sur un serveur d’application. La démarche à suivre est simple :

  • Démarrez Jetty si ce n’est déjà fait.
  • Faites un clic droit sur le projet, et dans le menu contextuel aller dans Export puis choississez War file
  • Choisissez un emplacement pour votre war, clicquez sur Finish. Le war a été créé. Maintenant, déplacez le dans le dossier webapps de Jetty

Notre war a été créé et déposé dans le répertoire des applications Web de notre serveur Jetty. Nous pouvons maintenant tester notre application.

Test de l’application Web

On aura alors l’interface suivante :

On va dans un premier temps essayer de valider le formulaire sans avoir saisi de prénom ni de nom. La page se rechargera alors avec un message d’erreur comme ci-dessous.

On va ensuite remplir correctement le formulaire en saisissant au moins un prénom, et un nom, puis cliquer sur le bouton Valider. On est alors redirigé vers la page suivante :

Vous avez ainsi achevé le tutoriel sur Spring Web MVC, nous n’avons montré ici que ses fonctionnalités de base, vous aurez tout loisir d’apprendre à utiliser Spring Web MVC au fil du temps.

Télécharger les sources

Les sources du projet Eclipse pour ce tutoriel sont téléchargeables sur Source Forge à l’adresse suivante.