John Jiang

a cup of Java, cheers!
https://github.com/johnshajiang/blog

   :: 首页 ::  :: 联系 :: 聚合  :: 管理 ::
  131 随笔 :: 1 文章 :: 530 评论 :: 0 Trackbacks
Maven入门--较复杂的实例
本文将使用一个较复杂的实例,讲述如何定制目录布局(即不使用Maven标准目录布局),以及讲述一些关键插件的使用(配置)。为了方便其它朋友能够方便地使用该实例,后台数据库使用开源的面向对象数据库--db4o,该数据库无需安装,已包含在与本文配套的实例中,文末附有该实例的下载链接。(2007.01.02最后更新)
注:转载时请注明原作者(jiangshachina)及出处(http://www.blogjava.net/jiangshachina)!

1 实例的构想
文章开头的摘要已经讲述了,本文仍然将以一个实例描述如何使用Maven,
该实例将使用非Maven标准的目录结构,并将呈现一些关键的Maven插件的配置与应用。 该实例是一个基于db4o的数据库Web应用。该应用本身十分简单,即从db4o数据库中查询出若干记录并将它们显现在Web页面中。
    该实例仍然由一个普通应用工程(demo-app)与一个Web应用工程(demo-web),以及这两个工程的父工程(demo)构成,最终的目标是将Web应用工程制作成war文件,并部署到JBoss服务器中。启动服务器后,能够在页面中看到正确的查询结果。
    该实例使用Eclipse3.2 + JDK1.5.0_10 + Windows2000开发。当然这仅仅只是我个人的开发平台,但该实例并不受限于此平台;由于我选择使用db4o针对JDK1.5的产品包,所以该实例只能运行在JDK1.5.0或更高版本的JDK/JRE中; 该工程中的所有文件都使用UTF-8编码方式。

2 demo工程
demo工程是其它两个工程的父工程,它的主要职责是预定义子工程所需要依赖的jar文件(artifact),以及针对子工程所使用的插件进行通用配置。该工程完整的POM文件如下所示:
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>mvn.demo</groupId>
    <artifactId>demo</artifactId>
    <packaging>pom</packaging>
    <version>
1.0-SNAPSHOT</version>
    <description>Maven Demo Project</description>

    <modules>
        <module>demo-app</module>
        <module>demo-web</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>mvn.demo</groupId>
                <artifactId>demo-app</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>mvn.demo</groupId>
                <artifactId>demo-web</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>com.db4o</groupId>
                <artifactId>db4o-java5</artifactId>
                <version>
5.5</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>
2.4</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>commons-configuration</groupId>
                <artifactId>commons-configuration</artifactId>
                <version>
1.2</version>
                <exclusions>
                    <exclusion>
                        <groupId>dom4j</groupId>
                        <artifactId>dom4j</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>xml-apis</groupId>
                        <artifactId>xml-apis</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>xalan</groupId>
                        <artifactId>xalan</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>xerces</groupId>
                        <artifactId>xercesImpl</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
        <groupId>junit</groupId>
         <artifactId>junit</artifactId>
           <version>
3.8.1</version>
      <scope>test</scope>
    </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>UTF-
8</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>
1.5</source>
                    <target>
1.5</target>
                    <encoding>UTF-
8</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                    </archive>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                    </archive>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <configuration>
                    <charset>UTF16</charset>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
    预定义工程的依赖关系,就是把会被子工程依赖的artifact的详细信息(groupId,artifactId,version,...)先声明到<dependencyManagement>中。然后子工程只需要声明使用某个artifact就可以了,即那时只需要设置groupId和artifactId(甚至更少)就可以了。
<dependencyManagement>中声明的artifact并不一定真的会被使用到
2.1 声明依赖关系
    根据实际情况,
该实例 需要使用db4o针对java5的产品包(jar文件)。由于该jar文件并不存在于Maven的中央仓库中,所以我们不能直接通过Maven获得该jar文件。我们只能另外下载db4o-5.5(Java版)的压缩包,然后从压缩包内获得db4o-java5.jar。得到该jar后,必须先将它安装到Maven的本地仓库中(安装方法参见资源[1],主题"向本地仓库安装文件时要生成POM文件"),以备后面的使用。此处将该artifact的groupId定义为com.db4o,artifactId定义为db4o-java5,version自然就是5.5了(请见上述POM脚本)。
    由于该实例最终是一个Web应用,所以它至少需要依赖Servlet的包(servlet-api-2.4.jar),还需要commons-configuration-1.2.jar。这两个artifact都已经存在于Maven中央仓库中,所以我查找到它们后,按照Maven中央仓库的命名将它们声明到了<dependencyManagement>中(请见上述POM脚本)。junit是进行单元测试时使用的artifact,(假设)它肯定会被每个工程使用,所以没有将它设置到 <dependencyManagement>中,而直接设置到了 <dependency>中。
    细心的朋友肯定已经发现了,针对 commons-configuration的依赖声明处多了一些语句。从表面上看,应该是排除了4个artifact(dom4j, xml-apis xalan xerces )。不错,就是排除了这4个jar文件(artifact)。如果有兴趣的话,可以将整个<exclusions>元素删除,然后再尝试一下制作war文件。你会发现在WEB-INF/lib目录下存在着这4个artifact对应的jar文件。那我为什么要将它们“排除”呢?因为,它们是多余的!即,它们对于我的这个Web应用来说,根本就是无用的!
    Maven2加入了一个很好的特性:自动加载“依赖的依赖(Transitive Dependency)”。以commons-configuration为例。为了能够让它运行正常,我们实际上还需要其它一些jar(artifact),如commons-collections,commons-lang,...。但这些artifact我都没有“显示”地声明需要依赖它们,但Maven会自动加载,因为
commons-configuration的POM文件将它们声明为了dependency
    既然那个4个artifact是commons-configuration的依赖,为什么会认为它们是无用的呢?实际上,它们就不应该被声明到commons-configuration的依赖关系中。这是commons-configuration开发者的失误,他们没有将依赖关系整理清晰,而将一些确实既不是runtime,更不是compile-time需要的artifact放入到了依赖关系中。在Maven中央仓库中存在着很多这种情况,所以我们有时需要弄清楚“哪些文件是我们真正需要的,哪些是可以被清除的”。但有时候,很难做到一个不漏。正是由于这一原因,自动加载Transitive Dependency这一极好的特性,有时让人十分无奈 ^_^
2.2 对插件进行基本配置
我们可以把对插件的全局性(如针对整个项目的)设置放到较高层次的POM文件中,因为它们被设置后,子工程们就会自然遵守它们,而且可以使每个子工程的情况都是一样的。
    在第1节中,已经表明该工程使用JDK1.5平台,并且所有文件都使用UTF-8
的编码方式。而Maven默认使用JDK1.3级别的javac编译器;默认使用本地编码方式(简体中文Windows操作系统默认使用GBK编码方式)处理文件。这样就必须对Maven进行适当设置,以满足工程的实际需要。
    针对资源文件的处理,Maven使用maven-resources-plugin插件,需要将它的编码方式设置为UTF-8。编译Java源文件,是使用maven-compiler-plugin插件,需要将它的source(Java源文件)与target(class文件)的级别都设置为1.5,另外还要将它的encoding方式设置为UTF-8。(详细设置请见POM脚本)

3 demo-app工程
demo-app工程是一个普通应用程序工程,它用于处理和数据库相关的操作,如针对数据库的增、删、改、查等基本功能。该工程POM文件的主要内容如下所示:
<project>
    ......

    <build>
        <finalName>app</finalName>
        <directory>target</directory>

        <sourceDirectory>src/java</sourceDirectory>
        <outputDirectory>target/classes</outputDirectory>
        <resources>
            <resource>
                <directory>src/java</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
        </resources>

        <testSourceDirectory>src/test/java</testSourceDirectory>
        <testOutputDirectory>target/test-classes</testOutputDirectory>
        <testResources>
            <testResource>
                <directory>src/test/java</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </testResource>
        </testResources>
    </build>
</project>
    文章的开头已经提到,本实例将会使用定制的目录结构,但在前面却一字不提此事,现在将描述如何定制目录结构。Maven的标准目录结构其实是在Super POM中设置的,由于任何POM都会继承该POM,所以所有的工作都会默认使用标准目录结构。要定制目录,其实就是需要重新设置相关参数的值,即用新值覆盖Super POM中的值。
[1]<finalName>,该元素指定了工程输出的artifact的名称,默认值为${artifactId}-${version},此处修改为app。
[2]<directory>,该元素指定了工程输出的目标目录。默认值为target,此处未修改变。
[3]<sourceDirectory>,该元素指定了Java源文件所在的目录。默认值为src/main/java,此处修改为src/java。
[4]<outputDirectory>,该元素指定了编译后的class文件的放置目录。默认值为target/classes,此处未作改变。
[5]<resources> <resource>,该元素指定了Java源文件使用的资源文件的存放目录。默认值为src/main/resources,此处修改为src/java。由于在编码Java源文件时,Maven会将资源路径中的文件全部拷贝到classes目录。而此时将Java资源文件目录与Java源文件目录,设置为同一目录,所以需要将.java文件排除在资源文件的范畴之外( <exclude>**/*.java</exclude> )。
[6]
<testSourceDirectory>,该元素指定了单元测试Java源文件的放置目录。默认值为src/test/java,此处未作修改。
[7]
<testOutputDirectory>,该元素指定了单元测试Java源文件编译后的class文件放置目录。默认值为 target/test-classes,此处未作改变。
[8]
<testResources> <testResource>,该元素指定了单元测试Java源文件所使用的资源文件的放置目录。默认值为src/test/resources,此处修改为 src/test/java。并且也做了与 设置<resources> <resource>时相同的处理(排除Java源文件)。
    通过上述设置后,就可以拥有一个定制的Maven工程目录结构了。

4 demo-web工程
demo-web工程是整个应用最终的目标输出,因为此处的目的就是制作一个war文件,然后将它部署到JBoss服务器中。与demo-app工程相比,demo-web工程的POM文件主要有如下不同内容:
<project >
    ......
    <build>
        ......
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>
2.0.1 </version>
                <configuration>
                    <webappDirectory>target/${artifactId}</webappDirectory>
                    <warSourceDirectory>src/webapp</warSourceDirectory>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jboss-maven-plugin</artifactId>
                <version>
1.3.1 </version>
                <configuration>
                    <jbossHome>E:/jboss-
4.0.2 </jbossHome>
                    <serverName>default</serverName>
                    <fileName>
                        ${project.build.directory}/${project.build.finalName}.${project.packaging}
                    </fileName>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
可以看出不同之处就在于对maven-war-plguin及jboss-maven-plugin插件的配置与使用。
    Maven使用maven-war-plugin插件对Web工程制作war文件。由于本文使用了定制目录结构,这样则会使maven-war-plugin无法找到Web工程的Web Root目录(默认是src/main/webapp),所以需要对该插件进行适当地配置。<warSourceDirectory>就是Web工程的Web Root目录,此处设置为;<webappDirectory>是制作war文件之前,相当于是一个被打开(exploded)的war文件的根目录(默认是target/artifactId-version)。
    该工程的脚本中,还使用了一个JBoss插件。该插件可以将制作好的war文件部署(实质上是拷贝)到指定的JBoss部署目录中。<jbossHome>是JBoss的安装根目录,<serverName>指JBoss Server的名称,<fileName>是被部署war文件的名称。

参考资源
[1]Maven入门--概念与实例. http://www.blogjava.net/jiangshachina/archive/2006/09/01/67080.html
[2]Maven + Continuum Weed. http://www.blogjava.net/jiangshachina/archive/2006/09/11/68944.aspx
[3]Maven POM Reference. http://maven.apache.org/pom.html
[3]db4o. http://www.db4objects.com
本文实例下载地址--http://www.blogjava.net/files/jiangshachina/mvn-demo.rar

posted on 2006-12-12 18:03 John Jiang 阅读(12654) 评论(21)  编辑  收藏 所属分类: JavaSEDatabaseMavendb4o原创

评论

# re: Maven入门--较复杂的实例 2006-12-18 00:48 Joeaniu
赞,写得很清晰~   回复  更多评论
  

# re: Maven入门--较复杂的实例 2006-12-18 08:48 Sha Jiang
谢谢夸奖 ^_^
本文我将会进行修改,还有些内容没有介绍到。
而且不必将每个工程的POM文件完整内容帖上来,只需要针对特定的脚本片断进行说明就可以了。POM的完整内容应该是看源文件的。  回复  更多评论
  

# re: Maven入门--较复杂的实例 2006-12-20 21:30 向大家学习
学习了 写的很好  回复  更多评论
  

# re: Maven入门--较复杂的实例 2006-12-23 18:31 Sha Jiang
刚刚在IBM的developerWorks中看到一篇介绍Maven2的好文章,不敢独享 ^_^
http://www-128.ibm.com/developerworks/edu/j-dw-java-mavenv2.html?S_TACT=105AGX02&S_CMP=HP
不过,需要首先注册才能阅读全文。  回复  更多评论
  

# re: Maven入门--较复杂的实例 2007-06-24 23:01 sitinspring
很好,很详细,值得学习.

  回复  更多评论
  

# re: Maven入门--较复杂的实例 2007-06-25 08:15 Sha Jiang
谢谢!  回复  更多评论
  

# re: Maven入门--较复杂的实例 2007-06-28 16:49 sitinspring
我用Maven一直有一个疑惑,就是文件总是需要拷贝来拷贝去,只有用Bat或者Srcipt解决,但也麻烦,不只你是如何解决这个问题的?用Continuun能否避免这个麻烦?
  回复  更多评论
  

# re: Maven入门--较复杂的实例 2007-06-29 08:53 Sha Jiang
> 我用Maven一直有一个疑惑,就是文件总是需要拷贝来拷贝去,
> 只有用Bat或者Srcipt解决,但也麻烦,不只你是如何解决这个问题的?
不明白你的意思?
为什么要将文件"拷贝来拷贝去"?只要把它们放到"合适"的地方就可以了啊。
Bat肯定是不用的,否则无法将这个工程移植到其它地方(Linux中能用bat文件吗?)。
Script?如果你是指Ant的脚本,有时会用一些,但应该将它的数量保持在一个很小的水平上。

> 用Continuun能否避免这个麻烦?
Continuum是持续集成服务器,它只会根据Maven(也其它几种build工具)工程中的Maven脚本去执行具体的Build工作。
所以这个问题与Continuum无关,关键是在Maven本身。

P.S.
如果你看了我的其它"留言回复"的话,就会知道我是使用CruiseControl。
Continuum集成Maven工程十分简便,但它的功能目前还较弱,而且CC作为最老牌的持续集成工具,使用的范围很广,所以最好还是决定使用CC。  回复  更多评论
  

# re: Maven入门--较复杂的实例 2007-06-29 08:57 Sha Jiang
> 所以最好还是决定使用CC
No No No,写错了,不是"最好",应该是"最后"。
一字之差,千里之谬。  回复  更多评论
  

# re: Maven入门--较复杂的实例[未登录] 2007-06-29 15:43 sitinspring
Thanks! I will try it.  回复  更多评论
  

# re: Maven入门--较复杂的实例 2007-07-02 08:22 Sha Jiang
Good Luck!  回复  更多评论
  

# re: Maven入门--较复杂的实例(原) 2007-10-15 14:37 岭南
使用这个东东觉得很不爽,写一大堆配置
还时不时要到命令行下去搞一伙。
觉得反而不方便。
用Myeclipse一下全搞定。  回复  更多评论
  

# re: Maven入门--较复杂的实例(原) 2007-10-15 17:18 Sha Jiang
to 岭南:
与使用Ant相比,Maven的学习难度要稍大一些。
但弄懂Maven的基本原理/应用后,再使用它,就不会觉得困难了。

而且不可否认的是,Maven对于开发者的友好性也确实要差一些。
Maven的标准目录结构可能与开发者的习惯或所用开发工具的特性有冲突。
通过定制目录结构应该可以较好的解决这个问题。
而且Maven的标准目录结构本身就有利于开发,所以也不应该对它进行大的修改。  回复  更多评论
  

# re: Maven入门--较复杂的实例(原) 2008-04-21 16:39 chamborghini
受益匪浅,收藏了  回复  更多评论
  

# re: Maven入门--较复杂的实例(原) 2008-12-25 09:56 Yvon
写得蛮好,谢谢  回复  更多评论
  

# re: Maven入门--较复杂的实例(原) 2009-06-24 16:44 kting
写的很好,很有价值,受益。  回复  更多评论
  

# re: Maven入门--较复杂的实例(原) 2010-12-02 15:46 Rosen
感谢选用db4o做demo:)  回复  更多评论
  

# re: Maven入门--较复杂的实例(原) 2011-09-14 15:53 Tony.Wang
我看上的是可以对几个工程统一编译和打包,这个相对ANT就好多了,研究了两三天,知道些皮毛了,看来要好好实践一个复杂的例子试试了  回复  更多评论
  

# re: Maven入门--较复杂的实例(原)[未登录] 2012-10-03 16:16 tony
再次感谢楼主  回复  更多评论
  

# re: Maven入门--较复杂的实例(原) 2014-04-29 17:45 Gemma
我运行demo的实例的时候报错,说设备未就绪。
好像是数据库的问题,第一次接触db4o,
请问dbFile=D:/Download/book.yap这个文件在哪?  回复  更多评论
  

# re: Maven入门--较复杂的实例(原) 2014-04-29 17:54 Sha Jiang
@Gemma
貌似这个问题已经存在七年多的时间了@_@
不过,程序是否能最终运行成功,其实也无所谓吧。你可以修改下源代码。
另外,你们为什么不用Gradle呢?Maven有被它取代的趋势。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: