Mvc1 Spring

Embed Size (px)

Citation preview

Spring MVC par l'exemple - Partie 1 -

[email protected], mars 2006

springmvc - partie1, [email protected]

1/70

1 GnralitsDans le dveloppement web, la mthodologie de dveloppement MVC (Modle-Vue-Contrleur) est dsormais bien ancre. Rappelons-en le principe. Une application web a souvent une architecture 3tier :

utilisateur

Couche interface utilisateur [ui]

Couche mtier [metier]

Couche d'accs aux donnes [dao]

Donnes

la couche [dao] s'occupe de l'accs aux donnes, le plus souvent des donnes persistantes au sein d'un SGBD. Mais cela peut tre aussi des donnes qui proviennent de capteurs, du rseau, ... la couche [metier] implmente les algorithmes " mtier " de l'application. Cette couche est indpendante de toute forme d'interface avec l'utilisateur. Ainsi elle doit tre utilisable aussi bien avec une interface console, une interface web, une interface de client riche. Elle doit ainsi pouvoir tre teste en-dehors de l'interface web et notamment avec une interface console. C'est gnralement la couche la plus stable de l'architecture. Elle ne change pas si on change l'interface utilisateur ou la faon d'accder aux donnes ncessaires au fonctionnement de l'application. la couche [interface utilisateur] qui est l'interface (graphique souvent) qui permet l'utilisateur de piloter l'application et d'en recevoir des informations.

