Création d’une application Spring MVC

Pré-requis

Avant de lire cet article, il est nécessaire d’avoir effectué :

Introduction

L’architecture MVC est une organisation de type Modèle-Vue-Contôleur. Pour créer un tel modèle, nous utilisons le module Web MVC du Framework Spring.

Ce module 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.

Pour mieux comprendre cette architecture, je vous propose de vous référer aux deux schémas suivants.

Pour plus d’informations, je vous conseille de consulter le site de Spring.

Modèle de projet

Je vous invite à lancer Eclipse et à parcourir le projet exemple contact-manager-spring-mvc-client (présent sur le repository de scub-foundation). Vous pourrez ainsi le suivre au fil de la lecture et mieux vous familiariser avec ce modèle de projet.



Le modèle de projet MVC respecte la structure standard de répertoire de Maven2. On retrouve donc :

  • le répertoire src qui regroupe les sources java et les ressources du projet
  • le répertoire target qui contient tous les éléments générés
  • le fichier pom.xml qui contient la description détaillée du projet

Le socle ajoute un répertoire conf qui va aider à gérer les configurations différentes suivant l’environnement (dev, test, prod-test, prod).

Le contenu du répertoire src

Le répertoire src/main/java

Ce répertoire contient tout notre code java et tout ce qui est en relation directe avec ce code java. Nous définissons donc dans le répertoire src/main/java l’ensemble des classes .java de notre module, notamment:

  • les classes du modèle (car nous utilisons le modèle MVC). Dans notre cas elles sont dans le package org.scub.foundation.contact.manager.client.spring.mvc.model. (Nous avons l’exemple de la classe ContactModel)
  • les classes des contrôleurs. Dans notre cas elles sont dans le package org.scub.foundation.contact.manager.client.spring.mvc.controller. (Nous avons l’exemple de classe ListContactsController et ManageContactController)

Le répertoire src/main/resources

Dans ce répertoire, nous avons un fichier applications.properties qui est destiné à contenir des propriétés de configuration de notre application.

Le contenu du répertoire src/web

Ce répertoire contient tout le code source concernant les vues de notre application, nous avons comme contenu de ce répertoire :

  • un fichier login.jsp qui est affiché afin de demander une authentification à l’utilisateur lorsqu’il tente de se connecter à l’application ;
  • un fichier index.jsp qui redirige l’utilisateur après son authentification vers une page d’accueil
  • un dossier erreurs contenant des pages d’erreurs personnalisées. Exemple de pages d’erreurs : 403.jsp, 404.jsp et 500.jsp ;
  • un dossier decorateurs qui contient des fichiers de structuration de nos pages web grâce au framework de gestion des layouts SiteMesh. Exemple de fichiers : decorateur_sample.jsp et empty.jsp (qui est un decorateur vide) ;
  • un dossier pages qui est destiné à contenir vos fichiers classiques .jsp (formulaires,pages de confirmation d’actions etc). Exemple de pages : index.jsp, page_sample_footer.jsp et page_sample_header.jsp.

Le contenu du répertoire conf

Le contenu du répertoire common/WEB-INF

Ce répertoire contient les fichiers suivants :

  • le fichier decorators.xml qui permet d’assurer la gestion des layouts grâce au framework java/j2EE SiteMesh ;
  • le fichier spring-mvc-servlet est le fichier de configuration de spring ;
  • le fichier web.xml est le fichier de configuration pour les applications web.

Les autres dossiers et fichiers du répertoire de configuration (conf) ne sont pas exploités spécifiquement par le modèle MVC, pour plus de détails, référez-vous au tutoriel création d’un îlot de services.

Le contenu du répertoire target

Comme dans tout projet Maven ce répertoire contient tout ce qui est généré à partir des sources de notre application lors des phases de compilation et de déploiement. Nous y trouverons par exemple: le .war de notre application qui peut être deployé dans un serveur web, ainsi que le jar du code source de toute l’application.

