Maven学习使用二

    这一章,学习一个简单的Hello World项目,更加全面的了解Maven。


一、编写POM

        Maven 项目的核心是 pom.xml。POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等。现在我们先为 Hello World项目编写一个最简单的 pom.xml。

        首先创建一个hello-world的文件夹,并在该文件夹中建立一个pom.xml文件,内容如下:

<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.caofanqi.stumvn</groupId>
<artifactId>hello-world</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Maven Hello World Project</name>
</project>

        第一行是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 定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联,如果你的公司是 mycom,有一个项目为 myapp,那么 groupId 就应该是 com.mycom.myapp。

        artifactId:项目的ID,定义了当前 Maven 项目在组中唯一的 ID。

        version 指定了 Hello World 项目当前的版本——1.0-SNAPSHOT。SNAPSHOT 意为快照,说明该项目还处于开发中,是不稳定的版本。随着项目的发展,version 会不断更新升级。

        name元素声明了一个对于用户更为友好的项目名称,这不是必须的,推荐为每个POM声明 name,方便信息交流。


二、编写主代码

        我们按照maven约定的格式创建源码目录

Maven学习使用二_maven

然后在该目录下创建文件com\caofanqi\stumvn\helloworld\HelloWorld.java ,内容如下:

Maven学习使用二_xml_02

package com.caofanqi.stumvn.helloworld;

public class HelloWorld{

public String sayHello(){
return "Hello Maven";
}

public static void main(String[] args){
System.out.print( new HelloWorld().sayHello() );
}
}

        关于该 Java 代码有两点需要注意。首先,在绝大多数情况下,应该把项目主代码放到 src/main/java/目录下(遵循 Maven 的约定),而无须额外的配置,Maven 会自动搜寻该目录找到项目主代码。其次,该 Java 类的包名是 com.caofanqi.stumvn.helloworld,这与之前在 POM 中定义的 groupId 和 artifactId 相吻合。一般来说,项目中 Java 类的包都应该基于项目的 groupId 和 artifactId,这样更加清晰,更加符合逻辑,也方便搜索构件或者 Java 类。

        编写完毕,使用maven进行编译,在项目根目录中执行 mvn clean compile 会得到如下输出

Maven学习使用二_jar_03

clean告诉maven清理输出目录target,compile告诉maven编译项目主代码,从输出中,我们看到maven首先执行了clean任务,删除target目录(第一次执行由于没有target目录,不会打印删除。默认情况下maven构建的所有输出都在target目录中)。接着执行resources任务(没有定义项目资源)。最后执行complie任务,将项目主代码编译到target/classes目录(编译好的类为hello-world\target\classes\com\caofanqi\stumvn\helloworld\HelloWorld.class)

Maven学习使用二_Maven_04


三、编写测试代码

        创建测试代码的目录

Maven学习使用二_maven_05

        要使用JUint,我们先要为项目添加一个JUnit的依赖修改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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.caofanqi.stumvn</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.10</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>

        dependencies 该元素下可以包含多个dependency元素以声明依赖,我们添加了一个groupId为junit,artifactId使junit,version是4.10的依赖。这就可以确定junit项目在maven中的坐标,有了这段声明,maven就能够自动下载junit-4.10.jar。

        scope为依赖范围,若依赖范围为test,表示依赖只对测试有效,也就是说测试代码中使用junit没问题,但是主代码中不能使用。如果不声明依赖的范围,默认是compile,表示依赖对主代码和测试代码都有效。

        编写测试类如下:

package com.caofanqi.stumvn.helloworld;
import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class HelloWorldTest{

@Test
public void testSayHello(){

assertEquals( "Hello Maven", new HelloWorld().sayHello());

}
}

编写完测试用例后,调用maven执行测试,运行 mvn clean test 命令后输出如下:

Maven学习使用二_JUnit_06

        构建成功了,我们输入的命令是 mvn clean test ,但是maven执行的命令不止这两个,还有resources、compile、testResources、testCompile。我们可以了解到,在maven执行test之前,它会自动执行项目主资源处理,主代码编译,测试资源处理,测试代码编译等工作,这是maven声明周期的一个特性,之后我们会学习maven的声明周期。

    从输出中我们还看到maven 从中央仓库下载了junit的pom和jar这两个文件到本地仓库中。

    测试代码通过编译之后在target/test-classes下生成了二进制文件,紧接着maven-surefire-plugin:2.12.4:test 任务运行测试,maven-surefire-plugin 是maven中负责测试的插件,这里它运行测试用例HelloWorld,并输出测试报告,显示一共运行了多少测试,失败了多少,出错了多少,跳过了多少。


四、打包和运行

        将项目进行编译、测试之后,下一个总要的步骤就是打包(package)。我们的POM中没有指定打包类型,会使用默认的打包类型jar,我们使用 mvn clean package 命令进行打包,输出如下:

Maven学习使用二_maven_07

        maven会在打包之前执行编译、测试等操作。这里我们看到maven-jar-plugin:2.4:jar 任务负责打包,实际上就是maven-jar-plugin插件的jar目标将项目主代码打包成为一个名为hello-world-1.0-SNAPSHOT.jar的文件,文件也位于target输出目录中,它是根据artifact-version.jar规则进行命名的,如果需要我们可以使用finalName来自定义文件的名称。

        到这里,我们有了项目的输出,但是如何让其他的maven项目直接引用这个jar呢?我们需要一个安装的步骤,使用 mvn clean install 命令将jar安装到本地仓库。

Maven学习使用二_Maven_08

        在打包之后,又执行了安装任务maven-install-plugin:2.4:install ,从输出中可以看到该任务将项目输出的jar和pom安装到了maven本地仓库中,我们可以打开相应的文件夹看到项目的pom和jar。

Maven学习使用二_maven_09

        只有本地仓库中有项目,我们在maven项目中才可以依赖使用。

        我们已经使用了maven最主要的命令:mvn clean compile、mvn clean test、mvn clean package、mvn clean install。执行test之前会先执行compile,执行package之前会先执行test,执行install之前会执行package。我们可以在任何一个maven项目中执行这些命令。

        但是到目前为止,我们还没有运行项目,HelloWorld类是有一个main方法的。默认打包生成的jar是不能够直接运行的,因为带有main方法的类信息不会添加到manifest中(可以打开 jar 文件中的

META-INF/MANIFEST.MF 文件,将无法看到 Main-Class 一行)

Maven学习使用二_Maven_10

        为了生成可执行的jar文件,需要借助maven-shade-plugin,配置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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.caofanqi.stumvn</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.10</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.caofanqi.stumvn.helloworld.HelloWorld</mainClass>
</transformer>
</transformers>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>

    我们配置了mainClass为com.caofanqi.stumvn.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,可以看到如下信息:

Maven学习使用二_Maven_11

    OK,我们在target目录下执行jar文件:

Maven学习使用二_xml_12

输出了Hello Maven,运行成功!


五、eclipse的使用

        1、导入Hello World项目

File->Import->Existing Maven Projects,然后选择Hello World的根目录(包含pom.xml的那个目录),点击Finish后,eclipse就会将项目导入,项目结构如下:

Maven学习使用二_jar_13

        看到主代码目录src/main/java和测试代码目录src/test/java成了eclipse中的资源目录,包和类的结构也十分清晰,pom.xnl永远在项目根目录下,从这个视图中我们可以看到依赖的junit-4.10.jar,真实的位置指向了maven本地仓库。

    2、使用mvn命令

        在eclipse中我们可以直接在maven项目或者pom.xml上右击->Run As,就能看到如下常见的maven命令:

Maven学习使用二_Maven_14

    选择想要执行的maven命令就能执行相应的构建,同时也可以在eclipse的console中看到构建输出。默认选项中没有我们想要执行的maven命令,比如 mvn clean test ,可以选择Maven build...以自定义Maven运行命令,在弹出对话框中的Goals一项中输入想要执行的命令,如clean test,设置一下Name,点击Run即可。下一次我们可以直接选择Maven build构建。

Maven学习使用二_jar_15


---------------------------------------------------------------------------------------------------------------

源码地址:https://gitee.com/itcaofanqi/CaoFanqiStudyRepository.git   Maven/hello-world

参考:《Maven实战》