《Maven权威指南》学习笔记十八_多模块企业级项目

1, Demon见http://www.sonatype.com/book/mvn-examples-1.0.zipch-multi-spring 目录。

2, 架构示例图(在Simple Parent下构建5个工程): 《Maven权威指南》学习笔记十八_多模块企业级项目_第1张图片

箭头指明POM继承关系。

这里需要明白一点,POM继承关系不决定父子模块的关系,个人认为POM继承和父子模块继承设计成一致也是出于简化方便的考虑。这里的POM继承关系刚好和父子模块关系是一致的。POM继承称之为“继承关系”,父子模块称之为“聚合关系”。继承和聚合的更详细说明见“Maven聚合与继承

3, 依赖关系

Simple Model: 简单对象模型。

Simple Weather: 通过调用外部接口获取天气数据并解析XML结果的逻辑封装;

直接依赖于Simple Model

Simple Persist: 数据访问对象层(DAO);直接依赖于Simple Model

Simple WebApp: 控制层和Web展示层;

直接依赖于Simple WeatherSimple Persist

Simple Command: 控制层和命令行展示层;

直接依赖于Simple WeatherSimple Persist

4, Simple Parent POM

<groupId>org.sonatype.mavenbook.ch07</groupId>

  <artifactId>simple-parent</artifactId>

  <packaging>pom</packaging>

  <version>1.0</version>

  <modules><!—子模块配置,聚合关系-->

    <module>simple-command</module>

    <module>simple-model</module>

    <module>simple-weather</module>

    <module>simple-persist</module>

    <module>simple-webapp</module>

  </modules>

  <build>

    <pluginManagement>

      <plugins>

        <plugin>

          <groupId>org.apache.maven.plugins</groupId>

          <artifactId>maven-compiler-plugin</artifactId>

          <configuration>

            <source>1.5</source>

            <target>1.5</target>

          </configuration>

        </plugin>

      </plugins>

   </pluginManagement>

  </build>

 […]

5, Simple Model 模块

   对象模型使用Hibernate标注来映射模型对象至关系数据库的表,依赖于org.hibernate:hibernate-annotationsPOM

<parent><!—父POM申明,继承关系-->

    <groupId>org.sonatype.mavenbook.ch07</groupId>

    <artifactId>simple-parent</artifactId>

    <version>1.0</version>

  </parent>

  <artifactId>simple-model</artifactId>

  <packaging>jar</packaging>

  <dependencies>

    <dependency>

      <groupId>org.hibernate</groupId>

      <artifactId>hibernate-annotations</artifactId>

      <version>3.3.0.ga</version>

    </dependency>

    <dependency>

      <groupId>org.hibernate</groupId>

      <artifactId>hibernate-commons-annotations</artifactId>

      <version>3.3.0.ga</version>

    </dependency>

  </dependencies>

[…]

Weather模型对象: 

@Entity

@NamedQueries({@NamedQuery

(name="Weather.byLocation", query="from Weather w where w.location = :location")//一个hql查询

})

public class Weather {

    @Id

    @GeneratedValue(strategy=GenerationType.IDENTITY)// @GeneratedValue控制新的主键值如何产生,IDENTITY GenerationType,使用了下层数据库的主键生成设施

    private Integer id;

    @ManyToOne(cascade=CascadeType.ALL)//级联,多对一(weather多location一)

    private Location location;

    @OneToOne(mappedBy="weather",cascade=CascadeType.ALL)

    private Condition condition;

    @OneToOne(mappedBy="weather",cascade=CascadeType.ALL)

    private Wind wind;

    @OneToOne(mappedBy="weather",cascade=CascadeType.ALL)

    private Atmosphere atmosphere;

    private Date date;//默认映射,@Transient可忽略映射

public Weather() {}

    public Integer getId() { return id; }

    public void setId(Integer id) { this.id = id; }

    // All getter and setter methods omitted...

Condition模型对象:

@Entity

public class Condition {

    @Id

    @GeneratedValue(strategy=GenerationType.IDENTITY)

    private Integer id;

    private String text;

    private String code;

    private String temp;

    private String date;

    @OneToOne(cascade=CascadeType.ALL)

    @JoinColumn(name="weather_id", nullable=false)// 通过一个名为weather_id的外键引用关联

的Weather对象

    private Weather weather;

    public Condition() {}

    public Integer getId() { return id; }

    public void setId(Integer id) { this.id = id; }

    // All getter and setter methods omitted...

}

6, Simple Weather 模块

POM:

[…]

<parent>

    <groupId>org.sonatype.mavenbook.ch07</groupId>

    <artifactId>simple-parent</artifactId>

    <version>1.0</version>

  </parent>

  <artifactId>simple-weather</artifactId>

  <packaging>jar</packaging>

  <name>Simple Weather API</name>

  […]

    <dependency>

      <groupId>org.sonatype.mavenbook.ch07</groupId>

      <artifactId>simple-model</artifactId><!--子模块间的直接依赖-->

      <version>1.0</version>

</dependency>

[…]

此模块暴露一个服务 WeatherService,获取和解析天气并返回Weather对象。

由于Simple WebApp Simple Command 都将通过调用WeatherService获取结果,这里使用Spring Framework IOC实现,在此模块提供Springbeans资源文件,通过ClasspathXmlApplicationContext,另外两个模块均可调用到WeatherService 的实例。

Spring的ApplicationContext资源文件bean配置如下:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    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-2.0.xsd

    default-lazy-init="true">

    <bean id="weatherService"

             class="org.sonatype.mavenbook.weather.WeatherService">

      <property name="yahooRetriever" ref="yahooRetriever"/>

      <property name="yahooParser" ref="yahooParser"/>

    </bean>   

    <bean id="yahooRetriever"

             class="org.sonatype.mavenbook.weather.YahooRetriever"/>  <!--接收雅虎天气的实现--> 

    <bean id="yahooParser"

             class="org.sonatype.mavenbook.weather.YahooParser"/><!--解析雅虎天气的实现-->

</beans>

7, Simple Persist 模块

   从雅虎获取的天气信息和本地数据库交互的DAO层。POM文件略,直接依赖于Simple Model,继承于Simple Parent

WeatherDAO类:

public class WeatherDAO extends HibernateDaoSupport{

    public WeatherDAO() {}

    public void save(Weather weather) {

      getHibernateTemplate().save( weather );

    }

    public Weather load(Integer id) {

      return (Weather) getHibernateTemplate().load( Weather.class, id);

    }

    public List<Weather> recentForLocation( final Location location ) {

      return (List<Weather>) getHibernateTemplate().execute(

        new HibernateCallback() {

        public Object doInHibernate(Session session) {

         Query query = getSession().getNamedQuery("Weather.byLocation");//使用Hibernate 标注,见Weather的Model

          query.setParameter("location", location);

          return new ArrayList<Weather>( query.list() );

        }

      });

    }

}

这里也使用到Spring,这里的Spring ApplicationContext 资源配置文件如下:

<property name="annotatedClasses">

            <list>

                <value>org.sonatype.mavenbook.weather.model.Weather</value>

                <value>org.sonatype.mavenbook.weather.model.Wind</value>

         […]

            </list>

        </property>

        <property name="hibernateProperties">

            <props>

                <prop key="hibernate.show_sql">false</prop>

                <prop key="hibernate.format_sql">true</prop>

                <prop key="hibernate.transaction.factory_class">

                  org.hibernate.transaction.JDBCTransactionFactory

                </prop>

                <prop key="hibernate.dialect">

                  org.hibernate.dialect.HSQLDialect

                </prop>

                <prop key="hibernate.connection.pool_size">0</prop>

                <prop key="hibernate.connection.driver_class">