Création d’un projet spring MVC

La première étape, avant de commencer à implémenter les différentes couches de l’application, consiste à créer les projets à partir des modèles de projets intégrés au socle. Vous allez ici créer le projet client spring MVC.
Pour cela, rien de plus simple, il suffit d’utiliser l’assistant accessible via :

  • Le raccourci clavier Ctrl + N
  • Le menu File → New → Other
  • Le menu contextuel New → Other (comme sur la copie d’écran ci dessous).

Saisissez dans le champ le texte ”maven” pour filtrer l’affichage et sélectionnez Maven Project puis cliquez sur Next.

Vous accédez alors à l’assistant de création d’un projet Maven, vérifiez à la première étape que la case à cocher Create a simple project (skip archetype selection) est bien décochée (comme sur la copie d’écran ci dessous).

Cliquez ensuite sur Next pour accéder à l’étape suivante qui va permettre de sélectionner l’archetype, correspondant au projet que vous souhaitez créer. Sélectionnez l’archetype scub-foundation-archetype-client-spring-mvc puis cliquez sur Next comme indiqué sur la copie d’écran ci dessous.

Il reste ensuite à spécifier les paramètres suivants :

  • groupId : contact-manager qui est commun à tous les projets de la même application.
  • artifactId : contact-manager-spring-mvc-client
  • version : 1.0
  • package : org.scub.foundation.contact.manager

Cliquez ensuite sur Finish. Le nouveau projet apparait alors dans la vue Package Explorer.

Développement de notre client MVC ContactManager

Création de la vue

Créez une vue contact_form.jsp dans web/pages dans laquelle on déclare le formulaire qui permettra d’ajouter un contact.

Cliquez sur File puis selectionnez New et File

Puis remplissez la fenêtre New File :

  • Enter or select the parent folder :
    contact-manager-spring-mvc-client/src/web/pages
  • File name : contact_form.jsp

Cliquez sur Finish.

Le code de contact_form.jsp est :

<!--
    This file is part of Scub Foundation.
    Copyright (C) 2006-2013  SCUB
 
    Scub Foundation is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    Scub Foundation is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public License
    along with Scub Foundation.  If not, see <http://www.gnu.org/licenses/>.
-->
 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
 
