Maven实战 -3. Maven使用入门 - 高飞网

3. Maven使用入门

2017-08-07 10:35:02.0

3.1 编写POM

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

    创建一个hello文件夹,在文件夹中新建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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.demo</groupId>
	<artifactId>hello</artifactId>
	<version>1.0-SNAPSHOT</version>
	<name>maven hello world</name>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
</project>

说明:

  1. project元素:是所有pom.xml的根元素,还声明了一些POM相关的命名空间及xsd元素。
  2. modelVersion:指定当前POM模型的版本,对于Maven2及Maven3来说,只能是4.0.0
  3. 坐标元素groupId、artifactId和version。这三个元素定义了一个项目的基本坐标。
  4. groupId元素:定义了项目属于哪个组。一般以公司域名的反写加项目组,如com.googlecode.myapp。
  5. artifactId元素:定义了当前Maven项目在组中唯一的ID。一般可写为工程名
  6. version元素:指定了HelloWorld项目当前的版本——1.0-SNAPSHOT。SNAPSHOT为快照版本,是不稳定版本,在开发和联调期间使用(因为快照版本会隐含地加上时间缀,开发过程中修改接口后版本不用显式升级),去掉SNAPSHOT为稳定版本。

3.2 编写主代码

    maven项目的目录标准要求,源代码放在src/main/java中,测试代码放在src/main/test中。因此我们在src/main/java中创建包目录并新建HelloWorld.java文件。

~/hello/src/main/java/cn/demo

package cn.demo.hello;
public class HelloWorld{
	public String sayHello(){
		return "Hello Maven";
	}

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

注意这里的包名cn.demo.hello正好与pom.xml中的groupId和artifactId相吻合,虽然这不是必须的,但这样更清晰、更加符合逻辑,也方便搜索构建或者Java类。

接下来运行mvn命令:mvn clean compile

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello ---
[INFO] Deleting /home/build/data/demo/hello/target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/build/data/demo/hello/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/build/data/demo/hello/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.477 s
[INFO] Finished at: 2017-08-07T11:03:34+08:00
[INFO] Final Memory: 11M/57M
[INFO] ------------------------------------------------------------------------

    其中,clean告诉Maven清理输出目录target/,compile告诉Maven编译项目主代码,从输出中看到Maven首先执行了clean:clean任务会删除target/目录。默认情况下,Maven构建的所有输出都在target/目录中;接着执行resources:resources任务(未定义项目资源,暂且略过);最后执行compiler:compile任务将项目主代码编译至target/classes目录中。

    上文提到的clean:clean、resources:resources和compiler:compile对应了一些Maven插件及插件目录,如clean:clean是插件clean的clean目标,compiler:compile是compiler插件的compile目标。

3.3 编写测试代码

    由于测试代码依赖于junit,因此要在pom.xml中加入junit依赖,这要使用dependencies和dependency标签。

<?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>cn.demo</groupId>
	<artifactId>hello</artifactId>
	<version>1.0-SNAPSHOT</version>
	<name>maven hello world</name>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.4</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
</project>

    有了dependency的坐标以后,Maven就能从中央仓库(http://repol.maven.org/maven2)中自动下载junit-4.4.jar。上述还有个元素是scope,意为依赖范围,值为test,意为只对测试有效,因此如果在src/main/java主代码中import JUnit,就会造成编译错误。如果不声明依赖范围,默认为compile,该依赖对主代码和测试代码都有效。

    测试代码放在src/test/java下

package cn.demo.hello;
import org.junit.*;
public class HelloWorldTest{
	@Test
	public void sayHello(){
		HelloWorld helloWorld = new HelloWorld();
		String result = helloWorld.sayHello();
		Assert.assertEquals("Hello Maven",result);
	}
}

    一个典型的单元测试包含三个步骤:1.准备测试类及数据;2.执行要测试的行为;3.检查结果。现在运行mvn clean test:

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello ---
[INFO] Deleting /home/build/data/demo/hello/target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/build/data/demo/hello/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/build/data/demo/hello/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/build/data/demo/hello/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/build/data/demo/hello/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello ---
[INFO] Surefire report directory: /home/build/data/demo/hello/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running cn.demo.hello.HelloWorldTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.071 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.512 s
[INFO] Finished at: 2017-08-07T12:24:12+08:00
[INFO] Final Memory: 13M/57M
[INFO] ------------------------------------------------------------------------
    庆幸的是执行成功了,但书上提到过一个错误,即不支持注解@Test。因此需要通过编译插件,显式的指明使用jdk几版本。

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>2.1</version>
			<configuration>
				<source>1.7</source>
				<target>1.7</target>
			</configuration>
		</plugin>
	</plugins>
</build>

3.4 打包和运行

    编译和测试之后,下一步骤就是要打包(package)。默认的打包类型为jar,当然还有其他的如war,zip等。运行命令 mvn clean package

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building maven hello world 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello ---
[INFO] Deleting /home/build/data/demo/hello/target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/build/data/demo/hello/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.1:compile (default-compile) @ hello ---
[INFO] Compiling 1 source file to /home/build/data/demo/hello/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/build/data/demo/hello/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.1:testCompile (default-testCompile) @ hello ---
[INFO] Compiling 1 source file to /home/build/data/demo/hello/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello ---
[INFO] Surefire report directory: /home/build/data/demo/hello/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running cn.demo.hello.HelloWorldTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.049 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello ---
[INFO] Building jar: /home/build/data/demo/hello/target/hello-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.248 s
[INFO] Finished at: 2017-08-07T12:36:56+08:00
[INFO] Final Memory: 15M/57M
[INFO] ------------------------------------------------------------------------
    如果让这个项目被其他项目使用呢?还需要一个安装的步骤:mvn clean install.
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello ---
[INFO] Building jar: /home/build/data/demo/hello/target/hello-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ hello ---
[INFO] Installing /home/build/data/demo/hello/target/hello-1.0-SNAPSHOT.jar to /home/build/.m2/repository/cn/demo/hello/1.0-SNAPSHOT/hello-1.0-SNAPSHOT.jar
[INFO] Installing /home/build/data/demo/hello/pom.xml to /home/build/.m2/repository/cn/demo/hello/1.0-SNAPSHOT/hello-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.228 s
[INFO] Finished at: 2017-08-07T13:50:28+08:00
[INFO] Final Memory: 16M/57M
[INFO] ------------------------------------------------------------------------

    打包之后,又执行了安装任务install:install。任务将输出的jar安装到了Maven仓库中,可以打开相应的文件夹看到hello项目的pom和jar。

-rw-rw-r-- 1 build build 2382 Aug  7 13:50 hello-1.0-SNAPSHOT.jar
-rw-rw-r-- 1 build build 1172 Aug  7 12:34 hello-1.0-SNAPSHOT.pom

    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>cn.demo.hello.HelloWorld</mainClass>
					</transformer>
				</transformers>
				<source>1.7</source>
				<target>1.7</target>
			</configuration>
		</execution>
	</executions>

</plugin>

    在hello-1.0-SNAPSHOT.jar的MATE-INF/MANIFEST.MF中可以看到:

Manifest-Version: 1.0
Build-Jdk: 1.7.0_71
Built-By: build
Created-By: Apache Maven 3.5.0
Main-Class: cn.demo.hello.HelloWorld
Archiver-Version: Plexus Archiver

直接运行:

[build@localhost target]$ java -jar hello-1.0-SNAPSHOT.jar 
Hello Maven

3.5 使用Archetype生成项目骨架

    Maven的约定项目骨架,项目根下有一个pom.xml,主代码放在src/main/java中,测试代码放在src/test/java中。以hello-world项目为例,创建hello-world文件夹,进入目录后,运行(下面的命令适合Maven3,如果是Maven2参考书中的说明)

mvn archetype:generate

选择合适的groupId、atrifactId、version、及包名。即可快速生成项目骨架。

.
└── hello-world
    ├── pom.xml
    └── src
        ├── main
        │   └── java
        │       └── cn
        │           └── demo
        │               └── App.java
        └── test
            └── java
                └── cn
                    └── demo
                        └── AppTest.java


Maven 的41种骨架功能介绍 - _zao123 - 博客园

上一篇:2. Maven安装 10
下一篇:5. 坐标和依赖 51