到目前为止,我们已经大概了解并安装好了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 小结
编写pom.xml文件
就像Make的Makefile,Ant的build.xml一样,Maven项目的核心是pom.xml。POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等等。现在我们先为Hello World项目编写一个最简单的pom.xml。首先创建一个名为hello-world的文件夹,新建一个名为pom.xml的文件,输入如下内容代码:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ymick</groupId>
<artifactId>helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>helloworldmaven</name>
</project>
代码的第一行是XML头,指定了该xml文档的版本和编码方式。紧接着是project元素,project是所有pom.xml的根元素,它还声明了一些 POM相关的命名空间及xsd元素,虽然这些属性不是必须的,但使用这些属性能够让第三方工具(如IDE中的XML编辑器)帮助我们快速编辑POM。这段代码中最重要的是groupId,artifactId和version三行。这三个元素定义了一个项目基本的坐标。在Maven的世界中任何的jar、pom或war都是以基于这些基本的坐标进行区分的。
1、modelVersion指定了当前POM模型的版本,对于Maven2及Maven 3来说,它只能是4.0.0。
2、groupId定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联
3、artifactId定义了当前Maven项目在组中唯一的ID,你可能会为不同的子项目(模块)分配artifactId
4、version指定了Hello World项目当前的版本——1.0-SNAPSHOT。SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定的版本。随着项目的发展,version会不断更新,如升级为1.0、1.1-SNAPSHOT、1.1、2.0等等。与使用Maven管理项目版本的升级发布相关。
5、name元素声明了一个对于用户更为友好的项目名称,虽然这不是必须的,但我还是推荐为每个POM声明name,以方便信息交流。
没有任何实际的Java代码,我们就能够定义一个Maven项目的POM,这体现了Maven的一大优点,它能让项目对象模型最大程度地与实际代码相独立,我们可以称之为解耦或者正交性。这在很大程度上避免了Java代码和POM代码的相互影响。比如当项目需要升级版本时,只需要修改POM,而不需要更改Java代码。而在POM稳定之后,日常的Java代码开发工作基本不涉及POM的修改。别一方面建议项目中JAVA类的包名都以groupId.artifactId为格式进行命名。
编写主代码
项目主代码和测试代码不同,项目的主代码会被打包到最终的构件中(比如jar),而测试代码只在运行测试时用到,不会被打包。默认情况下,Maven假设项目主代码位于src/main/java目录。我们遵循Maven的约定,创建该目录,然后在该目录下创建文件HelloWorld.java,如下:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World !!!");
}
}
Java代码有两点需要注意。首先,在95%以上的情况下,我们应该把项目主代码放到src/main/java/目录下(遵循Maven的约定),而无须额外的配置,Maven会自动搜寻该目录找到项目主代码。其次建议Java类的包名与在POM中定义的groupId和artifactId相吻合,即:groupId.artifactId。一般来说,项目中Java类的包都应该基于项目的groupId和artifactId,这样更加清晰,更加符合逻辑,也方便搜索构件或者Java类。代码编写完毕后,我们使用Maven进行编译,在项目根目录下运行命令 mvn clean compile 即可。注:clean告诉Maven清理输出目录target/。compile告诉Maven编译项目主代码。从输出中我们看到Maven首先执行了clean任务,删除target/目录。默认情况下Maven构建的所有输出都在target/目录中。接着执行resources任务。最后执行compile任务,将项目主代码编译至target/classes目录。
上文提到的clean:clean、resources:resources,compiler:compile对应了一些Maven插件及插件目标,比如clean:clean是clean插件的clean目标,compiler:compile是compiler插件的compile目标,后文会详细讲述Maven插件及其编写方法。至此,Maven在没有任何额外的配置的情况下就执行了项目的清理和编译任务。接下来我们编写一些单元测试代码并让Maven执行自动化测试。
编写测试代码
为了使项目结构保持清晰,主代码与测试代码应该分别位于独立的目录中。Maven项目中默认的主代码目录是src/main/java。Maven项目中默认的测试代码目录是src/test/java。在Java世界中,由Kent Beck和Erich Gamma建立的JUnit是事实上的单元测试标准。要使用JUnit,我们首先需要为HelloWorld项目添加一个JUnit依赖,修改项目的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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ymick</groupId>
<artifactId>helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>helloworldmaven</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。上述POM代码中还有一个值为test的scope元素。scope为依赖范围,若依赖范围为test则表示该依赖只对测试有效。换句话说,测试代码中的import JUnit代码是没有问题的,但是如果我们在主代码中用import JUnit代码,就会造成编译错误。如果不声明依赖范围,那么默认值就是compile,表示该依赖对主代码和测试代码都有效。配置了测试依赖后,接着就可以编写测试类。现在测试该类的sayHello()方法,检查其返回值是否为Hello Maven。在src/test/java目录下创建文件。HelloWorld的测试代码如下:
package com.ymick.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 。
注:命令行输入的是mvn clean test,而Maven实际执行的可不止这两个任务,还有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile。暂时我们需要了解的是,在Maven执行测试(test)之前,它会先自动执行项目主资源处理,主代码编译,测试资源处理,测试代码编译等工作。这是Maven生命周期的一个特性。
注:可能在构建执行compiler:testCompile任务的时候失败了,Maven输出提示我们需要使用-source 5或更高版本以启动注释,也就是前面提到的JUnit 4的@Test注解。这是Maven初学者常常会遇到的一个问题。由于历史原因,Maven的核心插件之一的compiler插件默认只支持编译Java 1.3,因此我们需要配置该插件使其支持Java 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的编译。
compiler:testCompile任务执行成功后可看到,测试代码通过编译之后在target/test-classes下生成了二进制文件,紧接着surefire:test任务运行测试,surefire是Maven世界中负责执行测试的插件,这里它运行测试用例HelloWorldTest,并且输出测试报告,显示一共运行了多少测试,失败了多少,出错了多少,跳过了多少。显然,我们的测试通过了——BUILD SUCCESSFUL。
打包和运行
将项目进行编译、测试之后,下一个重要步骤就是打包(package)。HelloWorld的POM中没有指定打包类型,使用默认打包类型jar,我们可以简单地执行命令 mvn clean package 进行打包。
3.1 编写POM
3.2 编写主代码
3.3 编写测试代码
3.4 打包和运行
3.5 使用Archetype生成项目骨架
3.6 m2eclipse简单使用
3.7 NetBeans Maven插件简单使用
3.8 小结
编写pom.xml文件
就像Make的Makefile,Ant的build.xml一样,Maven项目的核心是pom.xml。POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等等。现在我们先为Hello World项目编写一个最简单的pom.xml。首先创建一个名为hello-world的文件夹,新建一个名为pom.xml的文件,输入如下内容代码:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ymick</groupId>
<artifactId>helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>helloworldmaven</name>
</project>
代码的第一行是XML头,指定了该xml文档的版本和编码方式。紧接着是project元素,project是所有pom.xml的根元素,它还声明了一些 POM相关的命名空间及xsd元素,虽然这些属性不是必须的,但使用这些属性能够让第三方工具(如IDE中的XML编辑器)帮助我们快速编辑POM。这段代码中最重要的是groupId,artifactId和version三行。这三个元素定义了一个项目基本的坐标。在Maven的世界中任何的jar、pom或war都是以基于这些基本的坐标进行区分的。
1、modelVersion指定了当前POM模型的版本,对于Maven2及Maven 3来说,它只能是4.0.0。
2、groupId定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联
3、artifactId定义了当前Maven项目在组中唯一的ID,你可能会为不同的子项目(模块)分配artifactId
4、version指定了Hello World项目当前的版本——1.0-SNAPSHOT。SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定的版本。随着项目的发展,version会不断更新,如升级为1.0、1.1-SNAPSHOT、1.1、2.0等等。与使用Maven管理项目版本的升级发布相关。
5、name元素声明了一个对于用户更为友好的项目名称,虽然这不是必须的,但我还是推荐为每个POM声明name,以方便信息交流。
没有任何实际的Java代码,我们就能够定义一个Maven项目的POM,这体现了Maven的一大优点,它能让项目对象模型最大程度地与实际代码相独立,我们可以称之为解耦或者正交性。这在很大程度上避免了Java代码和POM代码的相互影响。比如当项目需要升级版本时,只需要修改POM,而不需要更改Java代码。而在POM稳定之后,日常的Java代码开发工作基本不涉及POM的修改。别一方面建议项目中JAVA类的包名都以groupId.artifactId为格式进行命名。
编写主代码
项目主代码和测试代码不同,项目的主代码会被打包到最终的构件中(比如jar),而测试代码只在运行测试时用到,不会被打包。默认情况下,Maven假设项目主代码位于src/main/java目录。我们遵循Maven的约定,创建该目录,然后在该目录下创建文件HelloWorld.java,如下:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World !!!");
}
}
Java代码有两点需要注意。首先,在95%以上的情况下,我们应该把项目主代码放到src/main/java/目录下(遵循Maven的约定),而无须额外的配置,Maven会自动搜寻该目录找到项目主代码。其次建议Java类的包名与在POM中定义的groupId和artifactId相吻合,即:groupId.artifactId。一般来说,项目中Java类的包都应该基于项目的groupId和artifactId,这样更加清晰,更加符合逻辑,也方便搜索构件或者Java类。代码编写完毕后,我们使用Maven进行编译,在项目根目录下运行命令 mvn clean compile 即可。注:clean告诉Maven清理输出目录target/。compile告诉Maven编译项目主代码。从输出中我们看到Maven首先执行了clean任务,删除target/目录。默认情况下Maven构建的所有输出都在target/目录中。接着执行resources任务。最后执行compile任务,将项目主代码编译至target/classes目录。
上文提到的clean:clean、resources:resources,compiler:compile对应了一些Maven插件及插件目标,比如clean:clean是clean插件的clean目标,compiler:compile是compiler插件的compile目标,后文会详细讲述Maven插件及其编写方法。至此,Maven在没有任何额外的配置的情况下就执行了项目的清理和编译任务。接下来我们编写一些单元测试代码并让Maven执行自动化测试。
编写测试代码
为了使项目结构保持清晰,主代码与测试代码应该分别位于独立的目录中。Maven项目中默认的主代码目录是src/main/java。Maven项目中默认的测试代码目录是src/test/java。在Java世界中,由Kent Beck和Erich Gamma建立的JUnit是事实上的单元测试标准。要使用JUnit,我们首先需要为HelloWorld项目添加一个JUnit依赖,修改项目的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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ymick</groupId>
<artifactId>helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>helloworldmaven</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。上述POM代码中还有一个值为test的scope元素。scope为依赖范围,若依赖范围为test则表示该依赖只对测试有效。换句话说,测试代码中的import JUnit代码是没有问题的,但是如果我们在主代码中用import JUnit代码,就会造成编译错误。如果不声明依赖范围,那么默认值就是compile,表示该依赖对主代码和测试代码都有效。配置了测试依赖后,接着就可以编写测试类。现在测试该类的sayHello()方法,检查其返回值是否为Hello Maven。在src/test/java目录下创建文件。HelloWorld的测试代码如下:
package com.ymick.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 。
注:命令行输入的是mvn clean test,而Maven实际执行的可不止这两个任务,还有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile。暂时我们需要了解的是,在Maven执行测试(test)之前,它会先自动执行项目主资源处理,主代码编译,测试资源处理,测试代码编译等工作。这是Maven生命周期的一个特性。
注:可能在构建执行compiler:testCompile任务的时候失败了,Maven输出提示我们需要使用-source 5或更高版本以启动注释,也就是前面提到的JUnit 4的@Test注解。这是Maven初学者常常会遇到的一个问题。由于历史原因,Maven的核心插件之一的compiler插件默认只支持编译Java 1.3,因此我们需要配置该插件使其支持Java 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的编译。
compiler:testCompile任务执行成功后可看到,测试代码通过编译之后在target/test-classes下生成了二进制文件,紧接着surefire:test任务运行测试,surefire是Maven世界中负责执行测试的插件,这里它运行测试用例HelloWorldTest,并且输出测试报告,显示一共运行了多少测试,失败了多少,出错了多少,跳过了多少。显然,我们的测试通过了——BUILD SUCCESSFUL。
打包和运行
将项目进行编译、测试之后,下一个重要步骤就是打包(package)。HelloWorld的POM中没有指定打包类型,使用默认打包类型jar,我们可以简单地执行命令 mvn clean package 进行打包。