<html>
 
     <head>
          <title>Contact Manager : Ajouter un contact</title>
          <SCRIPT type="text/javascript">
 
               function addEmailDiv(parentId){
                    var parent = document.getElementById(parentId);     
                    var nbEmails = parent.getElementsByTagName("div").length;
                    if (nbEmails<10)
		    {
                         var div = document.createElement('div');
			 div.id='div_emails_'+nbEmails;
 
			 var child = document.createElement('input');
			 child.type='text';
			 child.name='emails['+ nbEmails +']';
 
			 div.appendChild(child);
			 parent.appendChild(div);
 
			 addBtnDelete(div.id);
			 nbEmails++;
                    }
                    else{
	                 document.getElementById('modalEmails').style.visibility="visible";
		    }
               }
 
               function addTelDiv(parentId){
                    var parent = document.getElementById(parentId);
                    var nbTels = parent.getElementsByTagName("div").length;
                    if (nbTels<10)
                    {
                         var parent = document.getElementById(parentId);          
                         var div = document.createElement('div');
			 div.id='div_tels_'+nbTels;
			 div.class='input-append';
 
			 var child = document.createElement('input');
			 child.type='text';
			 child.name='telephones['+ nbTels +']';
			 div.appendChild(child);
 
			 parent.appendChild(div);
 
			 addBtnDelete(div.id);
			 nbTels++;
                    }
                    else{
                         document.getElementById('modalTels').style.visibility="visible";
                    }
               }
 
               function addBtnDelete(divId){
                    var div = document.getElementById(divId);
                    var btnSuppr = document.createElement('button');
                    var attrType = document.createAttribute('type');
                    attrType.value = 'button';
                    var attrClass = document.createAttribute('class');
                    attrClass.value = 'btn';               
                    var attrOnClick = document.createAttribute('onclick');
                    attrOnClick.value = 'deleteTB("'+ div.id +'")';
 
                    btnSuppr.setAttributeNode(attrType);               
                    btnSuppr.setAttributeNode(attrClass);          
                    btnSuppr.setAttributeNode(attrOnClick);
 
                    btnSuppr.innerHTML = '<i class="icon-minus"></i>';          
                    div.appendChild(btnSuppr);
               }
 
               function deleteTB(childId){
                    var element = document.getElementById(childId);          
                    element.parentNode.removeChild(element);
               }
 
               function closeModal(idModal){
                    document.getElementById(idModal).style.visibility="hidden";
               }
 
          </SCRIPT>
     </head>
 
     <body>
          <div class="span9">          
               <div class="well">
	            <form:form name="formulaire" class="form-horizontal" commandName="contactModel" method="POST" >
 
	 	         <!-- ID -->
	 		 <form:input id="inputId" path="id" type="hidden"/>
 
	 		 <!-- Civilité -->
	 		 <spring:bind path="civiliteId">
			      <div class="control-group">
		 	           <label class="control-label">Civilit&eacute;</label>
		 		   <div class="controls">
		 		        <label class="radio">
			    		     <form:radiobutton name="radioCivilite" id="radioCivilite1" path="civiliteId"  value="1" />
			    		     Monsieur
			    		</label>
			    		<label class="radio">
			    		     <form:radiobutton name="radioCivilite" id="radioCivilite2" path="civiliteId"  value="2" />
			    		     Madame
			    		</label>
			    		<label class="radio">
			    		     <form:radiobutton name="radioCivilite" id="radioCivilite3" path="civiliteId"  value="3" />
			    	             Mademoiselle
			    		</label>
					<p class="text-error"><form:errors path="civiliteId" /></p>
                                   </div>
                               </div>
                         </spring:bind>			
 
                         <!--Prénom -->
                         <spring:bind path="prenom">
  			     <div class="control-group">
		 	          <label class="control-label" for="inputPrenom">Pr&eacute;nom</label>
		 		  <div class="controls">
			    	       <form:input type="text" id="inputPrenom" path="prenom"/>
				       <p class="text-error"><form:errors path="prenom" /></p>
		 		  </div>
                              </div>
                         </spring:bind>	
 
			<!-- Nom -->					
			<spring:bind path="nom">
  			     <div class="control-group">
		 	          <label class="control-label" for="inputNom">Nom</label>
		 	               <div class="controls">
			                    <form:input type="text" id="inputNom" path="nom"/>
                                            <p class="text-error"><form:errors path="nom" /></p>
		 		       </div>
                             </div>
			</spring:bind>	
 
                         <!-- Emails -->
			 <spring:bind path="emails">
			      <div class="control-group">
			           <label class="control-label">Emails</label>
				        <div id="parentListEmails" class="controls">
				             <button type="button" class="btn" onClick="addEmailDiv('parentListEmails')"> <i class="icon-plus"></i> </button>
					     <c:if test="${status.error}">
					          <p class="text-error"><form:errors path="emails" /></p>
					     </c:if>
					     <c:forEach items="${contactModel.emails}" var="email" varStatus="itemsRow">
					          <div id="div_emails_${itemsRow.index}">
				                       <form:input type="text" name="emails[${itemsRow.index}]" path="emails[${itemsRow.index}]"/>
						       <button type="button" class="btn" onclick="deleteTB('div_emails_'+${itemsRow.index})">
						            <i class="icon-minus"></i>
						       </button>
						  </div>
					     </c:forEach>
                                        </div>
                              </div>
                         </spring:bind>
 
 
          		<!-- Modal d'alert pour le nombre d'emails -->
			<div class="modal" id="modalEmails" style="visibility:hidden">
			     <div class="modal-header">
                                  <button type="button" class="close" onClick="closeModal('modalEmails')">&times;</button>
				  <h3>Attention !</h3>
		             </div>
		             <div class="modal-body">
                                  <p>Vous ne pouvez ajouter plus de 10 emails par contact.</p>
		  	     </div>
		             <div class="modal-footer">
		                  <button type="button" class="btn" onClick="closeModal('modalEmails')">Close</button>
		             </div>
                         </div>
 
			 <!-- Téléphone -->
			 <spring:bind path="telephones">
			      <div class="control-group">
                                   <label class="control-label">T&eacute;l&eacute;phone</label>
                                   <div class="controls" id="parentListTel">
                                        <button type="button" class="btn" onClick="addTelDiv('parentListTel')"> <i class="icon-plus"></i> </button>
					<c:if test="${status.error}">
					     <p class="text-error"><form:errors path="telephones" /></p>
				        </c:if>
					<c:forEach items="${contactModel.telephones}" var="telephone" varStatus="itemsRow">
					     <div id="div_emails_${itemsRow.index}">
					          <form:input type="text" name="telephones[${itemsRow.index}]" path="telephones[${itemsRow.index}]"/>
					          <button type="button" class="btn" onclick="deleteTB('div_tels_'+${itemsRow.index})">
					               <i class="icon-minus"></i>
					          </button>
					     </div>
                                        </c:forEach>
                                   </div>
                              </div>
                         </spring:bind>
 
			 <!-- Modal d'alert pour le nombre de numéros de téléphones -->
                         <div class="modal" id="modalTels" style="visibility:hidden">
			      <div class="modal-header">
                                   <button type="button" class="close" onClick="closeModal('modalTels')">&times;</button>
				   <h3>Attention !</h3>
			      </div>
			      <div class="modal-body">
                                   <p>Vous ne pouvez ajouter plus de 10 num&eacute;ros de t&eacute;l&eacute;phone par contact.</p>          
                              </div>
                              <div class="modal-footer">
                                   <button type="button" class="btn" onClick="closeModal('modalTels')">Close</button>
                              </div>
                         </div>
 
                         <div id="submitRow"><button type="submit" class="btn">Valider</button></div>
 
                    </form:form>
 
               </div>
          </div>
     </body>
</html>

Vous pouvez voir que le fichier est constitué de deux parties : une première partie correspondant au code javascript de l’application permettant de gérer les tâches à effectuer suite à l’actionnement d’un bouton, et une seconde partie qui est notre code html. Cette partie met en forme le formulaire de sauvegarde d’un contact.

Les balises possèdent parfois le préfixe form, il permet d’indiquer que nous créons un formulaire et par conséquent permet de mapper les attributs de l’objet (de notre modèle) avec chaque champ de la page. Pour cela on utilise :

    • Dans la balise <form:form>, l’attribut commandName représentant le modèle associé au formulaire
    • Dans chaque <input>, l’attribut path afin de mapper l’attribut du modèle au champ texte


Création du modèle

Créez une classe ContactModel qui représentera un contact dans notre application.

Faites un clique droit sur répertoire du projet pour accéder au menu contextuel et sélectionnez New puis Class.

Dans la fenêtre de l’assistant New Java Class, indiquez dans les champs :

  • Package : org.scub.foundation.contact.manager.client.spring.mvc.model
  • Name : ContactModel

Cliquez sur Finish.

La classe ContactModel est constituée des attributs suivants :

package org.scub.foundation.contact.manager.client.spring.mvc.model;
 
import java.io.Serializable;
import java.util.List;
 
public class ContactModel implements Serializable {
 
    /**
     * Serial Version UID.
     */
    private static final long serialVersionUID = -5995895913036613123L;
 
    public ContactModel() {
        // TODO Auto-generated constructor stub
    }
 
    /**
     * Id du contact.
     */
    private Long id;
 
    /**
     * Id Civilite du contact
     */
    private Long civiliteId;
 