La communication va de la gauche vers la droite : l'utilisateur fait une demande la couche [interface utilisateur] cette demande est mise en forme par la couche [interface utilisateur] et transmise la couche [mtier] si pour traiter cette demande, la couche [mtier] a besoin des donnes, elle les demande la couche [dao] chaque couche interroge rend sa rponse la couche de gauche jusqu' la rponse finale l'utilisateur. Les couches [mtier] et [dao] sont normalement utilises via des interfaces Java. Ainsi la couche [mtier] ne connat de la couche [dao] que son ou ses interfaces et ne connat pas les classes les implmentant. C'est ce qui assure l'indpendance des couches entreelles : changer l'implmentation de la couche [dao] n'a aucune incidence sur la couche [mtier] tant qu'on ne touche pas la dfinition de l'interface de la couche [dao]. Il en est de mme entre les couches [interface utilisateur] et [mtier]. L'architecture MVC prend place dans la couche [interface utilisateur] lorsque celle-ci est une interface web. Des articles (par exemple : http://tahe.developpez.com/java/m2vc) ont montr qu'on pouvait galement appliquer le paradigme MVC une couche [interface utilisateur] Swing. Au sein de l'architecture 3tier, l'architecture MVC peut tre reprsente comme suit : Couche Interface Utilisateur [ui] utilisateur1

Contrleur4 3

2

Modle5

Couche mtier [metier]

Couche d'accs aux donnes [dao]

Donnes

Vue6

Le traitement d'une demande d'un client se droule selon les tapes suivantes : 1. le client fait une demande au contrleur. Celui-ci voit passer toutes les demandes des clients. C'est la porte d'entre de l'application. C'est le C de MVC. 2. le contrleur C traite cette demande. Pour ce faire, il peut avoir besoin de l'aide de la couche mtier. Une fois la demande du client traite, celle-ci peut appeler diverses rponses. Un exemple classique est : une page d'erreurs si la demande n'a pu tre traite correctement une page de confirmation sinon 3. le contrleur choisit la rponse (= vue) envoyer au client. Choisir la rponse envoyer au client ncessite plusieurs tapes : choisir l'objet qui va gnrer la rponse. C'est ce qu'on appelle la vue V, le V de MVC. Ce choix dpend en gnral du rsultat de l'excution de l'action demande par l'utilisateur.springmvc - partie1, [email protected]

2/70

lui fournir les donnes dont il a besoin pour gnrer cette rponse. En effet, celle-ci contient le plus souvent des informations calcules par le contrleur. Ces informations forment ce qu'on appelle le modle M de la vue, le M de MVC. L'tape 3 consiste donc en le choix d'une vue V et en la construction du modle M ncessaire celle-ci. 4. le contrleur C demande la vue choisie de s'afficher. Il s'agit le plus souvent de faire excuter une mthode particulire de la vue V charge de gnrer la rponse au client. Dans ce document, nous appelerons vue, aussi bien l'objet qui gnre la rponse au client que cette rponse elle-mme. La littrature MVC n'est pas explicite sur ce point. Si c'est la rponse qui devait s'appeler vue, on pourrait appeler gnrateur de vue, l'objet qui gnre cette rponse. 5. le gnrateur de vue V utilise le modle M prpar par le contrleur C pour initialiser les parties dynamiques de la rponse qu'il doit envoyer au client. 6. la rponse est envoye au client. La forme exacte de celle-ci dpend du gnrateur de vue. Ce peut tre un flux HTML, PDF, Excel, ...

La mthodologie de dveloppement web MVC ne ncessite pas ncessairement d'outils externes. On peut ainsi dvelopper une application web Java avec une architecture MVC avec un simple JDK et les bibliothques de base du dveloppement web. Une mthode utilisable pour des applications simples est la suivante :

le contrleur est assur par une servlet unique. C'est le C de MVC. toutes les requtes du client contiennent un attribut action, par exemple (http://.../appli?action=liste). selon la valeur de l'attribut action, la servlet fait excuter une mthode interne de type [doAction(...)]. la mthode [doAction] excute l'action demande par l'utilisateur. Pour cela, si besoin est, elle utilise la couche [mtier]. selon le rsultat de l'excution, la mthode [doAction] dcide d'une page JSP afficher. C'est la vue V du modle MVC. la page JSP a des lments dynamiques qui doivent tre fournis par la servlet. La mthode [doAction] va fournir ces lments. C'est le modle de la vue, le M de MVC. Ce modle est plac le plus souvent dans le contexte de la requte (request.setAttribute(" cl ", "valeur "), voire moins frquemment, dans le contexte de la session ou de l'application. On sait que la page JSP a accs ces trois contextes. la mthode [doAction] fait afficher la vue en transmettant le flux d'excution la page JSP choisie. Elle utilise pour cela, une instruction du genre [getServletContext() .getRequestDispatcher(" pageJSP ").forward(request, response)].

Pour des applications simples, dveloppes par un individu unique, cette mthode est suffisante. Nanmoins, lorsqu'on a crit plusieurs applications de ce type, on s'aperoit que les servlets de deux applications diffrentes : 1. ont le mme mcanisme pour dterminer quelle mthode [doAction] il faut excuter pour traiter l'action demande par l'utilisateur 2. ne diffrent en fait que par le contenu de ces mthodes [doAction] La tentation est alors grande de : factoriser le traitement (1) dans une servlet gnrique ignorante de l'application qui l'utilise dlguer le traitement (2) des classes externes puisque la servlet gnrique ne sait pas dans quelle application elle est utilise faire le lien entre l'action demande par l'utilisateur et la classe qui doit la traiter l'aide d'un fichier de configuration Des outils, souvent appels " frameworks ", sont apparus pour apporter les facilits prcdentes aux dveloppeurs. Le plus ancien et probablement le plus connu d'entre-eux est Struts (http://struts.apache.org/). Jakarta Struts est un projet de l'Apache Software Foundation (www.apache.org). Ce framework est dcrit dans (http://tahe.developpez.com/java/struts/). Apparu plus rcemment, le framework Spring (http://www.springframework.org/) offre des facilits analogues celles de Struts. Le but de cet article est de prsenter les possibilits de Spring MVC, la branche de Spring consacre au dveloppement web MVC. Une diffrence importante entre Struts et Spring est le champ d'applications de ces deux outils. Struts ne sert qu' construire le modle MVC dans la couche [interface web]. Spring offre lui, des outils pour le dveloppement des trois couches d'une application 3tier. Couche Interface Utilisateur[ui]1

utilisateur

Contrleur4 3

2

Modle5

Couche mtier [metier]

Couche d'accs aux donnes [dao]

Donnes

Vue6

SPRING Ci-dessus, on a reprsent Spring comme une couche transversale de l'application 3tier afin d'illustrer le fait qu'il offre des outils pour le dveloppement des trois couches. Struts lui, se cantonne uniquement la couche [interface utilisateur]. springmvc - partie1, [email protected] 3/70

On peut utiliser conjointement Spring et Struts : Spring pour l'intgration des couches, la gestion des transactions dans la couche [mtier], l'accs aux donnes dans la couche [dao], ... Struts dans la couche [interface utilisateur] Il peut cependant tre tentant de n'utiliser qu'un seul " framework " et d'utiliser dans la couche [interface utilisateur], Spring MVC en lieu et place de Struts. L'article " Variations autour d'une architecture web trois couches " ([http://tahe.developpez.com/java/web3tier]), prsente une application utilisant les trois architectures voques ici : une servlet propritaire traitant les actions avec des mthodes internes une architecture Struts une architecture Spring MVC Cet article prsente Spring MVC. Nous utiliserons une succession d'exemples simples pour illustrer les diffrentes facettes du produit et nous terminerons par la construction d'une application web MVC 3tier qui soit un peu raliste.

2 Outils utiliss et rfrencesLes outils utiliss pour les exemples ont t les suivants :

Eclipse 3.01 pour le dveloppement des applications Java, disponible l'url [http://www.eclipse.org]. Plugin Eclipse : Sysdeo Tomcat pour dvelopper des applications web avec le conteneur de servlets Tomcat, disponible l'url [http://www.sysdeo.com/eclipse/tomcatplugin]. Spring 1.2.4 disponible aux url [http://www.springframework.org/download]. On prendra la version de [Spring] avec dpendances car [Spring] utilise de nombreux outils tiers dont les archives sont contenues dans la version "avec dpendances". Tomcat 5 comme conteneur de servlets, disponible l'url [http://jakarta.apache.org].

Dans une chelle [dbutant-intermdiaire-avanc], ce document est dans la partie [intermdiaire]. Sa comprhension ncessite divers pr-requis. Certains d'entre-eux peuvent tre acquis avec des documents que j'ai crits. Dans ce cas, je les cite. Il est bien vident que ce n'est qu'une suggestion et que le lecteur peut utiliser ses documents favoris.

[ref1] : programmation web en Java [http://tahe.developpez.com/java/web/] [ref2] : utilisation d'Eclipse avec Tomcat 5 : [http://tahe.developpez.com/java/eclipse/]. Ce document prsente la version de Tomcat 5.0. Celle actuellement disponible est la 5.5.15 (mars 2006). Dans cette version, le lien [Tomcat administration] de la page d'accueil [http://localhost:8080] de Tomcat, ne fonctionne plus comme dans la version 5.0. En-dehors de ce point, les explications du document prcdent restent valides. Le prsent article n'utilise pas le lien [Tomcat administration]. [ref3] : documentation Spring : [http://www.springframework.org/documentation] [ref4] : utilisation de l'aspect IoC de Spring : [http://tahe.developpez.com/java/springioc] [ref5] : applications web 3tier avec une architecture MVC : [http://tahe.developpez.com/java/web3tier]

Pour crire cet article, je me suis servi de la documentation officielle de Spring ainsi que des deux ouvrages suivants : 1. 2. [ref6] : Professional Java Development with the Spring Framework, par Rod Johnson, Juergen Hoeller, Alef Arendsen, Thomas Risberg, Colin Sampaleanu, chez l'diteur Wiley [ref7] : Pro Spring, par Rob Harrop et Jan Machacek, chez l'diteur APress

Un livre est paru rcemment (fvrier 2006) sur Spring MVC [ref8] : Expert Spring MVC and Web Flow, par Seth Ladd, Darren Davison, Steven Devijver, Colin Yates aux ditions APress. Je n'ai pas eu l'occasion de le lire. A ma connaissance, c'est le premier livre sorti sur ce sujet. A ceux qui sont fchs avec l'anglais, je propose de lire l'article qui suit. Pour les autres, les trois rfrences prcdentes seront certainement utiles pour approfondir le sujet.

3 Le code des exemplesLe code des exemples qui vont suivre au mme endroit que cet article sous la forme d'un zip. Une fois celui-ci dzipp, on obtient l'arborescence suivante :

springmvc - partie1, [email protected]

4/70

Les dossiers [mvc-xx] sont des projets Eclipse. Ils ont tous un dossier [lib] vide. Celui-ci doit normalement contenir des archives .jar. Celles-ci tant de taille assez importante, on a viter de les dupliquer en les mettant uniquement dans le dossier [lib] ci-dessus :

Pour tester les diffrents projets sous Eclipse, on peut procder de la faon suivante. Sous Eclipse, importons par exemple le projet [mvc-02]. On clique droit dans [Package Explorer] :

Nous prenons l'option [Import ] :

springmvc - partie1, [email protected]

5/70

faire [Next]

faire [Browse] pour aller dsigner le projet [mvc-02] :

faire [OK]

faire [Finish]

Le projet s'ouvre dans [Package Explorer] :springmvc - partie1, [email protected]

6/70

Ci-dessus, la croix rouge indique que le projet est erron. Ceci parce que le dossier [lib] est vide. Avec l'explorateur windows, copier le contenu du dossier [lib] du fichier dzipp dans [mvc-02/WEB-INF/lib] :

Revenir sous Eclipse. Cliquer droit sur le nom du projet [spring-mvc-02] et prendre [Refresh] :

Cela force le projet se reconstruire :

Ci-dessus, le projet ne prsente plus d'erreurs.springmvc - partie1, [email protected]

7/70

Faire du projet [spring-mvc-02] une application Tomcat (clic droit sur projet) :

Pour le tester, lancer [Tomcat] :

Avec un navigateur, demander l'url [http://localhost:8080/spring-mvc-02/dosomething.html] :

Pour passer d'un projet l'autre, on ritre la dmarche prcdente. Pour permettre Tomcat de dmarrer plus vite, il est prfrable de supprimer le contexte des projets tests :

springmvc - partie1, [email protected]

8/70

Pour recrer ce contexte ultrieurement, il suffir de prendre l'option [Mise jour du contexte].

4 Les composantes d'une architecture Spring MVCRevenons sur l'architecture d'une application web MVC : Couche Interface Utilisateur[ui] utilisateur1

Contrleur4 3

2

Modle5

Couche mtier [metier]

Couche d'accs aux donnes [dao]

Donnes

Vue6

Spring MVC implmente cette architecture de la faon suivante : Couche Interface Utilisateur[ui] utilisateur1

DispatcherServlet2 3 4

Couche mtier [metier]

Couche d'accs aux donnes [dao]

Donnes

Controller5

Modle Map6

View7

1.

le client fait une demande au contrleur. Celui-ci voit passer toutes les demandes des clients. C'est la porte d'entre de l'application. C'est le C de MVC. Ici le contrleur est assur par une servlet gnrique : org.springframework.web.servlet.DispatcherServlet 9/70

springmvc - partie1, [email protected]

2.

3.

4.

5.

6. 7.

le contrleur principal [DispatcherServlet] fait excuter l'action demande par l'utilisateur par une classe implmentant l'interface : org.springframework.web.servlet.mvc.Controller A cause du nom de l'interface, nous appellerons une telle classe un contrleur secondaire pour le distinguer du contrleur principal [DispatcherServlet] ou simplement contrleur lorsqu'il n'y a pas d'ambigut. Le schma ci-dessus s'est content de reprsenter un contrleur particulier. Il y a en gnral plusieurs contrleurs, un par action. le contrleur [Controller] traite une demande particulire de l'utilisateur. Pour ce faire, il peut avoir besoin de l'aide de la couche mtier. Une fois la demande du client traite, celle-ci peut appeler diverses rponses. Un exemple classique est : une page d'erreurs si la demande n'a pu tre traite correctement une page de confirmation sinon le contrleur choisit la rponse (= vue) envoyer au client. Choisir la rponse envoyer au client ncessite plusieurs tapes : choisir l'objet qui va gnrer la rponse. C'est ce qu'on appelle la vue V, le V de MVC. Ce choix dpend en gnral du rsultat de l'excution de l'action demande par l'utilisateur. lui fournir les donnes dont il a besoin pour gnrer cette rponse. En effet, celle-ci contient le plus souvent des informations calcules par la couche mtier ou le contrleur lui-mme. Ces informations forment ce qu'on appelle le modle M de la vue, le M de MVC. Spring MVC fournit ce modle sous la forme d'un dictionnaire de type java.util.Map. L'tape 4 consiste donc en le choix d'une vue V et la construction du modle M ncessaire celle-ci. le contrleur DispatcherServlet demande la vue choisie de s'afficher. Il s'agit d'une classe implmentant l'interface org.springframework.web.servlet.View Spring MVC propose diffrentes implmentations de cette interface pour gnrer des flux HTML, Excel, PDF, ... Le schma ci-dessus s'est content de reprsenter une vue particulire. Il y a en gnral plusieurs vues. le gnrateur de vue View utilise le modle Map prpar par le contrleur Controller pour initialiser les parties dynamiques de la rponse qu'il doit envoyer au client. la rponse est envoye au client. La forme exacte de celle-ci dpend du gnrateur de vue. Ce peut tre un flux HTML, PDF, Excel, ...

Examinons le traitement d'une demande du client sous un aspect un peu plus technique : Etapes 1-2 : choix du contrleur traitant l'action demande par l'utilisateur Avec Spring MVC, c'est partir de l'URL demande par le client que le contrleur principal [DispatcherServlet] va choisir l'objet [Controller] qui va traiter l'action. Le lien URL Controller est fait par configuration. Il existe plusieurs mthodes de rsolution possibles, c.a.d. plusieurs faons possibles de lier une URL un objet [Controller]. Etapes 3-5 : traitement de la demande par l'objet [Controller] L'objet [Controller] charg de traiter l'action [org.springframework.web.servlet.mvc.Controller]. est une instance de classe implmentant l'interface

Spring offre plusieurs classes implmentant l'interface [Controller] :

Ces classes sont normalement destines tre drives. On se souvient en effet, que le contrleur est charg de traiter une action d'une application spcifique. Ceci ne peut tre fait dans les classes gnriques ci-dessus sauf lorsqu'il n'y a pas de traitement faire (ParameterizableViewController, ServletForwardingController). De faon gnrale, c'est au dveloppeur de construire la classe implmentant l'interface [Controller]. Il peut parfois se faire aider en drivant cette classe des classes ci-dessus. C'est notamment le cas si l'action demande est le POST d'un formulaire. Dans ce cas particulier important, la classe [SimpleFormController] apporte des facilits de dveloppement. L'interface [Controller] n'a qu'une mthode :

springmvc - partie1, [email protected]

10/70

l'unique mthode implmenter par un contrleur est donc [handleRequest] qui a pour paramtres, l'objet [request] qui encapsule la requte HTTP du client, et l'objet [response] qui lui encapsule la rponse HTTP qui sera faite ce mme client. comme le montre le schma plus haut, un contrleur doit dsigner une vue V afficher en rponse la demande du client et le modle M qui sera affich par cette vue. Ces deux lments sont rendus par [handleRequest] sous la forme d'un objet de type [ModelAndView] plus exactement [org.springframework.web.servlet.ModelAndView].

Un objet de type [ModelAndView] peut tre construit de diverses faons :

1 2 3 4 5 6 7

1. 2.

3. 4. 5.

le constructeur [1] ne dfinit ni modle, ni vue. Ceux-ci sont alors dfinis ultrieurement via les mthodes de la classe [ModelAndView] le constructeur [2] dfinit une vue V d'aprs son nom. Nous savons qu'au final, la vue est un objet implmentant l'interface [org.springframework.web.servlet.View]. Le lien nom objet View est alors fait dans un fichier de configuration. Le constructeur [2] ne prcise pas de modle. Il convient donc pour une vue sans modle. On peut aussi prciser le modle ultrieurement via des mthodes de [ModelAndView]. le constructeur [3] dfinit une vue V d'aprs son nom et dfinit galement un modle M sous la forme d'un objet implmentant l'interface [java.util.Map], donc un dictionnaire. le constructeur [4] est une variante du constructeur [3] lorsque le modle n'a qu'un unique lment. Dans ce cas, le dictionnaire n'a qu'un lment dont la cl sera [modelName] et la valeur associe [modelObject]. les constructeurs [5, 6, 7] sont des variantes des constructeurs [2, 3, 4] dans lesquelles, la vue V n'est plus dsigne par son nom mais directement instancie par un objet implmentant l'interface [View]. L'association nom vue objet View n'a alors plus tre faite dans le fichier de configuration.

Les mthodes de la classe [ModelAndView] sont les suivantes :

springmvc - partie1, [email protected]

11/70

1 2

les mthodes [1] et [2] permettent d'ajouter des lments au modle M

3 4

les mthodes [3] et [4] permettent de prciser la vue V soit par une instance View [3], soit par le nom de la vue [4].

Etapes 6-7 : rendu du modle M par la vue V Arriv ici, le flux d'excution a t transfr une vue [View]. [View] est une interface avec l'unique mthode suivante :

assez logiquement, l'unique mthode [render] dispose de l'objet [response] partir duquel la rponse HTTP va tre construite et du modle [model] construit prcdemment par le contrleur. La mthode [render] dispose galement de l'objet [request] qui encapsule la requte HTTP du client. Via cet objet, la mthode [render] a accs au contexte de la requte, la session qui lui est lie, ... L'une des implmentations de l'interface [View] est la classe [JstlView] qui implmente la vue l'aide d'une page JSP utilisant des balises JSTL. La mthode [render] de la classe [JstlView] met les lments du dictionnaire [model] qu'elle a reu dans le contexte de la requte [request]. C'est l que la page JSP qui sera envoye au client trouvera son modle.

Spring propose plusieurs implmentations de l'interface [View] :

springmvc - partie1, [email protected]

12/70

Des noms de classes ci-dessus, on peut dduire que Spring offre des classes permettant d'avoir des vues

de type HTML (JstlView), Excel, PDF destines des frameworks d'affichage : Velocity, FreeMarker, Tiles

Dans la suite, nous prsenterons des exemples illustrant les diffrentes tapes de traitement d'une requte dcrites ci-dessus.

5 Configuration d'une application Spring MVCUne application Spring MVC est une application web. Elle obit donc aux rgles de configuration de ce type d'applications. Cidessous, nous montrons comment est configure une application Spring MVC. L'environnement de dveloppement utilis est Eclipse. Le lecteur fera la part des choses entre ce que l'architecture dcrite doit Eclipse et qui est propre Eclipse et ce qui ressort de la configuration ncessaire de toute application web, quelque soit l'environnement de dveloppement utilis. Les applications qui vont suivre ont t construites sous Eclipse avec le plugin Sysdeo Tomcat afin de pouvoir lancer, arrter, relancer Tomcat partir d'Eclipse. Le dveloppement web avec Eclipse et Tomcat est dcrit dans [ref2] (cf page 4). Les diffrents projets que nous allons construire sous Eclipse seront tous des projets de type [Projet Tomcat]. Rappelons comment se cre un tel projet :

on dmarre l'assistant de cration par [File / New / Project ] :

on choisit le type [Projet Tomcat] on indique le nom du projet et son emplacement dans le systme de fichiers :

on donne un nom (contexte) l'application web :

springmvc - partie1, [email protected]

13/70

et c'est fini :

Le projet apparat dans l'explorateur de projets d'Eclipse :

Avec un clic droit sur le nom du projet, on a accs diverses proprits du projet Tomcat :

Les options utiles sont les suivantes : Mise jour du contexte : cre le fichier de dfinition de l'application qui indique Tomcat que cette application fait partie des applications qu'il doit grer. Suppression du contexte : supprime le fichier prcdent. Cela vite Tomcat de charger des ressources pour une application qui n'est temporairement plus utilise par exemple. Cela acclre galement le dmarrage de Tomcat. Recharger le contexte : demande Tomcat de recharger le contexte de l'application parce qu'on y a apport une modification. L'application est alors recharge sans avoir relancer Tomcat. Nous dcrivons maintenant une structure typique des applications Spring MVC que nous allons construire.

springmvc - partie1, [email protected]

14/70

WEB-INF/src Ce dossier contiendra les classes des applications web. C'est le plugin Tomcat qui l'impose. Nous mettrons les classes Java toujours dans le mme paquetage [istia.st.springmvc.exemples.web]. Les classes compiles sont automatiquement places dans le dossier [WEB-INF/classes], l o les attend le serveur web Tomcat. Tous les fichiers du dossier [WEB-INF/src] autres que les classes .java sont automatiquement recopies en l'tat dans [WEBINF/classes]. Dans une application web, le dossier [WEB-INF/classes] fait partie du " Classpath " de l'application web. Aussi mettra-t-on dans [WEB-INF/src] tous les fichiers qui doivent tre dans le Classpath de l'application. C'est le cas du fichier [log4j.properties] ci-dessus. Ce fichier est recherch dans le Classpath par l'archive [log4j-1.2.9.jar] que l'on voit dans la copie d'cran ci-dessus. Cette archive contient les classes de l'outil log4j souvent utilis pour afficher des logs. log4j est configur l'aide du fichier [log4j.properties]. A ma grande honte, j'avoue ne pas bien connatre log4j. J'ai utilis le fichier [log4j.properties] minimal suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. # Global logging configuration log4j.rootLogger=INFO, stdout # configuration... org.apache.commons.digester.Digester=INFO # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

En l'absence de ce fichier, Spring affichait sur la console un message disant que log4j n'tait pas configur. Il prcisait de plus que c'tait la classe [org.apache.commons.digester.Digester] qui voulait faire des logs. Aprs quelques recherches sur le web, j'ai cr le fichier prcdent. Les lignes sont standard : on les retrouve dans tous les exemples de [log4j.properties]. J'ai utilis le message de Spring pour la ligne 5 qui elle est spcifique. Ceci fait, Spring ne s'est plus plaint et a fait ses logs sur la console. Je m'en suis tenu l et c'est ce mme fichier qui sera utilis dans toutes les applications. WEB-INF/lib Ce dossier est facultatif. J'y mets toutes les archives .jar dont l'application a besoin :

spring.jar : la totalit de l'archive Spring 1.2.4 [http://www.springframework.org] commons-*.jar : bibliothques " commons " utilises par Spring [http://jakarta.apache.org/commons/] jstl.jar, standard.jar : bibliothques ncessaires pour l'utilisation des balises JSTL dans les pages JSP [http://jakarta.apache.org/taglibs/] log4j-1.2.9.jar : bibliothque de logs [http://logging.apache.org/log4j/docs/]

Le fait de mettre ces archives dans [WEB-INF/lib] n'a aucune signification particulire. Pour que l'application les reconnaisse, il faut les mettre dans son Classpath. Sous Eclipse, on procde comme suit : 1. clic droit sur le nom du projet / Properties / Java Build Path

springmvc - partie1, [email protected]

15/70

2.

utiliser [Add Jars] pour ajouter les archives dsires. Eclipse indique alors les archives du Classpath dans sa modlisation du projet :

WEB-INF/vues Nous utiliserons ce dossier pour y mettre les pages JSP qui serviront de vues l'application. Ces vues peuvent tre mises n'importe o dans le dossier de l'application web. En les mettant sous le dossier [WEB-INF] on interdit un utilisateur extrieur de demander directement une vue JSP. Il devra passer obligatoirement par l'une des actions dfinies pour l'application. WEB-INF Ce dossier est obligatoire dans une application web Java. Il comporte au moins deux lments : [WEB-INF/classes] qui contient les fichiers .class ncessaires l'application web.xml : le fichier de configuration de l'application Le fichier [web.xml] sera pour toutes les applications construit sur le modle suivant :1. 2. 3. 6. 7. 8. 9. 10. org.springframework.web.context.ContextLoaderListener 11. 12. 13. 14. spring-mvc-10 15. 16. org.springframework.web.servlet.DispatcherServlet 17. 18. 19. 20. spring-mvc-10 21. *.html springmvc - partie1, [email protected]

16/70

22. 23.

lignes 8-11 : dfinissent une classe qui est charge au dmarrage de l'application. La classe [org.springframework.web.context.ContextLoaderListener] est une classe Spring charge d'initialiser le contexte de l'application web en lisant le contenu du fichier [WEB-INF/applicationContext.xml]. Ce fichier nous servira instancier les couches [mtier] et [dao] lorsqu'il y en a. Lorsque l'application n'aura que la couche [interface utilisateur] et pas les couches [mtier] et [dao], le fichier [WEB-INF/applicationContext.xml] n'existera pas, ni les lignes 8-11 ci-dessus. Ce sera souvent le cas dans nos applications exemple o il n'y aura le plus souvent que la seule couche d'interface web. lignes 13-14 : dfinissent une servlet : ligne 14 : nom de la servlet ligne 16 : classe de la servlet. Avec Spring MVC, cette classe est toujours la classe [org.springframework.web.servlet.DispatcherServlet] qui joue le rle du contrleur C du MVC. lignes 19-22 : dsignent les URL gres par l'application : ligne 21 : indique que toute URL termine par .html est gre par l'application ligne 20 : dsigne la servlet charge de grer les URL dfinies ligne 21.

Le fichier [web.xml] ci-dessus indique donc que : toute URL termine par .html doit tre traite par la servlet appele [ spring-mvc-10 ] que la servlet [ spring-mvc-10 ] dsigne la classe [org.springframework.web.servlet.DispatcherServlet], une classe de Spring Le contrleur [org.springframework.web.servlet.DispatcherServlet] associ la servlet [spring-mvc-10] et charg de traiter les URL *.html, a besoin d'informations pour traiter les demandes de l'utilisateur. Il a par exemple besoin de connatre pour chaque URL [ur1.html], l'objet [Controller] charg de la traiter. Nous avons vu qu'un objet [Controller] allait dsigner la vue renvoyer l'utilisateur par son nom. Le contrleur [DispatcherServlet] aura donc besoin de savoir qu' tel nom de vue correspond telle page JSP. D'autres informations seront galement ncessaires. Nous les dtaillerons progressivement. Le contrleur [org.springframework.web.servlet.DispatcherServlet] associ la servlet [spring-mvc-10] trouvera ces informations dans le fichier [WEB-INF/spring-mvc-10-servlet.xml]. Le fichier porte donc le nom de la servlet. Il aura un contenu qui pourra ressembler ceci :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. DoSomethingController org.springframework.web.servlet.view.JstlView /WEB-INF/vues/ .jsp

Il est trop tt pour entrer dans les dtails mais voici les grandes lignes de ce fichier : lignes 5-11 : indiquent que l'URL se terminant par [/dosomething.html] doit tre trait par l'objet [Controller] nomm [DoSomethingController]. Nous avons vu que [web.xml] redirigeait les URL *.html vers [DispatcherServlet]. Le fichier [servlet-mvc-10-servlet.xml] prcise les choses : seule l'URL [*/dosomething.html] sera accepte. Les autres seront refuses. lignes 13-18 : dfinissent la classe associe au contrleur de nom [DoSomethingController]. Cette classe est crite par le dveloppeur pour les besoins spcifiques de l'application et implmente l'interface [Controller]. La classe l'implmentant est ici [istia.st.springmvc.exemples.web.DoSomething], une classe propritaire qu'on trouve dans [WEB-INF/src] sur la copie d'cran du projet Eclipse. springmvc - partie1, [email protected] 17/70

lignes 20-30 : dfinissent comment partir du nom d'une vue, on trouve la page JSP associe. Si [DoSomethingController] demande l'affichage d'une vue appele V, c'est la page JSP [WEB-INF/vues/V.jsp] qui sera affiche.

Pour terminer, la copie d'cran du projet montre la prsence du fichier [c.tld] dans le dossier [WEB-INF]. Ce fichier dfinit la syntaxe des balises de la bibliothque JSTL. Les pages JSP utilisent souvent cette bibliothque de balises qui permet de rduire la prsence de code Java dans la page JSP. Les pages JSP auront un contenu analogue au suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. Spring-mvc-10 Vue n 0 Membres du groupe ${personne}
DoSomething excut en ${dure} ms...

la ligne 1 est facultative. Elle prcise le type de codage utilis pour les caractres du fichier. ISO-8859-1 autorise les caractres accentus. la ligne 2 indique o trouver un fichier de dfinition de balises. Ici c'est le fichier [c.tld] dont on vient de parler. la ligne 3 indique que les expressions ${identificateur} (par exemple ${personne}ci-dessus) doivent tre interprtes. Selon la version JSTL utilise et celle des pages JSP, cette balise est parfois ncessaire, parfois pas. Avec les versions de JSTL et JSP utilises pour les exemples, elle tait ncessaire.

6 La liaison URL - Controller6.1 Les stratgies de rsolution des URL

Reprenons l'architecture d'une application Spring MVC : Couche Interface Utilisateur[ui] utilisateur1

DispatcherServlet2 3 4

Couche mtier [metier]

Couche d'accs aux donnes [dao]

Donnes

Controller5

Modle Map6

View7

1. 2.

le client fait une demande au contrleur. Celui-ci voit passer toutes les demandes des clients. C'est la porte d'entre de l'application. C'est le C de MVC. Ici le contrleur est assur par une servlet gnrique : org.springframework.web.servlet.DispatcherServlet le contrleur principal [DispatcherServlet] fait excuter l'action demande par l'utilisateur par une classe implmentant l'interface : org.springframework.web.servlet.mvc.Controller

Comment le contrleur [DispatcherServlet] sait-il quel objet [Controller] doit traiter la demande du client ? La demande du client est contenue dans l'URL demande au serveur et ventuellement dans les donnes qui l'accompagnent (dans la cas du requte HTTP POST ou plus rarement HTTP PUT). Spring se sert de l'URL pour dterminer quel objet [Controller] doit springmvc - partie1, [email protected] 18/70

traiter la demande. Spring met notre disposition diverses stratgies pour lier une URL un objet [Controller]. Le choix d'une stratgie particulire est fait dans le fichier de configuration [S-servlet.xml] de la servlet S de l'application Spring MVC en prcisant le nom d'une classe implmentant l'interface [org.springframework.web.servlet.HandlerMapping]. Spring offre les classes d'implmentation suivantes :

[BeanNameUrlHandlerMapping] : avec cette classe, une URL de la forme [http://machine:port/chemin1/.../document] sera traite par le Controller nomm [document]. C'est la stratgie de rsolution par dfaut si aucune stratgie n'est dfinie dans le fichier de configuration de la servlet. [SimpleUrlHandlerMapping] : avec cette classe, chaque URL [http://machine:port/chemin1/.../document ] devant tre traite par l'application est dclare dans le fichier de configuration de la servlet. Dans cette dclaration , on associe [/document] le nom de l'objet [Controller] qui doit la traiter.

Les deux stratgies permettent de spcifier des URL gnriques, par exemple /erreur*.html. La stratgie [SimpleUrlHandlerMapping] permet des URL gnriques plus complexes que celles permises par la stratgie [BeanNameUrlHandlerMapping]. Par ailleurs, la stratgie [SimpleUrlHandlerMapping] permet d'externaliser dans un fichier les associations URL Controller. Nous prsentons tout d'abord un exemple utilisant la stratgie [SimpleUrlHandlerMapping].

6.2

La stratgie SimpleUrlHandlerMapping

Le projet Eclipse de l'exemple est le suivant :

L'application est dfinie par le fichier [web.xml] suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. spring-mvc-02 org.springframework.web.servlet.DispatcherServlet spring-mvc-02 *.html

Ce fichier a dj t expliqu. Simplement notons que la servlet de l'application s'appelle [spring-mvc-02] et que donc son fichier de configuration doit s'appeler [spring-mvc-02-servlet.xml]. Ce fichier est prsent sur la copie d'cran ci-dessus. Son contenu est le suivant :1. 2. 3. 4. 5. 6.

springmvc - partie1, [email protected]

19/70

7. 8. DoSomethingController 9. 10. 11. 12. 13. 15.

lignes 5-11 : dfinissent la stratgie de rsolution des URL, ici la stratgie [ SimpleUrlHandlerMapping ]. On remarquera que le bean de la ligne 5 n'a pas de d'attribut " id ", attribut qui identifie les beans. On pourrait lui en donner un mais ce n'est pas obligatoire car il n'est pas rfrenc par ailleurs dans le fichier. Spring MVC instancie automatiquement un certain nombre de beans. C'est le cas des beans dfinissant la stratgie de rsolution, c'est dire des beans implmentant l'interface [HandlerMapping]. ligne 6-9 : dfinissent les liaisons URL Controller de l'application. On y trouve toutes les URL que l'application doit traiter avec, associ, le nom de l'objet Controller qui doit les traiter. ligne 8 : indique que l'URL se terminant par [/dosomething.html] doit tre traite par le Controller de nom [DoSomethingController]. lignes 13-14 : dfinissent le Controller de nom [DoSomethingController] (attribut id). On y indique que ce Controller est une instance de la classe [istia.st.springmvc.exemples.web.DoSomething], une classe propritaire que nous allons dfinir maintenant.

La classe [DoSomething] a t place dans [WEB-INF/src] comme le montre le projet Eclipse. Sa dfinition est la suivante :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. package istia.st.springmvc.exemples.web; import java.io.PrintWriter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class DoSomething implements Controller { // gestion de la requte public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { // on code en dur response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println( "Spring-MVC-02"+ "DoSomething excut..."); // pas de ModelAndView return null; } }

Rappelons tout d'abord qu'un objet [Controller] doit implmenter l'interface [Controller]. C'est ce que fait la classe ci-dessus, ligne 10.

lignes 13-23 : dfinissent la mthode [ handleRequest ] qui est l'unique mthode de l'interface [Controller]. Cette mthode doit rendre un couple (Vue, Modle) sous la forme d'un objet de type [ModelAndView]. Cet objet est ensuite utilis par le contrleur [DispatcherServlet] pour envoyer une rponse au client. Ici nous dcidons d'envoyer la rponse nous-mmes. C'est possible puisque nous disposons du paramtre [ HttpServletResponse response ] qui encapsule la rponse HTTP destine au client. ligne 16 : prcise que le flux qui va tre envoy est un flux HTML ligne 17 : rcupre le flux d 'criture vers le client lignes 18-20 : le flux HTML est envoy ligne 22 : on retourne au contrleur [DispatcherServlet] le pointeur null comme objet [ModelAndView]. Le contrleur interprte ce pointeur null comme le fait que la rponse au client a t envoye et qu'il ne doit pas s'en occuper.

Nous sommes prts pour un test. Nous lanons Tomcat :

springmvc - partie1, [email protected]

20/70

Dans la console, Spring affiche de nombreux logs qu'il est souvent intressant de lire. Ceux lis l'application [servlet-mvc-02] sont les suivants :INFO [http-8080-Processor23] - Initializing servlet 'spring-mvc-02' INFO [http-8080-Processor23] - FrameworkServlet 'spring-mvc-02': initialization started INFO [http-8080-Processor23] - Loading WebApplicationContext for Spring FrameworkServlet 'spring-mvc-02' INFO [http-8080-Processor23] - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring-mvc-02servlet.xml] INFO [http-8080-Processor23] - Bean factory for application context [WebApplicationContext for namespace 'spring-mvc-02servlet']: org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping,DoSomethingController]; root of BeanFactory hierarchy INFO [http-8080-Processor23] - 2 beans defined in application context [WebApplicationContext for namespace 'spring-mvc02-servlet'] INFO [http-8080-Processor23] - JDK 1.4+ collections available INFO [http-8080-Processor23] - Commons Collections 3.x available INFO [http-8080-Processor23] - Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@1d314cc] INFO [http-8080-Processor23] - Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@31d5e2] INFO [http-8080-Processor23] - No ThemeSource found for [WebApplicationContext for namespace 'spring-mvc-02-servlet']: using ResourceBundleThemeSource INFO [http-8080-Processor23] - Pre-instantiating singletons in factory [org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping,DoSomethingController]; root of BeanFactory hierarchy] INFO [http-8080-Processor23] - Creating shared instance of singleton bean 'org.springframework.web.servlet.handler.SimpleUrlHandlerMapping' INFO [http-8080-Processor23] - Creating shared instance of singleton bean 'DoSomethingController' INFO [http-8080-Processor23] - Using context class [org.springframework.web.context.support.XmlWebApplicationContext] for servlet 'spring-mvc-02' INFO [http-8080-Processor23] - Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided INFO [http-8080-Processor23] - Unable to locate LocaleResolver with name 'localeResolver': using default [org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@1f31ad9] INFO [http-8080-Processor23] - Unable to locate ThemeResolver with name 'themeResolver': using default [org.springframework.web.servlet.theme.FixedThemeResolver@1c0cd80] INFO [http-8080-Processor23] - No HandlerAdapters found in servlet 'spring-mvc-02': using default INFO [http-8080-Processor23] - No ViewResolvers found in servlet 'spring-mvc-02': using default INFO [http-8080-Processor23] - FrameworkServlet 'spring-mvc-02': initialization completed in 1592 ms INFO [http-8080-Processor23] - Servlet 'spring-mvc-02' configured successfully

Avec un navigateur, nous demandons l'URL [http://localhost:8080/spring-mvc-02/dosomething.html] :

Expliquons ce qui s'est pass : 1. 2. 3. le fichier [web.xml] de l'application [spring-mvc-02] a t consult. Ce fichier indique que les URL *.html doivent tre traites par la servlet de nom [spring-mvc-02] et instancie par [DispatcherServlet]. le contrleur [DispatcherServlet] prend la main et exploite le contenu du fichier [spring-mvc-02-servlet.html]. Il voit que l'URL [/dosomething.html] doit tre traite par le contrleur [istia.st.springmvc.exemples.web.DoSomething]. Celui a t instanci au dmarrage de l'application. [DispatcherServlet] appelle la mthode [handleRequest] de ce contrleur. la mthode [handleRequest] du contrleur [istia.st.springmvc.exemples.web.DoSomething] envoie le flux HTML que nous voyons ci-dessus et rend le pointeur [null] au contrleur principal [DispatcherServlet]. Celui-ci comprend que la rponse a t envoye. Le cycle [demande client - rponse serveur] est termin.

Voil... Notre premire application Spring a t crite. Les briques de base de toute application Spring MVC commencent se mettre en place.

6.3

La stratgie BeanNameUrlHandlerMapping21/70

springmvc - partie1, [email protected]

Le projet Eclipse de l'exemple est le suivant :

L'application est dfinie par le fichier [web.xml] suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. spring-mvc-03 org.springframework.web.servlet.DispatcherServlet spring-mvc-03 *.html

La servlet de l'application s'appelle [spring-mvc-03] et donc son fichier de configuration doit s'appeler [spring-mvc-03-servlet.xml]. Ce fichier est prsent sur la copie d'cran ci-dessus. Son contenu est le suivant :1. 2. 3. 4. 5. 6. 7.

Il n'y a plus de stratgies de rsolution. On sait qu'alors c'est la stratgie [BeanNameUrlHandlerMapping] qui est utilise. C'est dire qu'une url [/URL] est traite par le bean contrleur d'attribut name [/URL]. Dans une balise , l'attribut name sert galement identifier un bean comme le fait l'attribut id. Seulement l'attribut id a des rgles de syntaxe qui ne permettent pas d'crire [id= "/dosomething.html "], cause du signe /. On utilise donc l'attribut name. Ci-dessus, l'url [/dosomething.html] sera traite par le contrleur d'attribut name [/dosomething.html] et donc par la classe [istia.st.springmvc.exemples.web.DoSomething]. Cette classe est celle de l'application prcdente. Nous ne changeons rien sauf le titre de la page HTML que nous changeons en Spring-MVC-03. Nous sommes prts pour le test. Nous lanons Tomcat si besoin est, puis demandons l'URL [http://localhost:8080/spring-mvc03/dosomething.html] :

Expliquons ce qui s'est pass : 1. le fichier [web.xml] de l'application [spring-mvc-03] a t consult. Ce fichier indique que les URL *.html doivent tre traites par la servlet de nom [spring-mvc-03] dont la classe associe est [DispatcherServlet]. 22/70

springmvc - partie1, [email protected]

2.

3.

le contrleur [DispatcherServlet] prend la main et exploite le contenu du fichier [spring-mvc-03-servlet.html]. Sans stratgie de rsolution dfinie [spring-mvc-03-servlet.html], il utilise la stratgie par dfaut [BeanNameUrlhandlerMapping]. Il cherche donc un contrleur d'id [/dosomething.html]. Il le trouve. [DispatcherServlet] appelle la mthode [handleRequest] de ce contrleur. la mthode [handleRequest] du contrleur [istia.st.springmvc.exemples.web.DoSomething] envoie le flux HTML que nous voyons ci-dessus et rend le pointeur [null] au contrleur principal [DispatcherServlet]. Celui-ci comprend que la rponse a t envoye. Le cycle [demande client - rponse serveur] est termin.

6.4

La stratgie SimpleUrlHandlerMapping avec liaisons externalises

Le projet Eclipse de l'exemple est le suivant :

L'application est dfinie par un fichier [web.xml] analogue au prcdent, mais dsormais la servlet s'appelle [spring-mvc-04]. Le fichier de configuration [spring-mvc-04-servlet.xml] est le suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. mappings.properties

la ligne 15 indique que nous sommes revenus la stratgie de rsolution [ SimpleUrlHandlerMapping ]. Cependant, les liens URL Controller ne sont pas dans le mme fichier mais dans le fichier de proprits indiqu ligne 10.

Le fichier [mappings.properties] se trouve la racine du dossier de l'application (cf copie d'cran) et son contenu est le suivant :## mappings de l'application spring-mvc-04 /dosomething.html=DoSomethingController

Ce fichier a des lignes de la forme : Url=Controller, qui associent un objet Controller une Url. On ne fait ici qu'externaliser des informations qui dans l'application [spring-mvc-02] taient dans le fichier [spring-mvc-02-servlet.xml]. En-dehors de ce point, les applications spring-mvc-02 et spring-mvc-04 sont identiques. Pour le test, nous demandons l'URL [http://localhost:8080/spring-mvc-04/dosomething.html] :

springmvc - partie1, [email protected]

23/70

7 Accs au contexte d'une application Spring MVC7.1 Exemple 1

Reprenons l'architecture d'une application Spring MVC : Couche Interface Utilisateur[ui] utilisateur1

DispatcherServlet2 3 4

Couche mtier [metier]

Couche d'accs aux donnes [dao]

Donnes

Controller5

Modle Map6

View7

Pour traiter la demande d'un client, l'objet [Controller] a besoin d'informations de diffrente porte et situs pour cette raison dans des conteneurs diffrents :

le contexte de l'application (javax.servlet.ServletContext) contient les objets qui sont partags entre tous les utilisateurs. Parce qu'ils sont partags entre tous les utilisateurs, ils sont le plus souvent en lecture seule. Leur dure de vie est celle de l'application. la session (javax.servlet.http.Session) contient les objets appartenant un utilisateur donn. Celui fait au serveur des requtes successives qui sont considres chaque fois par le serveur comme une nouvelle requte. Le mcanisme de la session permet d'avoir une mmoire entre les diffrentes requtes d'un mme utilisateur. le contexte de la requte (javax.servlet.http.HttpServletRequest) contient les objets d'une requte donne d'un utilisateur donn. L'objet [HttpRequest] qui l'encapsule peut tre trait par une chane de servlets. Le contexte de la requte permet une servlet de passer des informations la servlet suivante de la chane.

Lors de son dmarrage, une application web a besoin de construire son environnement d'excution. Il s'agit d'une phase d'initialisation qui aboutit mettre dans le contexte de l'application, des objets partags par tous les utilisateurs, par exemple cidessus, les objets instanciant les couches [mtier] et [dao]. O peut se faire cette initialisation ? Lorsque la servlet d'une application web est charge par le conteneur de servlets, sa mthode [init] est excute. C'est dans la spcification des servlets. Ce sera donc le cas galement pour la servlet [DispatcherServlet] d'une application Spring MVC. Nous n'avons pas la matrise du contrleur [DispatcherServlet]. Pour accder sa mthode [init] qui nous permettrait d'initialiser l'application, nous sommes amens driver la classe [DispatcherServlet] afin de redfinir sa mthode [init]. C'est ce que montre l'exemple que nous dcrivons maintenant. Le projet Eclipse est le suivant :

springmvc - partie1, [email protected]

24/70

L'application web [spring-mvc-06] est configure par le fichier [web.xml] suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. spring-mvc-06 istia.st.springmvc.exemples.web.MyServlet groupe Paul,Mlanie,Jacques spring-mvc-06 *.html

Ce fichier [web.xml] ne diffre des prcdents que par sa ligne 11. Le contrleur C du MVC n'est plus de type [DispatcherServlet] comme jusqu' maintenant mais de type [ istia.st.springmvc.exemples.web.MyServlet ], un type propritaire dfini dans [WEBINF/src] (cf copie d'cran). Pour ne rien perdre des capacits de [DispatcherServlet], la classe [MyServlet] en drive. Nous drivons [DispacherServlet] afin d'avoir accs aux paramtres d'initialisation de l'application dfinis lignes 12-15 ci-dessus. Il s'agit de dfinir un groupe de personnes. La ligne de la classe [DispatcherServlet] est la suivante :

La classe [DispatcherServlet] ne dfinit pas elle-mme de mthode [init]. Dans la ligne ci-dessus, la mthode [init] apparat tout d'abord dans [GenericServlet]. Les classes drives [HttpServlet, HttpServletBean] la redfinissent. Seulement la classe [ HttpServletBean ] la redfinit en la dclarant [final], ce qui interdit qu'elle soit redfinie de nouveau dans les classes drives de [HttpServletBean]. Nous ne pouvons donc utiliser la mthode [init] pour initialiser l'application Spring MVC. En consultant la dfinition de la classe [DispatcherServlet], on trouve une mthode [initFrameworkServlet] qui peut tre utilise pour le faire :

springmvc - partie1, [email protected]

25/70

Lorsque cette mthode est appele, le contexte de l'application [applicationContext.xml] a dj t exploit. Par ailleurs, la mthode instancie diffrents objets ncessaires l'application, notamment sa stratgie de rsolution des URL (HandlerMapping). En redfinissant cette mthode, on peut ajouter de plus des initialisations " propritaires ". La classe [MyServlet], que nous allons utiliser comme contrleur principal de l'application, et drive de la classe [DispatcherServlet] est la suivante :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. package istia.st.springmvc.exemples.web; import javax.servlet.ServletException; import org.springframework.beans.BeansException; import org.springframework.web.servlet.DispatcherServlet; public class MyServlet extends DispatcherServlet { public void initFrameworkServlet() throws BeansException, ServletException { // init parent super.initFrameworkServlet(); // on rcupre le paramtre de [web.xml] String[] groupe = (this.getServletConfig().getInitParameter("groupe")) .split(","); // on met le tableau dans le contexte de l'application this.getServletContext().setAttribute("groupe", groupe); }

}

ligne 8 : la classe drive de [DispatcherServlet] lignes 10-18 : redfinissent la mthode [ initFrameworkServlet ] de la classe [DispatcherServlet] ligne 12 : nous laissons la mthode [ initFrameworkServlet ] de la classe parent faire son travail lignes 13-17 : nous ajoutons nos initialisations propritaires ligne 14 : on rcupre dans [web.xml], le paramtre (init-param) qui porte le nom " groupe ". On obtient une chane de caractres constitue de sous-chanes spares par une virgule. Ces sous-chanes sont rcupres dans le tableau groupe. ligne 17 : le tableau groupe est mis dans le contexte de l'application afin qu'il soit visible par tous les utilisateurs de l'application.

Le fichier [web.xml] dfinissait une servlet appele [servlet-mvc-06]. Le fichier de configuration [servlet-mvc-06-servlet.xml] de celle-ci est le suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. DoSomethingController

Il n'y a rien ici qu'on ne connaisse dj. L'url [/dosomething.html] va tre traite par le contrleur [ istia.st.springmvc.exemples.web.DoSomething ]. Celui-ci est dans [WEB-INF/src] (cf copie d'cran). Le code du contrleur [DoSomething] est le suivant :springmvc - partie1, [email protected]

26/70

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43.

package istia.st.springmvc.exemples.web; import java.io.PrintWriter; import java.util.Date; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class DoSomething implements Controller { // gestion de la requte public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { // dbut long dbut = new Date().getTime(); // attente Thread.sleep(10); // on code en dur response.setContentType("text/html"); PrintWriter out = response.getWriter(); // on prpare le code HTML String Html = "Spring-MVC-06" + ""; // on parcourt la liste des membres du groupe String[] groupe = (String[]) request.getSession().getServletContext().getAttribute("groupe"); for (int i = 0; i < groupe.length; i++) { Html += groupe[i] + "
\n"; } // fin long fin = new Date().getTime(); // dure long dure = fin - dbut; Html += "
DoSomething excut en " + dure + " ms..."; // on envoie le flux HTML out.println(Html); // pas de ModelAndView return null; } }

ligne 12 : [DoSomething] implmente l'interface [Controller]. lignes 15-42 : redfinissent la mthode [HandleRequest] qui sera appele par le contrleur [DispatcherServlet] ligne 18 : on note l'heure de dbut du traitement ligne 20 : on attend 10 ms ligne 22 : on indique que la rponse sera un flux HTML lignes 23 : le flux d'criture vers le client lignes 25 - 26 : dbut du flux HTML ligne 28 : on rcupre l'attribut " groupe " dans le contexte de l'application. lignes 29-31 : les membres du groupe sont crits dans le flux HTML ligne 33 : on note l'heure de fin du traitement ligne 35 : la dure du traitement ligne 36 : la dure est crite dans le flux HTML ligne 38 : envoi du flux HTML au client ligne 40 : on rend le pointeur [null] [DispatcherServlet] pour lui indiquer que la rponse a t envoye.

Nous sommes prts pour un test. Aprs avoir lanc Tomcat, nous demandons l'url [http://localhost:8080/spring-mvc06/dosomething.html] :

springmvc - partie1, [email protected]

27/70

7.2

Exemple 2

Reprenons l'architecture d'une application Spring MVC : Couche Interface Utilisateur[ui] utilisateur1

DispatcherServlet2 3 4

Couche mtier [metier]

Couche d'accs aux donnes [dao]

Donnes

Controller5

Modle Map6

View7

Les diffrents objets [Controller] qui traitent les demandes des utilisateurs ont normalement besoin de communiquer avec la couche mtier (opration 3 ci-dessus). Celle-ci est accde en gnral via une ou plusieurs interfaces. L'instanciation de celles-ci peut tre faite par configuration avec Spring IoC. Les instances cres doivent tre places dans le contexte de l'application car ce sont des singletons partags par tous les utilisateurs. Le fichier [web.xml] utilis prcdemment pour crer le contexte de l'application n'est pas un fichier Spring et ne peut donc tre utilis pour instancier les couches [mtier] et [dao] avec Spring IoC. Spring MVC propose donc une autre approche. Nous avons vu que les applications prcdentes taient associes une servlet S et un fichier de configuration [S-servlet.xml]. On pourrait vouloir instancier la couche [mtier] dans ce dernier fichier. Cependant, une application Spring MVC peut utiliser diverses servlets S1, S2, ... donnant naissance des fichiers [S1-servlet.xml, S2-servlet.xml, ...]. Afin que les singletons des couches [mtier] et [dao] soient accessibles aux diffrentes servlets, on dfinit ces singletons dans un fichier de configuration Spring " parent " des fichiers de servlets [Si-servlet.xml]. Spring permet en effet de crer une relation parent - fils entre deux fichiers de configuration. Les beans dfinis dans le fichier parent sont automatiquement connus du fichier fils. Dans une application Spring MVC, le fichier [applicationContext.xml] joue le rle de " parent " des fichiers [S1-servlet.xml, S2servlet.xml, ...] de dfinition des servlets de l'application. C'est donc dans ce fichier qu'on placera en gnral la configuration des couches [mtier] et [dao] de l'application. Le fichier [applicationContext.xml] doit tre plac dans le dossier [WEB-INF]. Pour que le fichier [applicationContext.xml] soit reconnu et exploit, l'application Spring MVC doit charger une classe spciale de type [org.springframework.web.context.ContextLoaderListener]. Cette classe va exploiter le fichier [applicationContext.xml] et instancier les beans qui y sont dfinis. Parce que ceux-ci doivent tre instancis avant ceux dfinis par les fichiers [Si-servlet.xml], la classe [org.springframework.web.context.ContextLoaderListener] doit tre instancie avant la classe [DispatcherServlet] qui elle, va exploiter les fichiers [Si-servlet.xml]. Cela peut tre obtenu au moyen d'un fichier [web.xml] analogue au suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. org.springframework.web.context.ContextLoaderListener spring-mvc-05 org.springframework.web.servlet.DispatcherServlet spring-mvc-05 *.html

Ce fichier est semblable aux prcdents sauf en ce qui concerne les lignes 8-11. Ces lignes dfinissent un " listener " d'application qui sera instanci ds le dmarrage de l'application et avant les classes associes aux servlets. Ceci nous assure que les beans dfinis dans [applicationContext.xml] seront instancis avant ceux dfinis dans les fichiers [Si-servlet.xml].springmvc - partie1, [email protected]

28/70

Pour illustrer le rle du fichier [applicationContext.xml], nous utiliserons le projet Eclipse suivant :

On notera la prsence du fichier [applicationContext.xml] dans [WEB-INF]. Le fichier [web.xml] de l'application est celui qui vient d'tre dcrit. Le fichier [applicationContext.xml] est, lui, le suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. Paul Mlanie Jacques

Il dfinit un bean " groupe ", objet de type [istia.st.springmvc.exemples.web.Groupe]. Cette classe, dfinie dans [WEB-INF/src] (cf copie d'cran) est dfinie comme suit :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. package istia.st.springmvc.exemples.web; import java.util.ArrayList; public class Groupe { private ArrayList membres; public ArrayList getMembres() { return membres; } public void setMembres(ArrayList membres) { this.membres = membres; }

}

ligne 7 : un champ priv de type [ArrayList] lignes 9 - 15 : getter / setter associs

Le fichier [applicationContext.xml] dfinit un bean d'id " groupe " qui est une instance de la classe [Groupe] avec pour lments du champ priv [membres], les chanes de caractres : " Paul ", " Mlanie ", " Jacques ". Le fichier de configuration [servlet-mvc-05-servlet.xml] de la servlet [spring-mvc-05] est le suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. DoSomethingController

springmvc - partie1, [email protected]

29/70

10. 11. 12. 13. 15. 16. 17. 18. 19.

lignes 5-11 : dfinissent [SimpleUrlHandlerMapping] comme stratgie de rsolution des URL lignes 13-18 : dfinissent le contrleur charg de traiter l'url [/dosomething.html]. Ce contrleur est une instance de la classe [ istia.st.springmvc.exemples.web.DoSomething ]. On voit (lignes 15-17) que ce contrleur a une proprit nomme " groupe " qui reoit pour valeur (ligne 16), la valeur d'un bean d'id " groupe ". Il s'agit du bean instanci par [applicationContext.xml]. La relation parent - fils qui lie les fichiers [applicationContext.xml] et [servlet-mvc-05servlet.xml] fait que le bean " groupe " dfini dans [applicationContext.xml] peut tre utilis dans [servlet-mvc-05servlet.xml].

Il ne nous reste plus qu' prsenter le contrleur [ istia.st.springmvc.exemples.web.DoSomething ] :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. package istia.st.springmvc.exemples.web; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Date; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class DoSomething implements Controller { // un groupe de personnes fourni par le contexte de l'application private Groupe groupe; public Groupe getGroupe() { return groupe; } public void setGroupe(Groupe groupe) { this.groupe = groupe; } // gestion de la requte public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { // dbut long dbut = new Date().getTime(); // attente Thread.sleep(10); // on code en dur response.setContentType("text/html"); PrintWriter out = response.getWriter(); // on prpare le code HTML String Html="Spring-MVC-05"+ ""; // on parcourt la liste des membres du groupe ArrayList membres=groupe.getMembres(); for(int i=0;i