2.1 在Windows上安装Maven
2.1.1 检查JDK安装
在安装Maven之前,首先要确认你已经正确安装了JDK。Maven可以运行在JDK 1.4及以上的版本上。本书的所有样例都基于JDK 5及以上版本。打开Windows的命令行,运行如下的命令来检查你的Java安装:
C:\Users\Juven Xu>echo %JAVA_HOME%
C:\Users\Juven Xu>java -version
结果如图2-1所示:
图2-1 Windows中检查Java安装
上述命令首先检查环境变量JAVA_HOME是否指向了正确的JDK目录,接着尝试运行java命令。如果Windows无法执行java命令,或者无法找到JAVA_HOME环境变量。你就需要检查Java是否安装了,或者环境变量是否设置正确。关于环境变量的设置,请参考2.1.3节。
2.1.2 下载Maven
请访问Maven的下载页面:http://maven.apache.org/download.html,其中包含针对不同平台的各种版本的Maven下载文件。对于首次接触Maven的读者来说,推荐使用Maven 3.0,,因此下载apache-maven-3.0-bin.zip。当然,如果你对Maven的源代码感兴趣并想自己构建Maven,还可以下载apache-maven-3.0 -src.zip。该下载页面还提供了md5校验和(checksum)文件和asc数字签名文件,可以用来检验Maven分发包的正确性和安全性。
在本书编写的时候,Maven 2的最新版本是2.2.1,Maven 3基本完全兼容Maven 2,而且较之于Maven 2它性能更好,还有不少功能的改进,如果你之前一直使用Maven 2,现在正犹豫是否要升级,那就大可不必担心了,快点尝试下Maven 3吧!
2.1.3 本地安装
将安装文件解压到你指定的目录中,如:
D:\bin>jar xvf "C:\Users\Juven Xu\Downloads\apache-maven-3.0--bin.zip"
这里的Maven安装目录是D:\bin\apache-maven-3.0,接着需要设置环境变量,将Maven安装配置到操作系统环境中。
打开系统属性面板(桌面上右键单击“我的电脑”→“属性”),点击高级系统设置,再点击环境变量,在系统变量中新建一个变量,变量名为M2_HOME,变量值为Maven的安装目录D:\bin\apache-maven-3.0。点击确定,接着在系统变量中找到一个名为Path的变量,在变量值的末尾加上%M2_HOME%\bin;,注意多个值之间需要有分号隔开,然后点击确定。至此,环境变量设置完成,详细情况如图2-2所示:
图2-2 Windows中系统环境变量配置
这里需要提一下的是Path环境变量,当我们在cmd中输入命令时,Windows首先会在当前目录中寻找可执行文件或脚本,如果没有找到,Windows会接着遍历环境变量Path中定义的路径。由于我们将%M2_HOME%\bin添加到了Path中,而这里%M2_HOME%实际上是引用了我们前面定义的另一个变量,其值是Maven的安装目录。因此,Windows会在执行命令时搜索目录D:\bin\apache-maven-3.0\bin,而mvn执行脚本的位置就是这里。
明白了环境变量的作用,现在打开一个新的cmd窗口(这里强调新的窗口是因为新的环境变量配置需要新的cmd窗口才能生效),运行如下命令检查Maven的安装情况:
C:\Users\Juven Xu>echo %M2_HOME%
C:\Users\Juven Xu>mvn -v
运行结果如图2-3所示:
图2-3 Windows中检查Maven安装
第一条命令echo %M2_HOME%用来检查环境变量M2_HOME是否指向了正确的Maven安装目录;而mvn –version执行了第一条Maven命令,以检查Windows是否能够找到正确的mvn执行脚本。
2.1.4 升级Maven
Maven还比较年轻,更新比较频繁,因此用户往往会需要更新Maven安装以获得更多更酷的新特性,以及避免一些旧的bug。
在Windows上更新Maven非常简便,只需要下载新的Maven安装文件,解压至本地目录,然后更新M2_HOME环境变量便可。例如,假设Maven推出了新版本3.1,我们将其下载然后解压至目录D:\bin\apache-maven-3.1,接着遵照前一节描述的步骤编辑环境变量M2_HOME,更改其值为D:\bin\apache-maven-3.1。至此,更新就完成了。同理,如果你需要使用某一个旧版本的Maven,也只需要编辑M2_HOME环境变量指向旧版本的安装目录。
2.2 在基于Unix的系统上安装Maven
Maven是跨平台的,它可以在任何一种主流的操作系统上运行,本节将介绍如何在基于Unix的系统(包括Linux、Mac OS以及FreeBSD等)上安装Maven。
2.2.1 下载和安装
首先,与在Windows上安装Maven一样,需要检查JAVA_HOME环境变量以及Java命令,细节不再赘述,命令如下:
juven@juven-ubuntu:~$ echo $JAVA_HOME
juven@juven-ubuntu:~$ java –version
运行结果如图2-4所示:
图2-4 Linux中检查Java安装
接着到http://maven.apache.org/download.html下载Maven安装文件,如apache-maven-3.0-bin.tar.gz,然后解压到本地目录:
juven@juven-ubuntu:bin$ tar -xvzf apache-maven-3.0-bin.tar.gz
现在已经创建好了一个Maven安装目录apache-maven-3.0,虽然直接使用该目录配置环境变量之后就能使用Maven了,但这里我更推荐做法是,在安装目录旁平行地创建一个符号链接,以方便日后的升级:
juven@juven-ubuntu:bin$ ln -s apache-maven-3.0 apache-maven
juven@juven-ubuntu:bin$ ls -l
total 4
lrwxrwxrwx 1 juven juven 18 2009-09-20 15:43 apache-maven -> apache-maven-3.0
drwxr-xr-x 6 juven juven 4096 2009-09-20 15:39 apache-maven-3.0
接下来,我们需要设置M2_HOME环境变量指向符号链接apache-maven-,并且把Maven安装目录下的bin/文件夹添加到系统环境变量PATH中去:
juven@juven-ubuntu:bin$ export M2_HOME=/home/juven/bin/apache-maven
juven@juven-ubuntu:bin$ export PATH=$PATH:$M2_HOME/bin
一般来说,需要将这两行命令加入到系统的登录shell脚本中去,以我现在的Ubuntu 8.10为例,编辑~/.bashrc文件,添加这两行命令。这样,每次启动一个终端,这些配置就能自动执行。
至此,安装完成,我们可以运行以下命令检查Maven安装:
juven@juven-ubuntu:bin$ echo $M2_HOME
juven@juven-ubuntu:bin$ mvn –version
运行结果如图2-5所示:
图2-5 Linux中检查Maven安装
2.2.2 升级Maven
在基于Unix的系统上,可以利用符号链接这一工具来简化Maven的升级,不必像在Windows上那样,每次升级都必须更新环境变量。
前一小节中我们提到,解压Maven安装包到本地之后,平行地创建一个符号链接,然后在配置环境变量时引用该符号链接,这样做是为了方便升级。现在,假设我们需要升级到新的Maven 3.1版本,同理,将安装包解压到与前一版本平行的目录下,然后更新符号链接指向3.1版的目录便可:
juven@juven-ubuntu:bin$ rm apache-maven
juven@juven-ubuntu:bin$ ln -s apache-maven-3.1/ apache-maven
juven@juven-ubuntu:bin$ ls -l
total 8
lrwxrwxrwx 1 juven juven 17 2009-09-20 16:13 apache-maven -> apache-maven-3.1 /
drwxr-xr-x 6 juven juven 4096 2009-09-20 15:39 apache-maven-3.0drwxr-xr-x 2 juven juven 4096 2009-09-20 16:09 apache-maven-3.1
同理,可以很方便地切换到Maven的任意一个版本。现在升级完成了,可以运行mvn -v进行检查。
2.3 安装目录分析
本章前面的内容讲述了如何在各种操作系统中安装和升级Maven。现在我们来仔细分析一下Maven的安装文件。
2.3.1 M2_HOME
前面我们讲到设置M2_HOME环境变量指向Maven的安装目录,本书之后所有使用M2_HOME的地方都指代了该安装目录,让我们看一下该目录的结构和内容:
bin
boot
conf
lib
LICENSE.txt
NOTICE.txt
README.txt
- Bin: 该目录包含了mvn运行的脚本,这些脚本用来配置Java命令,准备好classpath和相关的Java系统属性,然后执行Java命令。其中mvn是基于UNIX平台的shell脚本,mvn.bat是基于Windows平台的bat脚本。在命令行输入任何一条mvn命令时,实际上就是在调用这些脚本。该目录还包含了mvnDebug和mvnDebug.bat两个文件,同样,前者是UNIX平台的shell脚本,后者是windows的bat脚本。那么mvn和mvnDebug有什么区别和关系呢?打开文件我们就可以看到,两者基本是一样的,只是mvnDebug多了一条MAVEN_DEBUG_OPTS配置,作用就是在运行Maven时开启debug,以便调试Maven本身。此外,该目录还包含m2.conf文件,这是classworlds的配置文件,稍微会介绍classworlds。
- Boot: 该目录只包含一个文件,以maven 3.0为例,该文件为plexus-classworlds-2.2.3.jar。plexus-classworlds是一个类加载器框架,相对于默认的java类加载器,它提供了更丰富的语法以方便配置,Maven使用该框架加载自己的类库。更多关于classworlds的信息请参考http://classworlds.codehaus.org/。对于一般的Maven用户来说,不必关心该文件。
- Conf: 该目录包含了一个非常重要的文件settings.xml。直接修改该文件,就能在机器上全局地定制Maven的行为。一般情况下,我们更偏向于复制该文件至~/.m2/目录下(这里~表示用户目录),然后修改该文件,在用户范围定制Maven的行为。本书的后面将会多次提到该settings.xml,并逐步分析其中的各个元素。
- Lib: 该目录包含了所有Maven运行时需要的Java类库,Maven本身是分模块开发的,因此用户能看到诸如mavn-core-3.0.jar、maven-model-3.0.jar之类的文件,此外这里还包含一些Maven用到的第三方依赖如common-cli-1.2.jar、google-collection-1.0.jar等等。(对于Maven 2来说,该目录只包含一个如maven-2.2.1-uber.jar的文件原本各为独立JAR文件的Maven模块和第三方类库都被拆解后重新合并到了这个JAR文件中)。可以说,这个lib目录就是真正的Maven。关于该文件,还有一点值得一提的是,用户可以在这个目录中找到Maven内置的超级POM,这一点在8.5小节详细解释。其他: LICENSE.txt记录了Maven使用的软件许可证Apache License Version 2.0; NOTICE.txt记录了Maven包含的第三方软件;而README.txt则包含了Maven的简要介绍,包括安装需求及如何安装的简要指令等等。
2.3.2 ~/.m2
在讲述该小节之前,我们先运行一条简单的命令:mvn help:system。该命令会打印出所有的Java系统属性和环境变量,这些信息对我们日常的编程工作很有帮助。这里暂不解释help:system涉及的语法,运行这条命令的目的是为了让Maven执行一个真正的任务。我们可以从命令行输出看到Maven会下载maven-help-plugin,包括pom文件和jar文件。这些文件都被下载到了Maven本地仓库中。
现在打开用户目录,比如当前的用户目录是C:\Users\Juven Xu\,你可以在Vista和Windows7中找到类似的用户目录。如果是更早版本的Windows,该目录应该类似于C:\Document and Settings\Juven Xu\。在基于Unix的系统上,直接输入cd 回车,就可以转到用户目录。为了方便,本书统一使用符号 ~ 指代用户目录。
在用户目录下,我们可以发现.m2文件夹。默认情况下,该文件夹下放置了Maven本地仓库.m2/repository。所有的Maven构件(artifact)都被存储到该仓库中,以方便重用。我们可以到~/.m2/repository/org/apache/maven/plugins/maven-help-plugins/目录下找到刚才下载的maven-help-plugin的pom文件和jar文件。Maven根据一套规则来确定任何一个构件在仓库中的位置,这一点本书第6章将会详细阐述。由于Maven仓库是通过简单文件系统透明地展示给Maven用户的,有些时候可以绕过Maven直接查看或修改仓库文件,在遇到疑难问题时,这往往十分有用。
默认情况下,~/.m2目录下除了repository仓库之外就没有其他目录和文件了,不过大多数Maven用户需要复制M2_HOME/conf/settings.xml文件到~/.m2/settings.xml。这是一条最佳实践,我们将在本章最后一小节详细解释。
2.4 设置HTTP代理
有时候你所在的公司由于安全因素考虑,要求你使用通过安全认证的代理访问因特网。这种情况下,就需要为Maven配置HTTP代理,才能让它正常访问外部仓库,以下载所需要的资源。
首先确认自己无法直接访问公共的Maven中央仓库,直接运行命令ping repo1.maven.org可以检查网络。如果真的需要代理,先检查一下代理服务器是否畅通,比如现在有一个IP地址为218.14.227.197,端口为3128的代理服务,我们可以运行telnet 218.14.227.197 3128来检测该地址的该端口是否畅通。如果得到出错信息,需要先获取正确的代理服务信息;如果telnet连接正确,则输入ctrl+],然后q,回车,退出即可。
检查完毕之后,编辑~/.m2/settings.xml文件(如果没有该文件,则复制$M2_HOME/conf/settings.xml)。添加代理配置如下:
<settings>
…
<proxies>
<proxy>
<id>my-proxy</id>
<active>true</active>
<protocol>http</protocol>
<host>218.14.227.197</host>
<port>3128</port>
<!--
<username>***</username>
<password>***</password>
<nonProxyHosts>repository.mycom.com|*.google.com</nonProxyHosts>
-->
</proxy>
</proxies>
…
</settings>
这段配置十分简单,proxies下可以有多个proxy元素,如果你声明了多个proxy元素,则默认情况下第一个被激活的proxy会生效。这里声明了一个id为my-proxy的代理,active的值为true表示激活该代理,protocol表示使用的代理协议,这里是http。当然,最重要的是指定正确的主机名(host元素)和端口(port元素)。上述XML配置中我注释掉了username、password、nonProxyHost几个元素,当你的代理服务需要认证时,就需要配置username和password。nonProxyHost元素用来指定哪些主机名不需要代理,可以使用 |符号来分隔多个主机名。此外,该配置也支持通配符,如*.google.com表示所有以google.com结尾的域名访问都不要通过代理。
2.5 安装m2eclipse
Eclipse是一款非常优秀的IDE。除了基本的语法标亮、代码补齐、XML编辑等基本功能外,最新版的Eclipse还能很好地支持重构,并且集成了JUnit、CVS、Mylyn等各种流行工具。可惜Eclipse默认没有集成对Maven的支持。幸运的是,由Maven之父Jason Van Zyl创立的Sonatype公司建立了m2eclipse项目,这是Eclipse下的一款十分强大的Maven插件,可以访问http://m2eclipse.sonatype.org/ 了解更多该项目的信息。
本小节将先介绍如何安装m2eclipse插件,本书后续的章节会逐步介绍m2eclipse插件的使用。
现在我以Eclipse 3.6为例逐步讲解m2eclipse的安装。启动Eclipse之后,在菜单栏中选择Help,然后选择Install New Software…,接着你会看到一个Install对话框,点击Work with:字段边上的Add按钮,你会得到一个新的Add Repository对话框,在Name字段中输入m2e,Location字段中输入http://m2eclipse.sonatype.org/sites/m2e,然后点击OK。Eclipse会下载m2eclipse安装站点上的资源信息。等待资源载入完成之后,我们再将其全部展开,就能看到图2-6所示的界面:
图2-6 m2eclipse的核心安装资源列表
如图显示了m2eclipse的核心模块Maven Integration for Eclipse (Required),选择后点击Next >,Eclipse会自动计算模块间依赖,然后给出一个将被安装的模块列表,确认无误后,继续点击Next >,这时我们会看到许可证信息,m2eclipse使用的开源许可证是Eclipse Public License v1.0,选择I accept the terms of the license agreements,然后点击Finish,接着就耐心等待Eclipse下载安装这些模块,如图2-7所示:
图2-7:m2eclipse安装进度
除了核心组件之外,m2eclipse还提供了一组额外组件,主要是为了方便与其它工具如Subversion进行集成,这些组件的安装地址为http://m2eclipse.sonatype.org/sites/m2e-extras。使用前面类似的安装方法,我们可以看到如图2-8的组件列表:
图2-8:m2eclipse的额外组件安装资源列表
下面简单解释一下这些组件的用途:
1. 重要的
- Maven SCM handler for Subclipse (Optional):Subversion是非常流行的版本管理工具,该模块能够帮助我们直接从Subversion服务器签出Maven项目,不过前提是需要首先安装Subclipse(http://subclipse.tigris.org/)。
- Maven SCM Integration (Optional):Eclipse环境中Maven与SCM集成核心的模块,它利用各种SCM工具如SVN实现Maven项目的签出和具体化等操作。
2. 不重要的
- Maven issue tracking configurator for Mylyn 3.x (Optional):该模块能够帮助我们使用POM中的缺陷跟踪系统信息连接Mylyn至服务器。
- Maven SCM handler for Team/CVS (Optional):该模块帮助我们从CVS服务器签出Maven项目,如果你还在使用CVS,就需要安装它。
- Maven Integration for WTP (Optional):使用该模块可以让Eclipse自动读取POM信息并配置WTP项目。、
- M2eclipse Extensions Development Support (Optional):用来支持扩展m2eclipse,一般用户不会用到。
- Project configurators for commonly used maven plugins (temporary):一个临时的组件,用来支持一些Maven插件与Eclipse的集成,建议安装。
读者可以根据自己的需要安装相应组件,具体步骤不再赘述。
待安装完毕后,重启Eclipse,现在让我们验证一下m2eclipse是否正确安装了。首先,点击菜单栏中的Help,然后选择About Eclipse,在弹出的对话框中,点击Installation Details按钮,会得到一个对话框,在Installed Software标签栏中,检查刚才我们选择的模块是否在这个列表中,如图2-9所示:
图2-9m2eclipse安装结果
如果一切没问题,我们再检查一下Eclipse现在是否已经支持创建Maven项目,依次点击菜单栏中的File→New→Other,在弹出的对话框中,找到Maven一项,再将其展开,你应该能够看到如图2-10所示的对话框:
图2-10 Eclipse中创建Maven项目向导
如果一切正常,说明m2eclipse已经正确安装了。
最后,关于m2eclipse的安装,需要提醒的一点是,你可能会在使用m2eclipse时遇到类似这样的错误:
09-10-6 上午01时14分49秒: Eclipse is running in a JRE, but a JDK is required
Some Maven plugins may not work when importing projects or updating source folders.
这是因为Eclipse默认是运行在JRE上的,而m2eclipse的一些功能要求使用JDK,解决方法是配置Eclipse安装目录的eclipse.ini文件,添加vm配置指向JDK,如:
--launcher.XXMaxPermSize
256m
-vm
D:\java\jdk1.6.0_07\bin\javaw.exe
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Xms128m
-Xmx256m
2.6 安装NetBeans Maven插件
本小节会先介绍如何在NetBeans上安装Maven插件,后面的章节中还会介绍NetBeans中具体的Maven操作。
首先,如果你正在使用NetBeans 6.7及以上版本,那么Maven插件已经预装了。你可以检查Maven插件安装,点击菜单栏中的工具,接着选择插件,在弹出的插件对话框中选择已安装标签,你应该能够看到Maven插件,如图2-11所示:
图2-11 已安装的NetBeans Maven插件
如果你在使用NetBeans 6.7之前的版本,或者由于某些原因NetBeans Maven插件被卸载了,那么你就需要安装NetBeans Maven插件,下面我们以NetBeans 6.1为例,介绍Maven插件的安装。
同样,点击菜单栏中的工具,选择插件,在弹出的插件对话框中选择可用插件标签,接着在右边的搜索框内输入Maven,这时你会在左边的列表中看到一个名为Maven的插件,选择该插件,然后点击下面的安装按钮,如图2-12所示:
图2-12 安装NetBeans Maven插件
接着在随后的对话框中根据提示操作,阅读相关许可证并接受,NetBeans会自动帮我们下载并安装Maven插件,结束之后会提示安装完成,之后再点击插件对话框的已安装标签,就能看到已经激活的Maven插件。
最后,为了确认Maven插件确实已经正确安装了,可以看一下NetBeans是否已经拥有创建Maven项目的相关菜单。在菜单栏中选择文件,然后选择新建项目,这时应该能够看到项目类别中有Maven一项,选择该类别,右边会相应地显示Maven项目和基于现有POM的Maven项目,如图2-13所示:
图2-13 NetBeans中创建Maven项目向导
如果你能看到类似的对话框,说明NetBeans Maven已经正确安装了。
2.7 Maven安装最佳实践
本节介绍一些在安装Maven过程中不是必须的,但十分有用的实践。
2.7.1 设置MAVEN_OPTS环境变量
本章前面介绍Maven安装目录时我们了解到,运行mvn命令实际上是执行了Java命令,既然是运行Java,那么运行Java命令可用的参数当然也应该在运行mvn命令时可用。这个时候,MAVEN_OPTS环境变量就能派上用场。
我们通常需要设置MAVEN_OPTS的值为:-Xms128m -Xmx512m,因为Java默认的最大可用内存往往不能够满足Maven运行的需要,比如在项目较大时,使用Maven生成项目站点需要占用大量的内存,如果没有该配置,我们很容易得到java.lang.OutOfMemeoryError。因此,一开始就配置该变量是推荐的做法。
关于如何设置环境变量,请参考前面设置M2_HOME环境变量的做法,尽量不要直接修改mvn.bat或者mvn这两个Maven执行脚本文件。因为如果修改了脚本文件,升级Maven时你就不得不再次修改,一来麻烦,二来容易忘记。同理,我们应该尽可能地不去修改任何Maven安装目录下的文件。
2.7.2 配置用户范围settings.xml
Maven用户可以选择配置$M2_HOME/conf/settings.xml或者~/.m2/settings.xml。前者是全局范围的,整台机器上的所有用户都会直接受到该配置的影响,而后者是用户范围的,只有当前用户才会受到该配置的影响。
我们推荐使用用户范围的settings.xml,主要原因是为了避免无意识地影响到系统中的其他用户。当然,如果你有切实的需求,需要统一系统中所有用户的settings.xml配置,当然应该使用全局范围的settings.xml。
除了影响范围这一因素,配置用户范围settings.xml文件还便于Maven升级。直接修改conf目录下的settings.xml会导致Maven升级不便,每次升级到新版本的Maven,都需要复制settings.xml文件,如果使用~/.m2目录下的settings.xml,就不会影响到Maven安装文件,升级时就不需要触动settings.xml文件。
2.7.3 不要使用IDE内嵌的Maven
无论是Eclipse还是NetBeans,当我们集成Maven时,都会安装上一个内嵌的Maven,这个内嵌的Maven通常会比较新,但不一定很稳定,而且往往也会和我们在命令行使用的Maven不是同一个版本。这里有会出现两个潜在的问题:首先,较新版本的Maven存在很多不稳定因素,容易造成一些难以理解的问题;其次,除了IDE,我们也经常还会使用命令行的Maven,如果版本不一致,容易造成构建行为的不一致,这是我们所不希望看到的。因此,我们应该在IDE中配置Maven插件时使用与命令行一致的Maven。
在m2eclipse环境中,点击菜单栏中的Windows,然后选择Preferences,在弹出的对话框中,展开左边的Maven项,选择Installation子项,在右边的面板中,我们能够看到有一个默认的Embedded Maven安装被选中了,点击Add…然后选择我们的Maven安装目录M2_HOME,添加完毕之后选择这一个外部的Maven,如图2-14所示:
图2-14 在Eclipse中使用外部Maven
NetBeans Maven插件默认会侦测PATH环境变量,因此会直接使用与命令行一致的Maven环境。依次点击菜单栏中的工具→选项→其他→Maven标签栏,你就能看到如图2-15所示的配置:
图2-15 在NetBeans中使用外部Maven
2.8 小结
本章详细介绍了在各种操作系统平台上安装Maven,并对Maven安装目录进行了深入的分析,在命令行的基础上,本章又进一步介绍了Maven与主流IDE Eclipse及NetBeans的集成,本章最后还介绍了一些与Maven安装相关的最佳实践。本书下一章会创建一个Hello World项目,带领读者配置和构建Maven项目。
第3章 Maven使用入门
到目前为止,我们已经大概了解并安装好了Maven,现在,我们开始 创建一个最简单的Hello World项目。如果你是初次接触Maven,我建议你按照本章的内容一步步地编写代码并执行,可能你会碰到一些概念暂时难以理解,不用着急,记下这些疑 难点,相信本书的后续章节会帮你逐一解答。
3.1 编写POM
3.2 编写主代码
3.3 编写测试代码
3.4 打包和运行
3.5 使用Archetype生成项目骨架
3.6 m2eclipse简单使用
3.7 NetBeans Maven插件简单使用
3.8 小结
3.1 编写POM
就像Make的Makefile,Ant的build.xml一样,Maven项目的核心是pom.xml。POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。现在我们先为Hello World项目编写一个最简单的pom.xml。
首先创建一个名为hello-world的文件夹(本书中各章的代码都会对应一个以ch开头的项目),打开该文件夹,新建一个名为pom.xml的文件,输入其内容如代码清单3-1:
代码清单3-1:Hello World的POM
- <span style="font-size: small;"><?xml version="1.0" encoding="UTF-8"?>
- <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>
- <groupId>com.juvenxu.mvnbook</groupId>
- <artifactId>hello-world</artifactId>
- <version>1.0-SNAPSHOT</version>
- <name>Maven Hello World Project</name>
- </project>
- </span>
代码的第一行是XML头,指定了该xml文档的版本和编码方式。紧接着是project元素,project是所有pom.xml的根元素,它还声明了一些POM相关的命名空间及xsd元素,虽然这些属性不是必须的,但使用这些属性能够让第三方工具(如IDE中的XML编辑器)帮助我们快速编辑POM。
根元素下的第一个子元素modelVersion指定了当前POM模型的版本,对于Maven2及Maven 3来说,它只能是4.0.0。
这段代码中最重要的是groupId,artifactId和version三行。这三个元素定义了一个项目基本的坐标,在Maven的世界,任何的jar、pom或者war都是以基于这些基本的坐标进行区分的。
groupId定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联,譬如你在googlecode上建立了一个名为myapp的项目,那么groupId就应该是com.googlecode.myapp,如果你的公司是mycom,有一个项目为myapp,那么groupId就应该是com.mycom.myapp。本书中所有的代码都基于groupId com.juvenxu.mvnbook。
artifactId定义了当前Maven项目在组中唯一的ID,我们为这个Hello World项目定义artifactId为hello-world,本书其他章节代码会被分配其他的artifactId。而在前面的groupId为com.googlecode.myapp的例子中,你可能会为不同的子项目(模块)分配artifactId,如:myapp-util、myapp-domain、myapp-web等等。
顾名思义,version指定了Hello World项目当前的版本——1.0-SNAPSHOT。SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定的版本。随着项目的发展,version会不断更新,如升级为1.0、1.1-SNAPSHOT、1.1、2.0等等。本书的6.5小节会详细介绍SNAPSHOT,第13章介绍如何使用Maven管理项目版本的升级发布。
最后一个name元素声明了一个对于用户更为友好的项目名称,虽然这不是必须的,但我还是推荐为每个POM声明name,以方便信息交流。
没有任何实际的Java代码,我们就能够定义一个Maven项目的POM,这体现了Maven的一大优点,它能让项目对象模型最大程度地与实际代码相独立,我们可以称之为解耦,或者正交性,这在很大程度上避免了Java代码和POM代码的相互影响。比如当项目需要升级版本时,只需要修改POM,而不需要更改Java代码;而在POM稳定之后,日常的Java代码开发工作基本不涉及POM的修改。
3.2 编写主代码
项目主代码和测试代码不同,项目的主代码会被打包到最终的构件中(比如jar),而测试代码只在运行测试时用到,不会被打包。默认情况下,Maven假设项目主代码位于src/main/java目录,我们遵循Maven的约定,创建该目录,然后在该目录下创建文件com/juvenxu/mvnbook/helloworld/HelloWorld.java,其内容如代码清单3-2:
代码清单3-2:Hello World的主代码
- <span style="font-size: small;">package com.juvenxu.mvnbook.helloworld;
-
- public class HelloWorld
- {
- public String sayHello()
- {
- return "Hello Maven";
- }
-
- public static void main(String[] args)
- {
- System.out.print( new HelloWorld().sayHello() );
- }
- }
- </span>
这是一个简单的Java类,它有一个sayHello()方法,返回一个String。同时这个类还带有一个main方法,创建一个HelloWorld实例,调用sayHello()方法,并将结果输出到控制台。
关于该Java代码有两点需要注意。首先,在95%以上的情况下,我们应该把项目主代码放到src/main/java/目录下(遵循Maven的约定),而无须额外的配置,Maven会自动搜寻该目录找到项目主代码。其次,该Java类的包名是com.juvenxu.mvnbook.helloworld,这与我们之前在POM中定义的groupId和artifactId相吻合。一般来说,项目中Java类的包都应该基于项目的groupId和artifactId,这样更加清晰,更加符合逻辑,也方便搜索构件或者Java类。
代码编写完毕后,我们使用Maven进行编译,在项目根目录下运行命令 mvn clean compile ,我们会得到如下输出:
- <span style="font-size: small;">[INFO] Scanning for projects...
- [INFO] ------------------------------------------------------------------------
- [INFO] Building Maven Hello World Project
- [INFO] task-segment: [clean, compile]
- [INFO] ------------------------------------------------------------------------
- [INFO] [clean:clean {execution: default-clean}]
- [INFO] Deleting directory D:\code\hello-world\target
- [INFO] [resources:resources {execution: default-resources}]
- [INFO] skip non existing resourceDirectory D: \code\hello-world\src\main\resources
- [INFO] [compiler:compile {execution: default-compile}]
- [INFO] Compiling 1 source file to D: \code\hello-world\target\classes
- [INFO] ------------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- [INFO] ------------------------------------------------------------------------
- [INFO] Total time: 1 second
- [INFO] Finished at: Fri Oct 09 02:08:09 CST 2009
- [INFO] Final Memory: 9M/16M
- [INFO] ------------------------------------------------------------------------
- </span>
clean告诉Maven清理输出目录target/,compile告诉Maven编译项目主代码,从输出中我们看到Maven首先执行了clean:clean任务,删除target/目录,默认情况下Maven构建的所有输出都在target/目录中;接着执行resources:resources任务(未定义项目资源,暂且略过);最后执行compiler:compile任务,将项目主代码编译至target/classes目录(编译好的类为com/juvenxu/mvnbook/helloworld/HelloWorld.Class)。
上文提到的clean:clean、resources:resources,以及compiler:compile对应了一些Maven插件及插件目标,比如clean:clean是clean插件的clean目标,compiler:compile是compiler插件的compile目标,后文会详细讲述Maven插件及其编写方法。
至此,Maven在没有任何额外的配置的情况下就执行了项目的清理和编译任务,接下来,我们编写一些单元测试代码并让Maven执行自动化测试。
3.3 编写测试代码
为了使项目结构保持清晰,主代码与测试代码应该分别位于独立的目录中。3.2节讲过Maven项目中默认的主代码目录是src/main/java,对应地,Maven项目中默认的测试代码目录是src/test/java。因此,在编写测试用例之前,我们先创建该目录。
在Java世界中,由Kent Beck和Erich Gamma建立的JUnit是事实上的单元测试标准。要使用JUnit,我们首先需要为Hello World项目添加一个JUnit依赖,修改项目的POM如代码清单3-3:
代码清单3-3:为Hello World的POM添加依赖
- <?xml version="1.0" encoding="UTF-8"?>
- <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>
- <groupId>com.juvenxu.mvnbook</groupId>
- <artifactId>hello-world</artifactId>
- <version>1.0-SNAPSHOT</version>
- <name>Maven Hello World Project</name>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.7</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- </project>
代码中添加了dependencies元素,该元素下可以包含多个dependency元素以声明项目的依赖,这里我们添加了一个依赖——groupId是junit,artifactId是junit,version是4.7。前面我们提到groupId、artifactId和version是任何一个Maven项目最基本的坐标,JUnit也不例外,有了这段声明,Maven就能够自动下载junit-4.7.jar。也许你会问,Maven从哪里下载这个jar呢?在Maven之前,我们可以去JUnit的官网下载分发包。而现在有了Maven,它会自动访问中央仓库(http://repo1.maven.org/maven2/),下载需要的文件。读者也可以自己访问该仓库,打开路径junit/junit/4.7/,就能看到junit-4.7.pom和junit-4.7.jar。本书第6章会详细介绍Maven仓库及中央仓库。
上述POM代码中还有一个值为test的元素scope,scope为依赖范围,若依赖范围为test则表示该依赖只对测试有效,换句话说,测试代码中的import JUnit代码是没有问题的,但是如果我们在主代码中用import JUnit代码,就会造成编译错误。如果不声明依赖范围,那么默认值就是compile,表示该依赖对主代码和测试代码都有效。
配置了测试依赖,接着就可以编写测试类,回顾一下前面的HelloWorld类,现在我们要测试该类的sayHello()方法,检查其返回值是否为“Hello Maven”。在src/test/java目录下创建文件,其内容如代码清单3-4:
代码清单3-4:Hello World的测试代码
- package com.juvenxu.mvnbook.helloworld;
- import static org.junit.Assert.assertEquals;
- import org.junit.Test;
-
- public class HelloWorldTest
- {
- @Test
- public void testSayHello()
- {
- HelloWorld helloWorld = new HelloWorld();
-
- String result = helloWorld.sayHello();
-
- assertEquals( "Hello Maven", result );
- }
- }
一个典型的单元测试包含三个步骤:一,准备测试类及数据;二,执行要测试的行为;三,检查结果。上述样例中,我们首先初始化了一个要测试的HelloWorld实例,接着执行该实例的sayHello()方法并保存结果到result变量中,最后使用JUnit框架的Assert类检查结果是否为我们期望的”Hello Maven”。在JUnit 3中,约定所有需要执行测试的方法都以test开头,这里我们使用了JUnit 4,但我们仍然遵循这一约定,在JUnit 4中,需要执行的测试方法都应该以@Test 进行标注。
测试用例编写完毕之后就可以调用Maven执行测试,运行 mvn clean test :
- [INFO] Scanning for projects...
- [INFO] ------------------------------------------------------------------------
- [INFO] Building Maven Hello World Project
- [INFO] task-segment: [clean, test]
- [INFO] ------------------------------------------------------------------------
- [INFO] [clean:clean {execution: default-clean}]
- [INFO] Deleting directory D:\git-juven\mvnbook\code\hello-world\target
- [INFO] [resources:resources {execution: default-resources}]
- …
- Downloading: http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.pom
- 1K downloaded (junit-4.7.pom)
- [INFO] [compiler:compile {execution: default-compile}]
- [INFO] Compiling 1 source file to D: \code\hello-world\target\classes
- [INFO] [resources:testResources {execution: default-testResources}]
- …
- Downloading: http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.jar
- 226K downloaded (junit-4.7.jar)
- [INFO] [compiler:testCompile {execution: default-testCompile}]
- [INFO] Compiling 1 source file to D:\ code\hello-world\target\test-classes
- [INFO] ------------------------------------------------------------------------
- [ERROR] BUILD FAILURE
- [INFO] ------------------------------------------------------------------------
- [INFO] Compilation failure
- D:\code\hello-world\src\test\java\com\juvenxu\mvnbook\helloworld\HelloWorldTest.java:[8,5] -source 1.3 中不支持注释
- (请使用 -source 5 或更高版本以启用注释)
- @Test
- [INFO] ------------------------------------------------------------------------
- [INFO] For more information, run Maven with the -e switch
- …
不幸的是构建失败了,不过我们先耐心分析一下这段输出(为了本书的简洁,一些不重要的信息我用省略号略去了)。命令行输入的是mvn clean test,而Maven实际执行的可不止这两个任务,还有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile。暂时我们需要了解的是,在Maven执行测试(test)之前,它会先自动执行项目主资源处理,主代码编译,测试资源处理,测试代码编译等工作,这是Maven生命周期的一个特性,本书后续章节会详细解释Maven的生命周期。
从输出中我们还看到:Maven从中央仓库下载了junit-4.7.pom和junit-4.7.jar这两个文件到本地仓库(~/.m2/repository)中,供所有Maven项目使用。
构建在执行compiler:testCompile任务的时候失败了,Maven输出提示我们需要使用-source 5或更高版本以启动注释,也就是前面提到的JUnit 4的@Test 注解。这是Maven初学者常常会遇到的一个问题。由于历史原因,Maven的核心插件之一compiler插件默认只支持编译Java 1.3,因此我们需要配置该插件使其支持Java 5,见代码清单3-5:
代码清单3-5:配置maven-compiler-plugin支持Java 5
- <project>
- …
- <build>
- <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>
- </build>
- …
- </project>
该POM省略了除插件配置以外的其他部分,我们暂且不去关心插件配置的细节,只需要知道compiler插件支持Java 5的编译。现在再执行mvn clean test,输出如下:
- …
- [INFO] [compiler:testCompile {execution: default-testCompile}]
- [INFO] Compiling 1 source file to D: \code\hello-world\target\test-classes
- [INFO] [surefire:test {execution: default-test}]
- [INFO] Surefire report directory: D:\code\hello-world\target\surefire-reports
- -------------------------------------------------------
- T E S T S
- -------------------------------------------------------
- Running com.juvenxu.mvnbook.helloworld.HelloWorldTest
- Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.055 sec
- Results :
- Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
- [INFO] ------------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- [INFO] ------------------------------------------------------------------------
- …
我们看到compiler:testCompile任务执行成功了,测试代码通过编译之后在target/test-classes下生成了二进制文件,紧接着surefire:test任务运行测试,surefire是Maven世界中负责执行测试的插件,这里它运行测试用例HelloWorldTest,并且输出测试报告,显示一共运行了多少测试,失败了多少,出错了多少,跳过了多少。显然,我们的测试通过了——BUILD SUCCESSFUL。
3.4 打包和运行
将项目进行编译、测试之后,下一个重要步骤就是打包(package)。Hello World的POM中没有指定打包类型,使用默认打包类型jar,我们可以简单地执行命令 mvn clean package 进行打包,可以看到如下输出:
- …
- Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
-
- [INFO] [jar:jar {execution: default-jar}]
- [INFO] Building jar: D:\code\hello-world\target\hello-world-1.0-SNAPSHOT.jar
- [INFO]
- --------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- …
类似地,Maven会在打包之前执行编译、测试等操作。这里我们看到jar:jar任务负责打包,实际上就是jar插件的jar目标将项目主代码打包成一个名为hello-world-1.0-SNAPSHOT.jar的文件,该文件也位于target/输出目录中,它是根据artifact-version.jar规则进行命名的,如有需要,我们还可以使用finalName来自定义该文件的名称,这里暂且不展开,本书后面会详细解释。
至此,我们得到了项目的输出,如果有需要的话,就可以复制这个jar文件到其他项目的Classpath中从而使用HelloWorld类。但是,如何才能让其他的Maven项目直接引用这个jar呢?我们还需要一个安装的步骤,执行 mvn clean install:
- …
- [INFO] [jar:jar {execution: default-jar}]
- [INFO] Building jar: D: \code\hello-world\target\hello-world-1.0-SNAPSHOT.jar
- [INFO] [install:install {execution: default-install}]
- [INFO] Installing D:\code\hello-world\target\hello-world-1.0-SNAPSHOT.jar to C:\Users\juven\.m2\repository\com\juvenxu\mvnbook\hello-world\1.0-SNAPSHOT\hello-world-1.0-SNAPSHOT.jar
- [INFO]
- ------------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- …
在打包之后,我们又执行了安装任务install:install,从输出我们看到该任务将项目输出的jar安装到了Maven本地仓库中,我们可以打开相应的文件夹看到Hello World项目的pom和jar。之前讲述JUnit的POM及jar的下载的时候,我们说只有构件被下载到本地仓库后,才能由所有Maven项目使用,这里是同样的道理,只有将Hello World的构件安装到本地仓库之后,其他Maven项目才能使用它。
我们已经将体验了Maven最主要的命令:mvn clean compile、mvn clean test、mvn clean package、mvn clean install。执行test之前是会先执行compile的,执行package之前是会先执行test的,而类似地,install之前会执行package。我们可以在任何一个Maven项目中执行这些命令,而且我们已经清楚它们是用来做什么的。
到目前为止,我们还没有运行Hello World项目,不要忘了HelloWorld类可是有一个main方法的。默认打包生成的jar是不能够直接运行的,因为带有main方法的类信息不会添加到manifest中(我们可以打开jar文件中的META-INF/MANIFEST.MF文件,将无法看到Main-Class一行)。为了生成可执行的jar文件,我们需要借助maven-shade-plugin,配置该插件如下:
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-shade-plugin</artifactId>
- <version>1.2.1</version>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>shade</goal>
- </goals>
- <configuration>
- <transformers>
- <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.juvenxu.mvnbook.helloworld.HelloWorld</mainClass>
- </transformer>
- </transformers>
- </configuration>
- </execution>
- </executions>
- </plugin>
plugin元素在POM中的相对位置应该在<project><build><plugins>下面。我们配置了mainClass为com.juvenxu.mvnbook.helloworld.HelloWorld,项目在打包时会将该信息放到MANIFEST中。现在执行 mvn clean install ,待构建完成之后打开target/目录,我们可以看到hello-world-1.0-SNAPSHOT.jar和original-hello-world-1.0-SNAPSHOT.jar,前者是带有Main-Class信息的可运行jar,后者是原始的jar,打开hello-world-1.0-SNAPSHOT.jar的META-INF/MANIFEST.MF,可以看到它包含这样一行信息:
Main-Class: com.juvenxu.mvnbook.helloworld.HelloWorld
现在,我们在项目根目录中执行该jar文件:
D: \code\hello-world>java -jar target\hello-world-1.0-SNAPSHOT.jar
Hello Maven
控制台输出为Hello Maven,这正是我们所期望的。
本小节介绍了Hello World项目,侧重点是Maven而非Java代码本身,介绍了POM、Maven项目结构、以及如何编译、测试、打包,等等。
3.5 使用Archetype生成项目骨架
Hello World项目中有一些Maven的约定:在项目的根目录中放置pom.xml,在src/main/java目录中放置项目的主代码,在src/test/java中放置项目的测试代码。我之所以一步一步地展示这些步骤,是为了能让可能是Maven初学者的你得到最实际的感受。我们称这些基本的目录结构和pom.xml文件内容称为项目的骨架,当你第一次创建项目骨架的时候,你还会饶有兴趣地去体会这些默认约定背后的思想,第二次,第三次,你也许还会满意自己的熟练程度,但第四、第五次做同样的事情,就会让程序员恼火了,为此Maven提供了Archetype以帮助我们快速勾勒出项目骨架。
还是以Hello World为例,我们使用maven archetype来创建该项目的骨架,离开当前的Maven项目目录。
如果是Maven 3,简单的运行:
mvn archetype:generate
如果是Maven 2,最好运行如下命令:
mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-5:generate
很多资料会让你直接使用更为简单的 mvn archetype:generate 命令,但在Maven2中这是不安全的,因为该命令没有指定archetype插件的版本,于是Maven会自动去下载最新的版本,进而可能得到不稳定的SNAPSHOT版本,导致运行失败。然而在Maven 3中,即使用户没有指定版本,Maven也只会解析最新的稳定版本,因此这是安全的,具体内容见7.7小节。
我们实际上是在运行插件maven-archetype-plugin,注意冒号的分隔,其格式为 groupId:artifactId:version:goal ,org.apache.maven.plugins 是maven官方插件的groupId,maven-archetype-plugin 是archetype插件的artifactId,2.0-alpha-5 是目前该插件最新的稳定版,generate是我们要使用的插件目标。
紧接着我们会看到一段长长的输出,有很多可用的archetype供我们选择,包括著名的Appfuse项目的archetype,JPA项目的archetype等等。每一个archetype前面都会对应有一个编号,同时命令行会提示一个默认的编号,其对应的archetype为maven-archetype-quickstart,我们直接回车以选择该archetype,紧接着Maven会提示我们输入要创建项目的groupId、artifactId、 version、以及包名package,如下输入并确认:
- Define value for groupId: : com.juvenxu.mvnbook
- Define value for artifactId: : hello-world
- Define value for version: 1.0-SNAPSHOT: :
- Define value for package: com.juvenxu.mvnbook: : com.juvenxu.mvnbook.helloworld
- Confirm properties configuration:
- groupId: com.juvenxu.mvnbook
- artifactId: hello-world
- version: 1.0-SNAPSHOT
- package: com.juvenxu.mvnbook.helloworld
- Y: : Y
Archetype插件将根据我们提供的信息创建项目骨架。在当前目录下,Archetype插件会创建一个名为hello-world(我们定义的artifactId)的子目录,从中可以看到项目的基本结构:基本的pom.xml已经被创建,里面包含了必要的信息以及一个junit依赖;主代码目录src/main/java已经被创建,在该目录下还有一个Java类com.juvenxu.mvnbook.helloworld.App,注意这里使用到了我们刚才定义的包名,而这个类也仅仅只有一个简单的输出Hello World!的main方法;测试代码目录src/test/java也被创建好了,并且包含了一个测试用例com.juvenxu.mvnbook.helloworld.AppTest。
Archetype可以帮助我们迅速地构建起项目的骨架,在前面的例子中,我们完全可以在Archetype生成的骨架的基础上开发Hello World项目以节省我们大量时间。
此外,我们这里仅仅是看到了一个最简单的archetype,如果你有很多项目拥有类似的自定义项目结构以及配置文件,你完全可以一劳永逸地开发自己的archetype,然后在这些项目中使用自定义的archetype来快速生成项目骨架,本书后面的章节会详细阐述如何开发Maven Archetype。
3.6 m2eclipse简单使用
介绍前面Hello World项目的时候,我们并没有涉及IDE,如此简单的一个项目,使用最简单的编辑器也能很快完成,但对于稍微大一些的项目来说,没有IDE就是不可想象的,本节我们先介绍m2eclipse的基本使用。
3.6.1 导入Maven项目
第2章介绍了如何安装m2eclipse,现在,我们使用m2ecilpse导入Hello World项目。选择菜单项File,然后选择Import,我们会看到一个Import对话框,在该对话框中选择General目录下的Maven Projects,然后点击Next,就会出现Import Projects对话框,在该对话框中点击Browse…选择Hello World的根目录(即包含pom.xml文件的那个目录),这时对话框中的Projects:部分就会显示该目录包含的Maven项目,如图3-1所示:
图3-1 在Eclipse中导入Maven项目
点击Finish之后,m2ecilpse就会将该项目导入到当前的workspace中,导入完成之后,我们就可以在Package Explorer视图中看到如图3-2所示的项目结构:
图3-2 Eclipse中导入的Maven项目结构
我们看到主代码目录src/main/java和测试代码目录src/test/java成了Eclipse中的资源目录,包和类的结构也十分清晰,当然pom.xml永远在项目的根目录下,而从这个视图中我们甚至还能看到项目的依赖junit-4.7.jar,其实际的位置指向了Maven本地仓库(这里我自定义了Maven本地仓库地址为D:\java\repository,后续章节会介绍如何自定义本地仓库位置)。
3.6.2 创建Maven项目
创建一个Maven项目也十分简单,选择菜单项File -> New -> Other,在弹出的对话框中选择Maven下的Maven Project,然后点击Next >,在弹出的New Maven Project对话框中,我们使用默认的选项(不要选择Create a simple project选项,那样我们就能使用Maven Archetype),点击Next >,此时m2eclipse会提示我们选择一个Archetype,我们选择maven-archetype-quickstart,再点击Next >。由于m2eclipse实际上是在使用maven-archetype-plugin插件创建项目,因此这个步骤与上一节我们使用archetype创建项目骨架类似,输入groupId,、artifactId、version、package(暂时我们不考虑Properties),如图3-3所示:
图3-3 在Eclipse中使用Archetype创建项目
注意,为了不和前面已导入的Hello World项目产生冲突和混淆,我们使用不同的artifactId和package。OK,点击Finish,Maven项目就创建完成了,其结构与前一个已导入的Hello World项目基本一致。
3.6.3 运行mvn命令
我们需要在命令行输入如mvn clean install之类的命令来执行maven构建,m2eclipse中也有对应的功能,在Maven项目或者pom.xml上右击,再选择Run As,就能看到如下的常见Maven命令,如图3-4所示:
图3-4 在Eclipse中运行默认mvn命令
选择想要执行的Maven命令就能执行相应的构建,同时我们也能在Eclipse的console中看到构建输出。这里常见的一个问题是,默认选项中没有我们想要执行的Maven命令怎么办?比如,默认带有mvn test,但我们想执行mvn clean test,很简单,选择Maven buid… 以自定义Maven运行命令,在弹出对话框中的Goals一项中输入我们想要执行的命令,如clean test,设置一下Name,点击Run即可。并且,下一次我们选择Maven build,或者使用快捷键Alt + Shift + X, M快速执行Maven构建的时候,上次的配置直接就能在历史记录中找到。图3-5就是自定义Maven运行命令的界面:
图3-5 在Eclipse中自定义mvn命令
3.7 NetBeans Maven插件简单使用
NetBeans的Maven插件也十分简单易用,我们可以轻松地在NetBeans中导入现有的Maven项目,或者使用Archetype创建Maven项目,我们也能够在NetBeans中直接运行mvn命令。
3.7.1 打开Maven项目
与其说打开Maven项目,不如称之为导入更为合适,因为这个项目不需要是NetBeans创建的Maven项目,不过这里我们还是遵照NetBeans菜单中使用的名称。
选择菜单栏中的文件,然后选择打开项目,直接定位到Hello World项目的根目录,NetBeans会十分智能地识别出Maven项目,如图3-6所示:
图3-6 在NetBeans中导入Maven项目
Maven项目的图标有别于一般的文件夹,点击打开项目后,Hello World项目就会被导入到NetBeans中,在项目视图中可以看到如图3-7所示的项目结构:
图3-7 NetBeans中导入的Maven项目结构
NetBeans中项目主代码目录的名称为源包,测试代码目录成了测试包,编译范围依赖为库,测试范围依赖为测试库,这里我们也能看到pom.xml,NetBeans甚至还帮我们引用了settings.xml。
3.7.2 创建Maven项目
在NetBeans中创建Maven项目同样十分轻松,在菜单栏中选择文件,然后新建项目,在弹出的对话框中,选择项目类别为Maven,项目为Maven项目,点击“下一步”之后,对话框会提示我们选择Maven原型(即Maven Archtype),我们选择Maven快速启动原型(1.0),(即前文提到的maven-archetype-quickstart),点击“下一步”之后,输入项目的基本信息,这些信息在之前讨论archetype及在m2eclipse中创建Maven项目的时候都仔细解释过,不再详述,如图3-8所示:
图3-8 在NetBeans中使用Archetype创建Maven项目
点击完成之后,一个新的Maven项目就创建好了。
3.7.3 运行mvn命令
NetBeans在默认情况下提供两种Maven运行方式,点击菜单栏中的运行,我们可以看到生成项目和清理并生成项目两个选项,我们可以尝试“点击运行Maven构建”,根据NetBeans控制台的输出,我们就能发现它们实际上对应了mvn install和mvn clean install两个命令。
在实际开发过程中,我们往往不会满足于这两种简单的方式,比如,有时候我们只想执行项目的测试,而不需要打包,这时我们就希望能够执行mvn clean test命令,所幸的是NetBeans Maven插件完全支持自定义的mvn命令配置。
在菜单栏中选择工具,接着选择选项,在对话框中,最上面一栏选择其他,下面选择Maven标签栏,在这里我们可以对NetBeans Maven插件进行全局的配置(还记得第2章中我们如何配置NetBeans使用外部Maven么?)。现在,选择倒数第三行的编辑全局定制目标定义…,我们添加一个名为Maven Test的操作,执行目标为clean test,暂时不考虑其他配置选项,如图3-9所示:
图3-9 在NetBeans中自定义mvn命令
点击“缺省保存该配置”,在Maven项目上右击,选择定制,就能看到刚才配置好的Maven运行操作,选择Maven Test之后,终端将执行mvn clean test。值得一提的是,我们也可以在项目上右击,选择定制,再选择目标…再输入想要执行的Maven目标(如clean package),点击确定之后NetBeans就会执行相应的Maven命令。这种方式十分便捷,但这是临时的,该配置不会被保存,也不会有历史记录。
3.8 小结
本章以尽可能简单且详细的方式叙述了一个Hello World项目,重点解释了POM的基本内容、Maven项目的基本结构、以及构建项目基本的Maven命令。在此基础上,还介绍了如何使用 Archetype快速创建项目骨架。最后讲述的是如何在Eclipse和NetBeans中导入、创建及构建Maven项目。