    /**
     * Label Civilite du contact
     */
    private String civiliteLabel;
 
    /**
     * Prénom du contact.
     */
    private String prenom;
 
    /**
     * Nom du contact.
     */
    private String nom;
 
    /**
     * Email du contact.
     */
    private List <String> emails;
 
    private List <String> telephones;
 
    /**
     * Get the value of id.
     * @return the id
     */
    public Long getId() {
        return id;
    }
 
    /**
     * Set the value of id.
     * @param id the id to set
     */
    public void setId(Long id) {
        this.id = id;
    }
 
    /**
     * Get the value of prenom.
     * @return the prenom
     */
    public String getPrenom() {
        return prenom;
    }
 
    /**
     * Set the value of prenom.
     * @param prenom the prenom to set
     */
    public void setPrenom(String prenom) {
        this.prenom = prenom;
    }
 
    /**
     * Get the value of nom.
     * @return the nom
     */
    public String getNom() {
        return nom;
    }
 
    /**
     * Set the value of nom.
     * @param nom the nom to set
     */
    public void setNom(String nom) {
        this.nom = nom;
    }
 
    /**
     * Get the value of civilite.
     * @return the civilite
     */
    public Long getCiviliteId() {
        return civiliteId;
    }
 
    /**
     * Set the value of civilite.
     * @param civilite the civilite to set
     */
    public void setCiviliteId(Long civiliteId) {
        this.civiliteId = civiliteId;
    }
 
    public String getCiviliteLabel() {
        return civiliteLabel;
    }
 
    public void setCiviliteLabel(String civiliteLabel) {
        this.civiliteLabel = civiliteLabel;
    }
 
    /**
     * Get the value of emails.
     * @return the emails
     */
    public List <String> getEmails() {
        return emails;
    }
 
    /**
     * Set the value of emails.
     * @param emails the emails to set
     */
    public void setEmails(List <String> emails) {
        this.emails = emails;
    }
 
    /**
     * Get the value of telephones.
     * @return the telephones
     */
    public List <String> getTelephones() {
        return telephones;
    }
 
    /**
     * Set the value of telephones.
     * @param telephones the telephones to set
     */
    public void setTelephones(List <String> telephones) {
        this.telephones = telephones;
    }
}

Création du contrôleur

Le contrôleur va permettre de traiter les informations saisies dans le formulaire afin de sauvegarder un contact lorsque l’utilisateur clique sur le bouton Enregistrer du formulaire.

Faites un clique droit sur répertoire du projet et sélectionnez New puis Class.

Remplissez comme indiqué ci-dessous :

  • Package : org.scub.foundation.contact.manager.client.spring.mvc.controller
  • Name : ManageContactController

Cliquez sur Finish.

Le code de ManageContactController.java est :

package org.scub.foundation.contact.manager.client.spring.mvc.controller;
 
import java.util.ArrayList;
import java.util.List;
 
import javax.validation.Valid;
 
import org.scub.foundation.contact.manager.client.spring.mvc.model.ContactModel;
import org.scub.foundation.contact.manager.client.spring.mvc.util.Constants;
import org.scub.foundation.contact.manager.client.spring.mvc.validators.SaveContactValidator;
import org.scub.foundation.contact.manager.core.dto.ContactDto;
import org.scub.foundation.contact.manager.core.dto.TelephoneDto;
import org.scub.foundation.contact.manager.core.service.interfaces.ContactService;
import org.scub.foundation.framework.base.dto.IdLabelDto;
import org.scub.foundation.framework.base.dto.value.PhoneAsValueDto;
import org.scub.foundation.framework.base.mapping.util.MapperDozerBean;
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 org.springframework.web.bind.annotation.RequestParam;
/**
 * Contrôleur permettant la sauvegarde d'un contact.
 * @author Julie Jageneau
 */
@Controller
public class ManageContactController {
 
    /** Mapper Dozer */
    private MapperDozerBean mapperDozerBean;
 
