建议您先按照本文试试火,然后再看看maven的站点文档会比较节约时间,
因为开始时我看了一堆文档仍然不了解它到底在干啥,做了几个试验才明白,
由于maven鼓励各项目共用同一个jar资料库,所以象ant般在每个项目的lib中存放jar将
很少发生,而且并不需要你自己下载所有的依赖jar,只用告所它:名称-版本就行了,它会在
一些集中放置jar的网站自动下载,稍慢了些,不过,以后你就明白这样的好处了。
1.下载:
http://maven.huangdong.com/start/download.html
我们应挑选其中的中文版下载:http://maven.huangdong.com/dist/
目前最后版本:MavenCN 1.0 RC2
2.安装:
解压到硬盘,我解压到:D:/frameworks/maven-1.0-rc2
设置MAVEN_HOME环境变量为解压目录: MAVEN_HOME=D:/frameworks/maven-1.0-rc2
(又设环境变量!为何不能自己把自己的目录设为MAVEN_HOME呢? :-<
可能因为我们还要经常运用MAVEN_HOME/bin/maven.bat )
运行maven.bat来看看maven是否可用:
在命令行执行maven.bat出现下面的输出则说明你的maven可以运行了:
-------------------------------------------------------------
D:/frameworks/maven-1.0-rc2/bin>meven
__ __
| // |__ _Apache__ ___ __ ___
| |//| / _` / V / -_) ' / / _| ' / ~ intelligent projects ~
|_| |_/__,_|/_//___|_||_|/___|_||_| v. 1.0-rc2
BUILD SUCCESSFUL
-------------------------------------------------------------
3. ok现在就跑个小项目试试火力
此项目针只对几个java文件(web开发稍候再试...),来看看它的编译和打包jar功能和ant有何不同.
先建立一个新的目录 d:/test/maven
maven鼓励在path中设置maven的解压路径,这样就可以随时执行maven.bat了,可我觉得尽量少的在机器上
设置可能更好些(刚才设了个maven_home现在还耿耿于怀:-),所以我会为每个项目建立一个maven.bat:
d:/test/maven/maven.bat
-----------------------------------------
%MAVEN_HOME%/bin/maven %1 %2 %3 %4 %5
-----------------------------------------
ok,现在我们的目录中只有一个便利的bat而已,用maven生成模板为我们制造一个初始环境目录结构:
D:/test/maven>maven genapp
按照提示随便输入一些信息(模版程序的参数),或者简单的全部回车
D:/test/maven>maven genapp
屏幕输出:
----------------------------------------------------------------------
__ __
| // |__ _Apache__ ___ __ ___
| |//| / _` / V / -_) ' / / _| ' / ~ intelligent projects ~
|_| |_/__,_|/_//___|_||_|/___|_||_| v. 1.0-rc2
Enter a project template to use: [default]
Please specify an id for your application: [app]
chen56
Please specify a name for your application: Example Application
chen56
Please specify the package for your application: [example.web]
chen56
----------------------------------------------------------------------
哇,发现目录中多了几个文件和文件夹,这是maven的genapp插件所提供的模版结构。
我们的meven目录:
-----------------------------------------------
|-- project.properties
|-- project.xml
`-- src
|-- conf
| `-- app.properties
|-- java
| `-- chen56
| `-- App.java
`-- test
`-- chen56
|-- AppTest.java
|-- AbstractTestCase.java
`-- NaughtyTest.java
-----------------------------------------------
先不管它生成了啥东东,用屁股想想也知道大概是一些个配置文件
再输入:
D:/test/maven>maven java:compile
看看目录中多了个target目录,这也是maven默认的编译目录,里边已经把文件们都编译过了。
再输入:
D:/test/maven>maven jar
发现屏幕输出显示编译、测试、打包jar...,看看target目录,多了个chen56-1.0.jar文件,我们的成果已经被
打包了,哦哦,这样就行了吗?当然不行,在接下来的更复杂的web例子中我们先来讲讲刚才都作了什末。
/*
构造本地资源库(repository),这也是以后放置所有第三方类库的地方,比如junit放在:
repository/junit/jars/junit-3.8.1.jar
maven默认为%HOME%/.maven目录下:在我的WIN2000也就是:
C:/Documents and Settings/chen56/.maven/ 本地资源库
C:/Documents and Settings/chen56/.maven/plugins/ maven插件
C:/Documents and Settings/chen56/.repository/ 第3方类库
要完成此构造要运行maven-1.0-rc2/bin/install_repo.bat命令,要运行这个bat,就要设置
MAVEN_HOME 环境变量,我简单的建立另一个批处理文件 install.bat:
|----------------------------------------------
| set MAVEN_HOME=../
| install_repo %USERPROFILE%/.maven/repository
|-----------------------------------------------
运行install.bat,则会把maven自带的一些类库copy到repository目录中,并作一些它的初始化,天晓得它还干了啥。
*/
最近由于工作原因在研究、应用Maven,有了一些体会就写成了此文。本文虽然是Maven2的入门文章,但并不涉及Maven的历史、下载与安装,这些内容可以到Maven的官方网站上了解。本文主要是关注Maven中的重要概念,并以一个实例来阐述使用Maven的基本方法。文末有例子代码下载的链接。(2006.10.29最后更新)
1 关键名词
Project:任何您想build的事物,Maven都可以认为它们是工程。这些工程被定义为工程对象模型(POM,Poject Object Model)。一个工程可以依赖其它的工程;一个工程也可以由多个子工程构成。
POM:POM(pom.xml)是Maven的核心文件,它是指示Maven如何工作的元数据文件,类似于Ant中的build.xml文件。POM文件位于每个工程的根目录中。
GroupId:groupId是一个工程的在全局中唯一的标识符,一般地,它就是工程名。groupId有利于使用一个完全的包名,将一个工程从其它有类似名称的工程里区别出来。
Artifact:artifact是工程将要产生或需要使用的文件,它可以是jar文件,源文件,二进制文件,war文件,甚至是pom文件。每个artifact都由groupId和artifactId组合的标识符唯一识别。需要被使用(依赖)的artifact都要放在仓库(见Repository)中,否则Maven无法找到(识别)它们。
Dependency:为了能够build或运行,一个典型的Java工程会依赖其它的包。在Maven中,这些被依赖的包就被称为dependency。dependency一般是其它工程的artifact。
Plug-in:Maven是由插件组织的,它的每一个功能都是由插件提供的。插件提供goal(类似于Ant中的target),并根据在POM中找到的元数据去完成工作。主要的Maven插件要是由Java写成的,但它也支持用Beanshell或Ant脚本写成的插件。
Repository:仓库用于存放artifact,它可以是本地仓库,也可以是远程仓库。Maven有一个默认的远程仓库--central,可以从http://www.ibiblio.org/maven2/下载其中的artifact。在Windows平台上,本地仓库的默认地址是User_Home/.m2/repository。
Snapshot:工程中可以(也应该)有一个特殊版本,它的版本号包括SNAPSHOT字样。该版本可以告诉Maven,该工程正处于开发阶段,会经常更新(但还未发布)。当其它工程使用此类型版本的artifact时,Maven会在仓库中寻找该artifact的最新版本,并自动下载、使用该最新版。
2 Maven Build Life Cycle
软件项目一般都有相似的开发过程:准备,编译,测试,打包和部署,Maven将上述过程称为Build Life Cycle。在Maven中,这些生命周期由一系列的短语组成,每个短语对应着一个(或多个)操作;或对应着一个(或多个)goal(类似于Ant中的target)。
如编译源文件的命令mvn compile中的compile是一个生命周期短语。同时该命令也可以等价于mvn compiler:compile,其中的compiler是一个插件,它提供了compile(此compile与mvn compile中的compile意义不同)goal;compiler还可提供另一个goal--testCompile,该goal用于编译junit测试类。
在执行某一个生命周期时,Maven会首先执行该生命周期之前的其它周期。如要执行compile,那么将首先执行validate,generate-source,process-source和generate-resources,最后再执行compile本身。关于Maven中默认的生命周期短语,请见参考资源[6]中的附录B.3。
3 标准目录布局
Maven为工程中的源文件,资源文件,配置文件,生成的输出和文档都制定了一个标准的目录结构。Maven鼓励使用标准目录布局,这样就不需要进行额外的配置,而且有助于各个不同工程之间的联接。当然,Maven也允许定制个性的目录布局,这就需要进行更多的配置。关于Maven的标准目录布局,请见参考资源[6]中的附录B.1。
4 Maven的优点
[1]build逻辑可以被重用。在Ant中可能需要多次重复地写相同的语句,但由于POM的继承性,可以复用其它的POM文件中的语句。这样既可以写出清晰的build语句,又可以构造出层次关系良好的build工程。
[2]不必关注build工作的实现细节。我们只需要使用一些build生命周期短语就可以达到我们的目标,而不必管Maven是如何做到这些的。如,只需要告诉Maven要安装(install),那么它自然就会验证,编译,打包,及安装。
[3]Maven会递归加载工程依赖的artifact所依赖的其它artifact,而不用显示的将这些artifact全部写到dependency中。
[4]如果完全使用Maven的标准目录布局,那么可以极大地减少配置细节。
5 实例
5.1 构想
由于只是阐述Maven的基本使用方法,所以本文将要设计的实例,只是一个简单的Maven demo。该实例包含两个工程:普通应用程序工程(app)和Web应用工程(webapp)。app工程提供一个简单的Java类;webapp工程只包含一个Servlet,并将使用app中的Java类。
该Demo的目标是能够正确地将webapp制成war包,以供部署时使用。要能够正确制作war,自然首先就必须要能够正确的编译源代码,且要将App模块制成jar包。本文创建的工程所在的目录是D:/maven/demo。
5.2 App工程
可以使用Maven的archetype插件来创建新工程,命令如下:
D:/maven/demo>mvn archetype:create -DgroupId=ce.demo.mvn -DartifactId=app
该工程的groupId是ce.demo.mvn,那么该工程的源文件将放在Java包ce.demo.mvn中。artifactId是app,那么该工程根目录的名称将为app。
当第一次执行该命令时,Maven会从central仓库中下载一些文件。这些文件包含插件archetype,以及它所依赖的其它包。该命令执行完毕后,在目录D:/maven/demo下会出现如下目录布局:
一个 更高层次工程,即使用app和webapp成为这个工程的子工程。为了使demo目录成为一个demo工程,只需要在这个目录下添加一个pom.xml文件,该文件内容如下:
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- ce
| `-- demo
| `-- mvn
| `-- App.java
`-- test
`-- java
`-- ce
`-- demo
`-- mvn
`-- AppTest.java
因本文暂时不涉及JUnit测试,故请将目录app/src/test目录删除(不删除也没关系 ^_^)。然后再修改App.java文件,其完全内容如下:
其实,如果我们能够清楚地知道Maven的标准目录布局,就可以不使用archetype插件来创建工程原型;如果我们要定制个性的目录布局,那么就更没有必要使用archetype插件了。
5.3 WebApp工程
我们仍然如创建app工程一样使用archetype插件来创建webapp工程,命令如下:
D:/maven/demo>mvn archetype:create -DgroupId=ce.demo.mvn -DartifactId=webapp -DarchetypeArtifactId=maven-archetype-webapp
第一次运行此命令时,也会从central仓库中下载一些与Web应用相关的artifact(如javax.servlet)。此命令与创建app的命令的不同之处是,多设置了一个属性archetypeArtifacttId,该属性的值为maven-archetype-webapp。即告诉Maven,将要创建的工程是一个Web应用工程。创建app工程时没有使用该属性值,是由于archetype默认创建的是应用程序工程。同样的,执行完该命令之后,会出现如下标准目录布局:
public class App {
public String getStr(String str) {
return str;
}
}
|-- pom.xml
`-- src
`-- main
`-- webapp
| -- index.jsp
|-- WEB-INF
`-- web.xml
根据5.1节的构想,webapp工程将只包含一个Servlet,所以我们不需要index.jsp文件,请将其删除。此时大家可以发现,目前的目录布局中并没有放Servlet,即Java源文件的地方。根据参考资源[6]中的附录B.1,以及app工程中Java源文件的布局,可以知道Servlet(它仍然是一个Java类文件)仍然是放在webapp/src/main/java目录中,请新建该目录。此处的Servlet是一个简单HelloServlet,其完整代码如下:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ce.demo.mvn.App; // 引用app工程中的App类
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = -3696470690560528247L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
App app = new App();
String str = app.getStr("CE Maven Demo");
PrintWriter out = response.getWriter();
out.print("<html><body>");
out.print("<h1>" + str);
out.print("</body></html>");
}
}
5.4 POM文件
大家可以发现,在前面新建工程时,我们并没有提到各个工程中的pom.xml文件。现在将要讨论这个问题。我们先看看app工程中的POM文件,其完整内容如下:
< modelVersion > 4.0.0 </ modelVersion >
< groupId > ce.demo.mvn </ groupId >
< artifactId > app </ artifactId >
< packaging > jar </ packaging >
< version > 1.0 </ version >
< name > CE Maven Demo -- App </ name >
</ project >
大家可以发现此我帖出来的内容与实际由archetype插件生成的POM文件的内容有些不同,但基本上是一致的。只是为了使文件中的语句更清晰,此处删除了一些冗余的内容,并修改了该工程的version和name的值,以与此例子的背景来符合。在目前情况下modelVersion值将被固定为4.0.0,这也是Maven2唯一能够识别的model版本。groupId,artifactId的值与创建工程时使用的命令中的相关属性值是一致的。packaging的值由工程的类型决定,如应用程序工程的packaging值为jar,Web应用工程的packaging值为war。上述情况也可以从webapp的POM文件中看出,下面将看看这个pom的完整内容。
< modelVersion > 4.0.0 </ modelVersion >
< groupId > ce.demo.mvn </ groupId >
< artifactId > webapp </ artifactId >
< packaging > war </ packaging >
< version > 1.0 </ version >
< name > CE Maven Demo -- WebApp </ name >
< dependencies >
< dependency >
< groupId > ce.demo.mvn </ groupId >
< artifactId > app </ artifactId >
< version > 1.0 </ version >
</ dependency >
< dependency >
< groupId > javax.servlet </ groupId >
< artifactId > servlet-api </ artifactId >
< version > 2.4 </ version >
< scope > provided </ scope >
</ dependency >
</ dependencies >
</ project >
比较app与webapp中的POM,除前面已经提过的packaging的差别外,我们还可以发现webapp中的POM多了dependencies项。由于webapp需要用到app工程中的类(见HelloServlet源代码),它还需要javax.servlet包(因为该包并不默认存在于jsdk中)。故,我们必须要将它们声明到依赖关系中。
5.5 执行
上述两个工程创建完毕后,就需要执行一些命令来看看会有什么结果出现。我们首先进入app目录,并执行命令mvn compile,然后会在该目录下发现新生成的目录target/classes,即编译后的class文件(包括它的包目录)就放在了这里。再执行命令mvn package,在目录target中就会生成app-1.0.jar文件。该文件的全名由如下形式确定:artifactId-version.packaging。根据第2章的叙述可以知道,执行命令mvn package时,将首先将产生执行命令mvn compile之后的结果,故如果要打包,那么只需要执行mvn package即可。
在app工程中执行完之后,就需要进入webapp工程了。进入webapp目录,此次将只执行mvn package命令(隐示地执行了compile过程)。此次命令的执行并不成功,会出现如下问题:
由粗体内容可知,Maven正试图从central仓库下载app工程的artifact,但central仓库肯定不会有这个artifact,其结果只能是执行失败!由第1章artifact名词的解释可知,被依赖的artifact必须存在于仓库(远程或本地)中,但目前webapp所依赖的app必不存在于仓库中,所以执行只能失败。
解决这个问题有两种方法:[1]将app-1.0.jar安装到仓库中,使它成为一个artifact;[2]构建一个更高层次的工程,使app和webapp成为这个工程的子工程,然后从这个更高层次工程中执行命令。
第一种方法比较简单(见http://www.blogjava.net/jiangshachina/admin/EditPosts.aspx中的第一个主题),此处将详细讨论第2种方法(见5.6节)。
5.6 更高层次工程
我们可以将app和webapp的上一级目录demo作为这两个工程的
……
Downloading: http://repo1.maven.org/maven2/ce/demo/mvn/app/ 1.0/app-1.0 .pom
[ INFO ] ------------------------------------------------------------------------
[ ERROR ] BUILD ERROR
[ INFO ] ------------------------------------------------------------------------
[ INFO ] Error building POM (may not be this project's POM).
Project ID: ce.demo.mvn:app
Reason: Error getting POM for 'ce.demo.mvn:app' from the repository: Error transferring file
ce.demo.mvn:app:pom: 1.0
from the specified remote repositories:
central (http://repo1.maven.org/maven2)
……
< modelVersion > 4.0.0 </ modelVersion >
< groupId > ce.demo </ groupId >
< artifactId > mvn-demo </ artifactId >
< packaging > pom </ packaging >
< version > 1.0 </ version >
< name > CE Maven Demo </ name >
< modules >
< module > app </ module >
< module > webapp </ module >
</ modules >
</ project >
与app和webapp中的POM相比,demo的POM使用了modules项,modules用于声明本工程的子工程,module中的值对应于子工程的artifact名。而且该POM的packaging类型必须为pom。
有了demo工程后,我们只需要在demo目录下执行相关命令就可以了。通过如下命令即可验证:
[1]mvn clean – 消除工程(包括所有子工程)中产生的所有输出。这本文的实例中,实际上是删除target目录。由于之前的操作只有app工程产生了target目录,而webapp并没有,所以将只会删除app工程中的target目录。
[2]mvn package – 将工程制作成相应的包,app工程是作成jar包(app-1.0.jar),webapp工程是作成war包(webapp-1.0.war)。打开webapp-1.0.war包,可以发现app-1.0.jar被放到了WEB-INF的lib目录中。
6 小结
通过以上的叙述与实例,应该可以对Maven有一个粗略的认识了。使用Maven关键是要弄清楚如何写pom.xml文件,就如同使用Ant要会写build.xml文件一样。在POM中可以直接写入Ant的task脚本,也可以调用Ant的build.xml文件(推荐),所以Maven也可以完成Ant的绝大多数工作(但不必安装Ant)。注意:使用Maven就不要再过多的使用Ant脚本。
利用好Maven的继承特性及子工程的关系,可以很好地简化POM文件,并能够构建层次结构良好的工程,有利于工程的维护。
7 参考资源
[1]Maven官方网站. http://maven.apache.org
[2]Maven POM文件参考结构. http://maven.apache.org/ref/current/maven-model/maven.html
[3]Super POM. http://maven.apache.org/guides/introduction/introduction-to-the-pom.html
[4]Maven主要插件的列表. http://maven.apache.org/plugins
[5]Maven基本使用指南. http://maven.apache.org/guides/index.html
[6]Better Build with Maven. http://www.mergere.com/m2book_download.jsp -- 强烈推荐
[7]介绍Maven2. http://www.javaworld.com/javaworld/jw-12-2005 /jw-1205-maven_p.html
[8]揭秘Maven2 POM. http://www.javaworld.com/javaworld/jw-05-2006/jw-0529-maven.html
[9]Maven让事情变得简单. http://www-128.ibm.com/developerworks/cn/java/j-maven
[10]Maven文档集. http://docs.codehaus.org/display/MAVENUSER/Home
[11]有效利用Maven2的站点生成功能. http://www.matrix.org.cn/resource/article/44/44491_Maven2.html
文中例子程序下载:http://www.blogjava.net/files/jiangshachina/maven.rar
与SCM(CVS,SVN...)的结合也比较容易,一般只需要设置scm这个元素就可以了。请参见:
http://maven.apache.org/ref/current/maven-model/maven.html#class_scm
然后再使用maven-scm-plugin
http://maven.apache.org/scm/plugins/
就可以做checkout等等工作了。
最近在写一篇关于Maven的较复杂应用实例的文章,文中会尽量多使用一些插件及其设置,敬请关注 ^_^
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文件如下所示:
< 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 > 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 >
</ plugins >
</ build >
</ project >
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工程是一个普通application工程,它主要负责对数据库操作,如连接数据库、读取数据库的处理。该工程的POM文件完整内容如下所示:
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" >
< parent >
< groupId > mvn.demo </ groupId >
< artifactId > demo </ artifactId >
< version > 1.0-SNAPSHOT </ version >
</ parent >
< modelVersion > 4.0.0 </ modelVersion >
< groupId > mvn.demo </ groupId >
< artifactId > demo-app </ artifactId >
< packaging > jar </ packaging >
< name > Maven Demo Application Project </ name >
< dependencies >
< dependency >
< groupId > com.db4o </ groupId >
< artifactId > db4o-java5 </ artifactId >
</ dependency >
</ dependencies >
< 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 >
<finalName>是工程输出的“产品”的名称,默认为artifaceId-version.packaging。必须注意的是,该设置并不会影响install或deploy到仓库中的artifact的名称,这个名称仍然会是aritfaceId-version.packaging的形式。
<sourceDirectory>是工程Java源代码的目录(即Eclipse工程中的source folder)。默认为src/main/java,此处设置为src/java(这些路径都是相对于pom.xml文件的相对路径)。
<outputDirectory>是工程Java源代码被编码后的class文件的存放目录(即Eclipse工程中的classes folder)。默认为target/classes,此处设置相同的值。
<resources><resource>定义了Java源代码所使用的资源文件的存放目录。默认为src/main/resources,此处设置为src/java,即与Java源文件是同一个目录。这样就需要考虑一个问题:Maven会将所有的源文件当作资源文件拷贝到jar文件中。所以需要在<excludes><exclude>中排除所有.java文件(详见该工程的POM脚本)。
<testSourceDirectory>是工程的Unit测试源代码的存放目录,默认为src/test/java,此处设置为相同的值。
<testOutputDirectory>是工程的Unit测试源代码编码后的class文件后存放目录。默认为target/test-classes,此处设置为相同的值。
<testResources><testResource>定义了Unit测试代码要使用的资源文件的存放目录。默认为src/test/resources,此处设置为src/test/java, 但排除了所有的.java文件(理由请见 <resources><resource> 中的相关说明)。
通过上述设置,就已经拥有了一个定制的工程目录结构。
4 demo-web工程
demo-web工程是一个Web应用工程,它将使用demo-app工程中数据库应用程序去访问db4o数据库文件,将其中的数据查询出来并显示到页面中。该工程的POM完整内容如下所示:
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" >
< parent >
< groupId > mvn.demo </ groupId >
< artifactId > demo </ artifactId >
< version > 1.0-SNAPSHOT </ version >
</ parent >
< modelVersion > 4.0.0 </ modelVersion >
< groupId > mvn.demo </ groupId >
< artifactId > demo-web </ artifactId >
< packaging > war </ packaging >
< name > Maven Demo Web Application Project </ name >
< dependencies >
< dependency >
< groupId > mvn.demo </ groupId >
< artifactId > demo-app </ artifactId >
<version>1.0-SNAPSHOT</version>
</ dependency >
< dependency >
< groupId > javax.servlet </ groupId >
< artifactId > servlet-api </ artifactId >
</ dependency >
< dependency >
< groupId > commons-configuration </ groupId >
< artifactId > commons-configuration </ artifactId >
</ dependency >
</ dependencies >
< build >
< finalName > demo </ 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 >
< 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使用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
根据实际情况,。