                  org.hsqldb.jdbcDriver

                </prop>

                <prop key="hibernate.connection.url">

                  jdbc:hsqldb:data/weather;shutdown=true

                </prop>

                <prop key="hibernate.connection.username">sa</prop>

                <prop key="hibernate.connection.password"></prop>

                <prop key="hibernate.connection.autocommit">true</prop>

                <prop key="hibernate.jdbc.batch_size">0</prop>

            </props>

        </property>

    </bean>

<bean id="locationDAO"

             class="org.sonatype.mavenbook.weather.persist.LocationDAO">

        <property name="sessionFactory" ref="sessionFactory"/>

    </bean>

    <bean id="weatherDAO"

  class="org.sonatype.mavenbook.weather.persist.WeatherDAO">

        <property name="sessionFactory" ref="sessionFactory"/>

    </bean>

 </beans>

8, Simple WebApp 模块

weather-servlet.xml为simmple-webapp中使用的Spring MVC的资源配置文件,applicationContext-xxx.xml为各自项目Spring IOC使用的普通配置文件。

《Maven权威指南》学习笔记十八_多模块企业级项目_第2张图片

weatherController: 使用weatherService获取天气,使用weatherDAO持久化天气。

POM:

 <groupId>org.sonatype.mavenbook.multispring</groupId><!—继承,注意不要纠结值,这是为了表现形式-->

    <artifactId>simple-parent</artifactId>

    <version>0.8-SNAPSHOT</version>

  </parent>

  <artifactId>simple-webapp</artifactId>

  <packaging>war</packaging> 

<dependencies>

<dependency>

      <groupId>org.sonatype.mavenbook.multispring</groupId>

      <artifactId>simple-weather</artifactId>

      <version>0.8-SNAPSHOT</version>

    </dependency>

    <dependency>

      <groupId>org.sonatype.mavenbook.multispring</groupId>

      <artifactId>simple-persist</artifactId>

      <version>0.8-SNAPSHOT</version>

    </dependency>

  </dependencies>

<build>

    <plugins>

      <plugin>

        <groupId>org.mortbay.jetty</groupId>

        <artifactId>maven-jetty-plugin</artifactId>

        <dependencies>

          <dependency><!—轻量级数据库-->

            <groupId>hsqldb</groupId>

            <artifactId>hsqldb</artifactId>[…]

          </dependency>

        </dependencies>

      </plugin>

      <plugin>

        <groupId>org.codehaus.mojo</groupId>

        <artifactId>hibernate3-maven-plugin</artifactId><!—hibernate插件-->[…]

        <configuration>

          <components>

            <component>

              <name>hbm2ddl</name><!—使用注解配置形式实现hbm to ddl-->

              <implementation>annotationconfiguration</implementation>

            </component>

          </components>

        </configuration>

        <dependencies>

          <dependency><!--Maven Hibernate3插件能成功的使用JDBC连接该数据库,

需要引用HSQLDB JDBC驱动-->

            <groupId>hsqldb</groupId>

            <artifactId>hsqldb</artifactId>[…]

          </dependency>

        </dependencies>

      </plugin>

    </plugins>

  </build>

Maven hibernate 插件:

l     如果正在使用Hibernate映射XML文件(.hbm.xml),要使用hbm2java目标生成模型类,implementation设置成“configuration”。

l     如果使用Hibernate3插件逆向工程从一个数据库产生.hbm.xml文件和模型类, implementation设置成“jdbcconfiguration”。

l     如果使用现存的标注对象模型来生成一个数据库,也就是有Hibernate映射,但没有数据库,implementation设置成“annotationconfiguration”。

Tip:不建议使用<extensions>添加插件需要的依赖,会造成classpath污染,除非是定义新的wagon实现。

WeatherController类如下:

[…]

public class WeatherController implements Controller {//实现Spring MVC 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);//返回数据给模板 ,第一个参数为模板名称

[…]

ModelAndView类将被用来呈现Velocity模板,这个模板有对${weather}变量的引用。weather.vm模板存储在src/main/webapp/WEB-INF/vm/下,如下所示:

${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>
HistoryController及其对应的 history.vm 略。

主要用于Spring MVC weather-servlet.xml配置文件如下:     

<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"><!—URL映射模式-->

               <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/"/><!—velocity模板目录 配置-->

     </bean><!—使用Velocity的配置-->

     <bean id="viewResolver"  class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">

       <property name="cache" value="true"/><!—velocity模板配置-->

       <property name="prefix" value=""/>

       <property name="suffix" value=".vm"/>

       <property name="exposeSpringMacroHelpers" value="true"/>

     </bean>

</beans>

web.xml:    

<param-name>contextConfigLocation</param-name>

    <param-value><!—加载 Spring配置文件,依赖项目打包后的Jar将位于本项目的lib目录下-->

      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> <!—Spring上下文监听器,本质上是一个Spring容器,根据contextConfigLocation参数构造一个ApplicationContext-->

     org.springframework.web.context.ContextLoaderListener

    </listener-class>

  </listener>

  <servlet><!--定义一个名为weather的Spring MVC DispatcherServlet。这会让Spring

从/WEB-INF/weather-servlet.xml寻找Spring配置文件-->

    <servlet-name>weather</servlet-name>

    <servlet-class><!—Spring URL分发-->

      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>

9, 运行Simple WebApp

1),执行”mvn hibernate3:hbm2ddl”, 使用Hibernate3插件构造HSQLDB数据库

2), 执行”mvn jetty:run”

3), 访问http://localhost:8080/simple-webapp/weather.x?zip=60202

10, Simple Command 模块

simple-command项目是simple-webapp的一个命令行版本。这个命令行工具有这同样的模块依赖:simple-persistsimple-weather。我们从命令行运行这个simple-command工具,而非通过web浏览器与该应用交互。

POM:

[…]<parent>…</parent>

  <artifactId>simple-command</artifactId>

  <packaging>jar</packaging>

  <build>

    <plugins>

      <plugin>

        <groupId>org.apache.maven.plugins</groupId>

        <artifactId>maven-surefire-plugin</artifactId>

        <configuration>

          <testFailureIgnore>true</testFailureIgnore><!—忽略测试失败-->

        </configuration>

      </plugin>

      <plugin>

       <artifactId>maven-assembly-plugin</artifactId><!—装配插件-->

        <configuration>

          <descriptorRefs>

            <descriptorRef>jar-with-dependencies</descriptorRef><!—包含运行应用所需要的所有二进制代码-->

          </descriptorRefs>

        </configuration>

      </plugin>

       <plugin>

        <groupId>org.codehaus.mojo</groupId>

        <artifactId>hibernate3-maven-plugin</artifactId>

[此处hibernate插件的配置同Simple WebApp模块的POM]

      </plugin>

    </plugins>

  </build>[…]                                   

此模块提供Main类,提供main方法,通过SpingClassPathXmlApplicationContext加载Springbean配置文件,获取bean实例实现数据的获取、调用、持久化操作。这里还使用到Velocity,手工加载Velocity模板,给其上下文注入值,具体使用不作介绍。

11, 运行 Simple Command

这里使用装配插件打包,目的是将本Command工程所以来的环境都打包进来,使用命令:mvn assembly:assembly

然后执行:mvn hibernate3:hbm2ddl, 创建HSQLDB数据库;

最后可以运行Jar的入口类。

12, 通过以上介绍,可以观察到我们可以通过Maven聚合的概念,分离接口模块和实现模块为两个不同的模块,而可以并存多个实现模块,在其他聚合模块只需要使用接口模块的依赖进行编码,不同的实现可以通过依赖坐标的切换实现(似乎没有意义?)。

 





你可能感兴趣的:(maven,Module)