    /** Services permettant de gérer des contacts */
    private ContactService contactService;
 
    /** Nom du model */
    private String commandName;
 
    /** URL de la page formView */
    private String formView;
 
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new SaveContactValidator());
    }
 
    /**
     * Affiche le formulaire. Si contactId est nul, affiche un formulaire vide Sinon, retourne un contactModel pour pré remplir les champs
     * @param model
     * @param contactId id d'un conatc
     * @return la pege contenant le formulaire
     */
    @RequestMapping(value="pages/contact_form.do", method = RequestMethod.GET)
    public String initForm(final Model model, @RequestParam String contactId) {
        ContactModel contactModel = new ContactModel();
 
      //Initialisation des listes d'emails et de téléphones
        final List <String> emails = new ArrayList <String> ();
        final List <String> telephones = new ArrayList <String>();
        contactModel.setEmails(emails);
        contactModel.setTelephones(telephones);
 
        if (contactId != null && !contactId.trim().isEmpty()){
            final ContactDto contactDto = contactService.getContactById(Long.parseLong(contactId));
            contactModel = mapperDozerBean.map(contactDto, ContactModel.class);
 
            List <String> listTel = new ArrayList <String>();
            for (TelephoneDto telephoneDto : contactDto.getTelephones()) {
                listTel.add(telephoneDto.getValue().getNumero());
            }
            contactModel.setTelephones(listTel);
        }
 
        model.addAttribute(commandName, contactModel);
        model.addAttribute("contactId", contactId);
        return formView;
    }
 
    /**
     * Supprime un contact.
     * @param contactId identifiant du contact à supprimer
     * @return redirection vers la page d'accueil
     */
    @RequestMapping(value = "pages/delete/contact_form.do", method = RequestMethod.GET)
    public String deleteContact(@RequestParam String contactId) {
        contactService.deleteContact(Long.parseLong(contactId));
        return "redirect:/";
    }
 
    /**
     * Récupère les résultats du formulaire et redirige après traitement.
     * @param contactModel Model résultat du formulaire
     * @param result résultat du validateur
     * @return la page de redirection
     */
    @RequestMapping(value = "pages/contact_form", method = RequestMethod.POST)
    public String getForm(@Valid ContactModel contactModel, BindingResult result) {
 
        if (result.hasErrors()) {
            // s'il y a des erreurs, on reste sur le formulaire
            return formView;
        } else {
            // Copie du contenu de contactModel vers le DTO contactDto
            ContactDto contactDto = mapperDozerBean.map(contactModel, ContactDto.class);
 
            // Création d'une liste d'emails
            ArrayList <String> listeEmails = new ArrayList <String>();
            for (String email : contactModel.getEmails()) {
                if (email != null && !email.trim().isEmpty()) {
                    listeEmails.add(email);
                }
            }
            contactDto.setEmails(listeEmails);
 
            // Création d'une liste de téléphone
            ArrayList <String> listTel = new ArrayList <String>();
            for (String telephone : contactModel.getTelephones()) {
                if (telephone != null && !telephone.trim().isEmpty()) {
                    TelephoneDto tel = new TelephoneDto();
                    tel.setType(new IdLabelDto(Constants.TELEPHONE_TYPE));
                    PhoneAsValueDto phoneAsValueDto = new PhoneAsValueDto();
                    phoneAsValueDto.setNumero(telephone);
                    phoneAsValueDto.setFormat(Constants.TELEPHONE_FORMAT);
                    phoneAsValueDto.setIndicatif(Constants.TELEPHONE_INDICATIF);
                    phoneAsValueDto.setTag(Constants.TELEPHONE_TAG);
                    tel.setValue(phoneAsValueDto);
                    listTel.add(tel);
                }
            }
            contactDto.setTelephones(listTel);
 
            contactService.ajouterOuModifierContact(contactDto);
            return "redirect:/";
        }
 
    }
 
    /**
     * Setter de contactService
     * @param contactService nouveau contactService
     */
    public void setContactService(ContactService contactService) {
        this.contactService = contactService;
    }
 
    /**
     * Setter de mapperDozerBean
     * @param mapperDozerBean nouveau mapperDozerBean
     */
    public void setMapperDozerBean(MapperDozerBean mapperDozerBean) {
        this.mapperDozerBean = mapperDozerBean;
    }
 
    /**
     * Setter de commandName
     * @param commandName nouveau commandName
     */
    public void setCommandName(String commandName) {
        this.commandName = commandName;
    }
 
    /**
     * Setter de formView
     * @param formView nouveau formView
     */
    public void setFormView(String formView) {
        this.formView = formView;
    }
}

