| Ce site met a disposition le build journalier de la traduction francaise du Maven: The Definitive Guide Consultez : | ![]() |
L'application Web est définie dans le module simple-webapp. Ce projet va définir deux contrôleurs Spring MVC :
WeatherController et HistoryController.
Ces deux contrôleurs vont référencer les composants des modules simple-weather et simple-persist.
Le conteneur Spring est configuré dans le fichier web.xml de l'application web, celui-ci réfère le fichier
applicationContext-weather.xml du module simple-weather et le fichier
applicationContext-persist.xml du module simple-persist.
L'architecture des composants de cette application web simple est montrée sur la Figure 7.3, « Contrôleurs Spring MVC référençant les modules simple-weather et simple-persist. ».
Le POM du module simple-webapp est affiché dans l'Exemple 7.12, « POM du module simple-webapp ».
Exemple 7.12. POM du module simple-webapp
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sonatype.mavenbook.multispring</groupId>
<artifactId>simple-parent</artifactId>
<version>1.0</version>
</parent>
<artifactId>simple-webapp</artifactId>
<packaging>war</packaging>
<name>Simple Web Application</name>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sonatype.mavenbook.multispring</groupId>
<artifactId>simple-weather</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.sonatype.mavenbook.multispring</groupId>
<artifactId>simple-persist</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.5</version>
</dependency>
</dependencies>
<build>
<finalName>simple-webapp</finalName>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<dependencies>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<components>
<component>
<name>hbm2ddl</name>
<implementation>annotationconfiguration</implementation>
</component>
</components>
</configuration>
<dependencies>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Au fur et à mesure que nous avançons dans ce livre, les exemples deviennent de plus en
plus substantiels. Vous avez d'ailleurs probablement noté que le fichier
pom.xml commence à devenir volumineux.
Dans ce POM, nous configurons quatre dépendances et deux plugins.
Regardons ce POM en détail et étendons-nous sur certains des points de configuration importants :
|
Ce projet |
|
|
Le plugin Maven Jetty est utilisé de la manière la plus simple qui soit dans ce projet.
Nous ajoutons simplement la balise |
|
|
Dans notre configuration de build, nous allons configurer le plugin Maven Hibernate3 pour qu'il utilise une instance de la
base de données embarquée HSQLDB.
Pour que le plugin Maven Hibernate3 arrive à se connecter à la base, il doit référencer le driver JDBC d'HSQLDB dans
son classpath.
Pour rendre cette dépendance disponible au plugin, nous ajoutons sa déclaration directement dans la déclaration du
|
|
|
C'est à partir de l'utilisation du plugin Maven Hibernate3 que ce POM devient le plus intéressant.
Dans la section suivante, nous allons exécuter le goal |
|
|
Le plugin Maven Hibernate3 dispose de plusieurs moyens pour récupérer le mapping Hibernate en fonction du cas d'utilisation.
Si vous utilisez des fichiers XML pour le Mapping Hibernate ( |
Une erreur classique consiste à utiliser la balise extensions de la configuration pour ajouter des dépendances nécessaires à un plugin.
Il est fortement découragé de procéder de la sorte car les extensions peuvent polluer le classpath de votre projet,
et provoquer des effets de bord désagréables.
De plus, le comportement des extensions a été modifié depuis la version 2.1 de Maven.
Le seul usage correct de la balise extensions est l'ajout d'implémentations complémentaires.
Regardons maintenant les deux contrôleurs Spring MVC, chacun d'entre eux référence des beans déclarés dans les simple-weather et simple-persist.
Exemple 7.13. WeatherController du module simple-webapp
package org.sonatype.mavenbook.web;
import org.sonatype.mavenbook.weather.model.Weather;
import org.sonatype.mavenbook.weather.persist.WeatherDAO;
import org.sonatype.mavenbook.weather.WeatherService;
import javax.servlet.http.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class WeatherController implements Controller {
private WeatherService weatherService;
private WeatherDAO weatherDAO;
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String zip = request.getParameter("zip");
Weather weather = weatherService.retrieveForecast(zip);
weatherDAO.save(weather);
return new ModelAndView("weather", "weather", weather);
}
public WeatherService getWeatherService() {
return weatherService;
}
public void setWeatherService(WeatherService weatherService) {
this.weatherService = weatherService;
}
public WeatherDAO getWeatherDAO() {
return weatherDAO;
}
public void setWeatherDAO(WeatherDAO weatherDAO) {
this.weatherDAO = weatherDAO;
}
}
WeatherController implémente l'interface Controller qui assure la présence d'une méthode
handleRequest() dont la signature est montrée dans cet exemple.
Si vous regardez le corps de cette méthode, vous constaterez que celle-ci invoque la méthode retrieveForecast() du service weatherService.
Contrairement au chapitre précédent, dans lequel une servlet instancie la classe WeatherService,
le WeatherController est un bean contenant une propriété weatherService.
Le conteneur Spring IoC a la responsabilité de charger le service weatherService dans le contrôleur.
Notez également que nous n'utilisons pas le WeatherFormatter dans ce contrôleur.
Au lieu de cela, nous passons l'objet Weather retourné par la méthode retrieveForecast() au constructeur de la classe ModelAndView.
Cette classe ModelAndView est utilisée pour effectuer le rendu du template Velocity. Ce template disposera d'une référence sur la variable ${weather} contenant ce même objet.
Le template weather.vm se trouve dans le répertoire src/main/webapp/WEB-INF/vm, celui-ci est affiché dans l'Exemple 7.14, « Modèle weather.vm interprété par le WeatherController ».
Dans ce WeatherController, avant d'effectuer le rendu des prévisions météo, nous passons l'objet Weather
retourné par le service WeatherService à la méthode save() de la classe WeatherDAO.
Cet objet est sauvegardé par Hibernate en base de données.
Plus tard, dans le contrôleur HistoryController, nous verrons comment récupérer l'historique de ces prévisions météorologiques.
Exemple 7.14. Modèle weather.vm interprété par le WeatherController
<b>Current Weather Conditions for:
${weather.location.city}, ${weather.location.region},
${weather.location.country}</b><br/>
<ul>
<li>Temperature: ${weather.condition.temp}</li>
<li>Condition: ${weather.condition.text}</li>
<li>Humidity: ${weather.atmosphere.humidity}</li>
<li>Wind Chill: ${weather.wind.chill}</li>
<li>Date: ${weather.date}</li>
</ul>
La syntaxe de ce modèle Velocity est rapide à expliquer, les variables sont référencées
par l'intermédiaire de la notation ${}. L'expression entre les accolades fait
référence à une propriété, ou à une propriété d'une propriété de la
variable weather passée à ce modèle par
le WeatherController.
Le contrôleur HistoryController est utilisé pour récupérer la liste
des prévisions météorologiques les plus récentes parmi celles demandées par le WeatherController.
Chaque fois que nous récupérons une prévision dans le WeatherController, celui-ci enregistre l'objet Weather récupéré dans la base de données via le WeatherDAO.
Ce DAO utilise ensuite Hibernate pour transformer l'objet Weather en une série de lignes dans un ensemble de tables de la base de données.
Le contrôleur HistoryController est affiché dans l'Exemple 7.15, « HistoryController du module simple-web ».
Exemple 7.15. HistoryController du module simple-web
package org.sonatype.mavenbook.web;
import java.util.*;
import javax.servlet.http.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import org.sonatype.mavenbook.weather.model.*;
import org.sonatype.mavenbook.weather.persist.*;
public class HistoryController implements Controller {
private LocationDAO locationDAO;
private WeatherDAO weatherDAO;
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String zip = request.getParameter("zip");
Location location = locationDAO.findByZip(zip);
List<Weather> weathers = weatherDAO.recentForLocation( location );
Map<String,Object> model = new HashMap<String,Object>();
model.put( "location", location );
model.put( "weathers", weathers );
return new ModelAndView("history", model);
}
public WeatherDAO getWeatherDAO() {
return weatherDAO;
}
public void setWeatherDAO(WeatherDAO weatherDAO) {
this.weatherDAO = weatherDAO;
}
public LocationDAO getLocationDAO() {
return locationDAO;
}
public void setLocationDAO(LocationDAO locationDAO) {
this.locationDAO = locationDAO;
}
}
Le contrôleur HistoryController est chargé avec les deux DAOs
du module simple-persist.
Les instances de ces deux DAOs sont portées par les propriétés WeatherDAO et LocationDAO.
Le but de l'HistoryController est de récupérer une List d'objets Weather en fonction du paramètre zip.
Quand le WeatherDAO enregistre un objet Weather dans la base de données,
il ne se contente pas de stocker le code postal, il enregistre un objet Location qui est lié à l'objet Weather du module simple-model.
Pour récupérer la List des objets Weather, l'HistoryController commence par récupérer
l'objet Location qui correspond au paramètre zip représentant le code postal.
Pour cela, on invoque la méthode findByZip() du DAO LocationDAO.
Une fois cet objet Location récupéré, l'HistoryController essayera de récupérer les objets Weather les plus récents associés à cette Location.
Une fois la List<Weather> récupérée, une HashMap est créée contenant les deux variables
du modèle Velocity history.vm de l'Exemple 7.16, « Modèle history.vm utilisé par l'HistoryController ».
Exemple 7.16. Modèle history.vm utilisé par l'HistoryController
<b>
Weather History for: ${location.city}, ${location.region}, ${location.country}
</b>
<br/>
#foreach( $weather in $weathers )
<ul>
<li>Temperature: $weather.condition.temp</li>
<li>Condition: $weather.condition.text</li>
<li>Humidity: $weather.atmosphere.humidity</li>
<li>Wind Chill: $weather.wind.chill</li>
<li>Date: $weather.date</li>
</ul>
#end
Le modèle history.vm du dossier src/main/webapp/WEB-INF/vm référence la
variable location pour afficher les prévisions météo provenant du WeatherDAO.
Ce template utilise une structure de contrôle Velocity, #foreach, pour itérer sur chaque élément de la variable weathers.
Chaque élément de la liste weathers est assigné à une variable nommée weather.
Le cœur de la boucle, entre #foreach et #end, permet d'afficher les informations de chaque prévision.
Nous venons de voir les implémentations de nos deux Controller.
Nous venons également de voir comment ils référencent les beans des modules simple-weather et simple-persist.
Ces Controller répondent aux requêtes HTTP par l'intermédiaire de mystérieux systèmes qui savent comment effectuer le rendu de templates Velocity.
Toute la magie est configurée dans l'ApplicationContext Spring du fichier src/main/webapp/WEB-INF/weather-servlet.xml.
Ce XML configure les contrôleurs et référence d'autres beans managés par Spring.
Il est chargé par un ServletContextListener qui est configuré pour charger également les fichiers applicationContext-weather.xml et applicationContext-persist.xml à partir du classpath.
Regardons de plus près le fichier weather-servlet.xml de l'Exemple 7.17, « Configuration des contrôleurs Spring du fichier weather-servlet.xml ».
Exemple 7.17. Configuration des contrôleurs Spring du fichier weather-servlet.xml
<beans>
<bean id="weatherController"
class="org.sonatype.mavenbook.web.WeatherController">
<property name="weatherService" ref="weatherService"/>
<property name="weatherDAO" ref="weatherDAO"/>
</bean>
<bean id="historyController"
class="org.sonatype.mavenbook.web.HistoryController">
<property name="weatherDAO" ref="weatherDAO"/>
<property name="locationDAO" ref="locationDAO"/>
</bean>
<!-- you can have more than one handler defined -->
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/weather.x">
<ref bean="weatherController" />
</entry>
<entry key="/history.x">
<ref bean="historyController" />
</entry>
</map>
</property>
</bean>
<bean id="velocityConfig"
class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/vm/"/>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".vm"/>
<property name="exposeSpringMacroHelpers" value="true"/>
</bean>
</beans>
|
Le fichier |
|
|
Le bean |
|
|
Comme nous utilisons le moteur de template Velocity, nous avons besoin de fournir
quelques options de configuration spécifiques. Dans le bean |
|
|
Enfin, le |
Pour finir, le projet simple-webapp possède un fichier web.xml qui fournit la configuration de base à l'application web.
Le fichier web.xml est affiché dans l'Exemple 7.18, « web.xml du module simple-webapp ».
Exemple 7.18. web.xml du module simple-webapp
<web-app id="simple-webapp" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Simple Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext-weather.xml
classpath:applicationContext-persist.xml
</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>weather</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>weather</servlet-name>
<url-pattern>*.x</url-pattern>
</servlet-mapping>
</web-app>
|
Voici un peu de magie qui nous permet la réutilisation des fichiers |
|
|
Le paramètre |
|
|
Cela assure que le système Log4J est configuré lors du démarrage de l'application.
Il est important de mettre ce |
|
|
Le |
|
|
Nous définissons un |
|
|
Toutes les requêtes terminant par |