该web应用中项目simple-webapp
中定义。这个简单web应用项目将会定义两个Spring
MVC控制器:WeatherController
和HistoryController
。两者都会引用simple-weather
和simple-persist
中定义的组件。Spring容器在应用程序的web.xml
中配置,该文件引用了simple-weather
中的applicationContext-weather.xml
文件和simple-persist
中的applicationContext-persist.xml
文件。这个简单web应用的组件架构如Figure 7.3, “Spring MVC 控制器引用simple-weather和simple-persist中的组件”显示。
simple-webapp
的POM如Example 7.12, “simple-webapp的POM”显示。
Example 7.12. simple-webapp的POM
<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.ch07</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>org.apache.geronimo.specs</groupId> <artifactId>geronimo-servlet_2.4_spec</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-weather</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.sonatype.mavenbook.ch07</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>
随着书本的推进以及样例变得越来越大,你会注意到pom.xml
开始呈现得有一些笨重,这里我们配置了四个依赖和两个插件。让我们详细查看一下这个POM然后详述其中一些重要的配置点:
|
|
Maven Jetty插件以最简单的方式加入到该项目,我们只是添加一个引用了对应 |
|
在我们的build配置中,我们还配置了Maven Hibernate3插件来访问内嵌的HSQLDB实例。要让Maven
Hibernate3插件能成功的使用JDBC连接该数据库,该插件需要引用classpath中的HSQLDB
JDBC驱动。为了让这个插件能使用该依赖,我们在 |
|
这个Maven Hibernate插件正是该POM变得有趣的地方。在下一节,我们将会运行 |
|
Maven
Hibernate3插件有不同的方法获取Hibernate映射信息,这些信息适用于Hibernate3插件的不同用例。如果你正在使用Hibernate映射XML文件( |
Note
一个常见的错误是使用extensions
配置添加一个插件需要的依赖。这是强烈不推荐的因为extensions会在你的项目中造成classpath污染,以及其它令人讨厌的副作用。此外,extensions行为正在2.1中被重做,最后你都会要改变它。唯一的对extensions
的正常使用是定义新的wagon实现。
接下来,我们将我们的注意力转移到两个处理所有请求的Spring
MVC控制器。两个控制器都引用了在simple-weather
和simple-persist
中定义的bean。
Example 7.13. simple-webapp WeatherController
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
实现了MVC
Controller接口,该接口强制要求实现如上例中的handleRequest()
方法。如果你看一下该方法的主要内容,你会看到它调用了weatherService
实例变量的retrieveForecast()
方法。不像前面的章节中,有一个Servlet来初始化WeatherService
类,WeatherController
是一个带有weatherService
属性的bean。Spring
Ioc容器会负责将weatherService
组件注入到控制器。同时也注意我们并没有在这个控制器实现中使用WeatherFormatter
;而是将retrieveForecast()
返回的Weather
对象传递给了ModelAndView
的构造函数。ModelAndView
类将被用来呈现Velocity模板,这个模板有对${weather}
变量的引用。weather.vm
模板存储在src/main/webapp/WEB-INF/vm
,如???所示。
在这个WeatherController
中,在我们呈现天气预报输出之前,我们将WeatherService
返回的Weather
对象传递给WeatherDAO
的save()
方法。这里我们使用Hibernate将Weather
对象保存到HSQLDB数据库。之后,在HistoryController
中,我们将看如何能够获取由WeatherController
保存的天气预报历史信息。
Example 7.14. 由 WeatherController 呈现的 weather.vm 模板
<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>
Velocity模板的语法简单易懂,变量通过${}
标记引用。大括弧里面的表达式引用weather
变量的一个属性,或者该变量属性的属性。weather
变量是由WeatherController
传递给该模板的。
HistoryController
用来获取那些已经由WeatherController
请求过的最近历史天气预报信息。任何时候当我们从WeatherController
获取预报的时候,该控制器通过WeatherDAO
将Weather
对象保存至数据库。WeatherDAO
然后使用Hibernate将Weather
对象剖析成一组相关数据库表的记录行。HistoryController
如Example 7.15, “simple-web 的 HistoryController”所示。
Example 7.15. simple-web 的 HistoryController
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; } }
HistoryController
被注入了两个定义在simple-persist
中的DAO对象。这两个DAO是HistoryController
的bean属性:WeatherDAO
和LocationDAO
。HistoryController
的目标是获取一个与zip
参数对应的Weather
对象列表。当WeatherDAO
将Weather
对象保存至数据库,它不只是保存邮编,它保存了一个与simple-model
中Weather
对象相关的Location
对象。为了获取一个Weather
对象的List
,首先通过调用LocationDAO
的findByZip()
方法,获取与zip
参数对应的Location
对象。
一旦获得了Location
对象,HistoryController
之后就会尝试获取与给定的Location
相匹配的Weather
对象。在获取了List<Weather>
之后,一个HashMap
被创建以存储两个变量,供如???中显示的history.vm
Velocity模板使用。
Example 7.16. 由 HistoryController 呈现的 history.vm
<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
src/main/webapp/WEB-INF/vm
中的history.vm
模板引用了location
变量以输出天气预报位置的相关信息。该模板使用了一个Velocity的控制结构,为了循环weathers
变量中的每个元素。weathers
中的每个元素被赋给了一个名为weather
的变量,#foreach
和#end
中间的模板用来呈现每个预报输出。
你已经看到了这些Controller
实现,以及它们如何引用定义在simple-weather
和simple-persist
中的其它bean,它们相应HTTP请求,让那些知道如何呈现Velocity模板的神奇的模板系统来控制输出。所有的魔法都在位于src/main/webapp/WEB-INF/weather-servlet.xml
的Spring
appliction
context中配置。这个XML文件配置了控制器并引用了其它Spring管理的bean,它由ServletContextListener
载入,后者同时也被配置从classpath中载入了applicationContext-weather.xml
和applicationContext-persist.xml
。让我们仔细看一下???中展示的weather-servlet.xml
。
Example 7.17. weather-servlet.xml 中的 Spring 控制器配置
<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>
|
|
|
|
由于我们正使用Velocity模板引擎,我们需要传入一些配置选项。在 |
|
最后, |
最后,simple-webapp
项目中有一个web.xml
,提供了这个web应用的基本配置。web.xml
文件如???所示:
Example 7.18. simple-webapp 的 web.xml
<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>
这里有一些魔法能让我们在项目中重用 |
|
|
|
这里确保当web应用启动的时候Log4J系统被配置。将 |
|
|
|
我们定义一个名为 |
|
所有以 |