Quelques explications sur le contrôleur :

    • @Controller : spécifie que la classe est un contrôleur
    • @RequestMapping: mappe les requêtes web avec les méthodes concernées
      • l’attribut value : chemin exprimé explicitement permettant de relier la vue au contrôleur
      • l’attribut method : spécification de la méthode utilisée pour transmettre les données de la vue vers le contrôleur
    • @RequestParam : indique que le paramètre qui suit est nécessaire pour accéder à la méthode (dans notre cas, le paramètre est contactId de type String)
    • @InitBinder ainsi que la méthode qui suit cette annotation : définit le validateur à utiliser sur le modèle portant l’annotation @Valid

Configurer l’application cliente

Lier le client au(x) noyau(x)

Un client peut exploiter un ou plusieurs noyaux. Pour lier le client à un noyau, il suffit de rajouter une dépendance vers le projet correspondant, dans notre cas contact-manager-core-interfaces dans le POM du projet contact-manager-spring-mvc-client.

Ouvrez le fichier pom.xml. Vous pouvez ensuite configurer le POM :

  • Sélectionnez l’onglet pom.xml source (situé dans la partie inférieure)
  • Ajoutez l’élément correspondant au code ci-dessous à la fin du fichier.
    <dependencies>
        <dependency>
            <groupId>contact-manager</groupId>
            <artifactId>contact-manager-core-interfaces</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency> 		  
    </dependencies>

Il est nécessaire de publier le projet scub-foundation-my-contact-manager-core-interfaces dans le référentiel local afin de le rendre visible aux autres projets.

Importer les services de noyau(x)

Vous pouvez importer les services mis à disposition par les noyaux déclarés comme dépendances (cf. paragraphe précédent). Pour être en mesure d’utiliser les services développés dans les tutoriaux précédents :

  • Ouvrez le fichier /conf/dev/resources/rmiServiceImporterSpecContext.xml
  • Ajoutez le bean suivant afin d’ajouter les services déclarés dans l’interface contactService.java du projet core-interfaces:
    <bean id="contactService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl" value="rmi://localhost:1099/contact-manager-core-implementations/contactService"/>
        <property name="serviceInterface" value="org.scub.foundation.contact.manager.core.service.interfaces.ContactService"/>
        <property name="refreshStubOnConnectFailure" value="true"/>
        <property name="lookupStubOnStartup" value="false"/>
    </bean>

Mise à jour du fichier de configuration

Il reste à ajouter quelques lignes dans les fichiers de configuration Spring pour avoir une application cliente fonctionnelle.

  • Ouvrez le fichier /conf/common/WEB-INF/spring-mvc-servlet.xml
  • Mappez les url avec les contrôleurs développés précédemment
  • Déclarez vos contrôleurs
  • Déclarez votre validateur

Vous devez obtenir le code suivant :

<!--?xml version="1.0" encoding="UTF-8"?-->
<?xml version="1.0" encoding="UTF-8"?>
<!--
    This file is part of Scub Foundation.
    Copyright (C) 2006-2013  SCUB
 
    Scub Foundation is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    Scub Foundation is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public License
    along with Scub Foundation.  If not, see <http://www.gnu.org/licenses/>.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:context= "http://www.springframework.org/schema/context"
		xmlns:mvc= "http://www.springframework.org/schema/mvc"
		xmlns:p= "http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
           http://www.springframework.org/schema/context 
           http://www.springframework.org/schema/context/spring-context-3.1.xsd
           http://www.springframework.org/schema/mvc 
           http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
 
 
	<!-- Using annotations -->
	<context:annotation-config/>  
	<context:component-scan base-package= "org.scub.foundation.contact.manager.client.spring.mvc.controller" />
	 <mvc:annotation-driven validator="saveContactValidator"/>
 
	<bean 
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
 
 
 
 
	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>
 
	<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * MAPPING CONTROLLER * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  -->
 
	<bean id="mappingSpecifique" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="order"><value>0</value></property>
		<property name="mappings">
			<props>			
				 <prop key="/pages/list_contacts.do">listContactsController</prop>
				 <prop key="/pages/*contact_form.do">manageContactController</prop>		
			</props>
		</property>
	</bean>
 
	<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEFINITION DES CONTROLLERS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*  Definir ici vos controllers ex :
	*	<bean id="contactCommercialController"
	*	class="com.smatis.siteweb.controller.ContactController"> 
	*	<property name="contactService"><ref bean="contactService"/></property>
	*	<property name="sessionForm"><value>true</value></property>
	*	<property name="formView"><value>contacts/commercial/formulaireContactCommercial</value></property>
	*	<property name="successView"><value>contacts/commercial/formulaireContactCommercialSucces</value></property>
	*	<property name="commandName"><value>contact</value></property>
	*	<property name="commandClass"><value>com.smatis.siteweb.modele.contacts.ContactCommercial</value></property>
	*	<property name="validator"><ref bean="contactValidator" /></property>
	*	</bean>
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  -->
	<bean id="listContactsController" class="org.scub.foundation.contact.manager.client.spring.mvc.controller.ListContactsController">
		<property name="formView"><value>pages/list_contacts</value></property>
		<property name="successView"><value>pages/list_contacts</value></property>
		<property name="commandName"><value>contactCriteriasModel</value></property>
		<property name="contactService"><ref bean="contactService"/></property>
		<property name="mapperDozerBean"><ref bean="mapperDozerBean"/></property>
	</bean>
 
	<bean id="manageContactController" class="org.scub.foundation.contact.manager.client.spring.mvc.controller.ManageContactController">
		<property name="formView"><value>pages/contact_form</value></property>
		<property name="commandName"><value>contactModel</value></property>
		<property name="contactService"><ref bean="contactService"/></property>
		<property name="mapperDozerBean"><ref bean="mapperDozerBean"/></property>
	</bean>
 
	<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * VALIDATOR * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	* Definir ici les validators ex :
	* 	<bean id="identificationValidator" class="com.smatis.siteweb.validator.IdentificationValidator" />	
	* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  -->
	<bean id="saveContactValidator" class="org.scub.foundation.contact.manager.client.spring.mvc.validators.SaveContactValidator"/>
 
 
</beans>

Tester l’application

Remarque : Pour tester l’application complète, récupérez le projet exemple sur le repository de scub foundation.

Pour tester, il suffit maintenant de déployer les projets sur un serveur d’application.

  • Placez vous à la racine du projet scub-foundation-my-contact-manager-core-implementation
  • Publier le core dans le référentiel local
  • Déployer le core dans Jetty comme l’indique la copie d’écran ci-dessous :

  • Procédez de la même façon avec votre projet client MVC
  • Lancez à présent le navigateur Web de votre choix, et rendez vous à l’adresse pour accéder à l’application cliente Spring Web MVC
  • Identifiez vous avec les identifiants/mot de passe user / user
  • Vous devez à présent obtenir l’interface graphique ci-dessous :

  • Cette interface vous permet de rechercher un contact. Pour ajouter un nouveau contact, cliquez sur le lien Nouveau Contact du menu de gauche

Télécharger les sources

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