1 Maven使用

1.1 编写POM

就像Make的Makefile,Ant的build.xml一样,Maven项目的核心是pom.xml。

首先创建一个名为hello-world的文件夹(本书中各章的代码都会对应一个以ch开头的项目),打开该文件夹,新建一个名为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>com.juvenxu.mvnbook</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定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联,譬如你在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的修改。

1.2 编写主代码

项目主代码和测试代码不同,项目的主代码会被打包到最终的构件中(比如jar),而测试代码只在运行测试时用到,不会被打包。默认情况下,Maven假设项目主代码位于src/main/java目录,我们遵循Maven的约定,创建该目录,然后在该目录下创建文件com/juvenxu/mvnbook/helloworld/HelloWorld.java,其内容如下:

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() );
    }
}

关于该Java代码有两点需要注意。首先,在95%以上的情况下,我们应该把项目主代码放到src/main/java/目录下(遵循Maven的约定),而无须额外的配置,Maven会自动搜寻该目录找到项目主代码。其次,该Java类的包名是com.juvenxu.mvnbook.helloworld,这与我们之前在POM中定义的groupId和artifactId相吻合。一般来说,项目中Java类的包都应该基于项目的groupId和artifactId,这样更加清晰,更加符合逻辑,也方便搜索构件或者Java类。 代码编写完毕后,我们使用Maven进行编译,在项目根目录下运行命令 mvn clean compile 即可。

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

1.3 编写测试代码

为了使项目结构保持清晰,主代码与测试代码应该分别位于独立的目录中。3.2节讲过Maven项目中默认的主代码目录是src/main/java,对应地,Maven项目中默认的测试代码目录是src/test/java。因此,在编写测试用例之前,我们先创建该目录。 在Java世界中,由Kent Beck和Erich Gamma建立的JUnit是事实上的单元测试标准。要使用JUnit,我们首先需要为Hello World项目添加一个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/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。

上述POM代码中还有一个值为test的元素scope,scope为依赖范围,若依赖范围为test则表示该依赖只对测试有效,换句话说,测试代码中的import JUnit代码是没有问题的,但是如果我们在主代码中用import JUnit代码,就会造成编译错误。如果不声明依赖范围,那么默认值就是compile,表示该依赖对主代码和测试代码都有效。

配置了测试依赖,接着就可以编写测试类,回顾一下前面的HelloWorld类,现在我们要测试该类的sayHello()方法,检查其返回值是否为“Hello Maven”。在src/test/java目录下创建文件,其内容如代码清单如下:

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 );
    }
}

测试用例编写完毕之后就可以调用Maven执行测试,运行 mvn clean test。

构建在执行compiler:testCompile任务的时候失败了,Maven输出提示我们需要使用-source 5或更高版本以启动注释,也就是代码中JUnit 4的@Test注解。这是Maven初学者常常会遇到的一个问题。由于历史原因,Maven的核心插件之一compiler插件默认只支持编译Java 1.3,因此我们需要配置该插件使其支持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省略了除插件配置以外的其他部分。现在再执行mvn clean test,结果正常。

1.4 打包和运行

将项目进行编译、测试之后,下一个重要步骤就是打包(package)。Hello World的POM中没有指定打包类型,使用默认打包类型jar,我们可以简单地执行命令 mvn clean package 进行打包。
类似地,Maven会在打包之前执行编译、测试等操作。这里我们看到jar:jar任务负责打包,实际上就是jar插件的jar目标将项目主代码打包成一个名为hello-world-1.0-SNAPSHOT.jar的文件,该文件也位于target/输出目录中,它是根据artifact-version.jar规则进行命名的,如有需要,我们还可以使用finalName来自定义该文件的名称。

至此,我们得到了项目的输出,如果有需要的话,就可以复制这个jar文件到其他项目的Classpath中从而使用HelloWorld类。但是,如何才能让其他的Maven项目直接引用这个jar呢?我们还需要一个安装的步骤,执行 mvn clean install:

在打包之后,我们又执行了安装任务install:install,从输出我们看到该任务将项目输出的jar安装到了Maven本地仓库中,我们可以打开相应的文件夹看到Hello World项目的pom和jar。之前讲述JUnit的POM及jar的下载的时候,我们说只有构件被下载到本地仓库后,才能由所有Maven项目使用,这里是同样的道理,只有将Hello World的构件安装到本地仓库之后,其他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。

1.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。

1.6 配合IDE使用

介绍前面Hello World项目的时候,我们并没有涉及IDE,如此简单的一个项目,使用最简单的编辑器也能很快完成,但对于稍微大一些的项目来说,没有IDE就是不可想象的。
可以使用的IDE很多.如Emacs,Eclipse,NetBeans 等等
这部分可以直接参考其他说明文档,其中m2eclipse简单使用也可以参考《Maven实战》

转载自:http://www.cnblogs.com/csophys/archive/2012/05/18/2507926.html

上一篇:《Maven实战》整理一:Maven的安装及配置

下一篇:《Maven实战》整理三:坐标和依赖

2.Maven 使用的更多相关文章

  1. 【分享】标准springMVC+mybatis项目maven搭建最精简教程

    文章由来:公司有个实习同学需要做毕业设计,不会搭建环境,我就代劳了,顺便分享给刚入门的小伙伴,我是自学的JAVA,所以我懂的.... (大图直接观看显示很模糊,请在图片上点击右键然后在新窗口打开看) ...

  2. 理解Maven中的SNAPSHOT版本和正式版本

    Maven中建立的依赖管理方式基本已成为Java语言依赖管理的事实标准,Maven的替代者Gradle也基本沿用了Maven的依赖管理机制.在Maven依赖管理中,唯一标识一个依赖项是由该依赖项的三个 ...

  3. 【微框架】Maven +SpringBoot 集成 阿里大鱼 短信接口详解与Demo

    Maven+springboot+阿里大于短信验证服务 纠结点:Maven库没有sdk,需要解决 Maven打包找不到相关类,需要解决 ps:最近好久没有写点东西了,项目太紧,今天来一篇 一.本文简介 ...

  4. 安装eclipse的maven插件

    我们团队用maven来管理项目需要的库文件,其实以前都没听过maven,第一次接触这个,师兄要我直接去装下这个,开始以为还挺简单的,没想到中间遇到了一些小麻烦,现在把我成功安装maven的过程分享下, ...

  5. MAVEN学习-第一个Maven项目的构建

    MAVEN安装成功之后就可以进行项目的构建和管理了: 为什么要用maven进行项目的构建和管理? 对于初学者来说一个最直接的也是最容易里的优点在于JAR包的管理,相对于以前开发一个项目的时候我们需要用 ...

  6. Maven 代理设置

    在maven的安装目录下 %MAVEN_HOME%/conf/setting.xml 中进行设置 <proxies>    <!-- proxy     | Specificatio ...

  7. spring maven pom.xml设置

    spring pom.xml设置 <?xml version="1.0" encoding="UTF-8"?> <project xmlns= ...

  8. maven依赖查询地址

    http://search.maven.org/#search%7Cga%7C1%7C

  9. maven 中snapshot版本和release版本的区别

    maven中的仓库分为两种,snapshot快照仓库和release发布仓库.snapshot快照仓库用于保存开发过程中的不稳定版本,release正式仓库则是用来保存稳定的发行版本.定义一个组件/模 ...

  10. Maven多模块,Dubbo分布式服务框架,SpringMVC,前后端分离项目,基础搭建,搭建过程出现的问题

    现互联网公司后端架构常用到Spring+SpringMVC+MyBatis,通过Maven来构建.通过学习,我已经掌握了基本的搭建过程,写下基础文章为而后的深入学习奠定基础. 首先说一下这篇文章的主要 ...

随机推荐

  1. iOS开发之Runtime常用示例总结

    经常有小伙伴私下在Q上问一些关于Runtime的东西,问我有没有Runtime的相关博客,之前还真没正儿八经的总结过.之前只是在解析第三方框架源码时,聊过一些用法,也就是这些第三方框架中用到的Runt ...

  2. 关于OpenGL和DX学习的取舍

    大家多知道左右就肯定要与显卡打交道.两大图形图像IPA.OpenGL(图形),DX(图形,声音,键盘控制,网络) OpenGL的兴起可能取决于苹果公司的适用,吸引看大部分开发者适用,它有跨平台的有点. ...

  3. 学习笔记——Java数组

    1.创建一维数组 最简单快捷的方法是:声明的同时为数组分配内存.如: int month[]=new int[12] 也可以先声明再分配内存.如: int month[]; //或int[] mont ...

  4. VUE2.0实现购物车和地址选配功能学习第七节

    第七节 卡片选中,设置默认 1.卡片选中html:<li v-for="(item,index) in filterAddress" v-bind:class="{ ...

  5. Jquery基本用法

    今天下午讲了Jquery的基本用法:在用Jquery方法时,首先要引用Jquery文件: <script src="jquery-1.11.2.min.js">< ...

  6. 3360: [Usaco2004 Jan]算二十四

    3360: [Usaco2004 Jan]算二十四 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6  Solved: 6[Submit][Statu ...

  7. php基础语法(20161021)

    上午: 数据库总结: 1.创建数据库 create database 数据库名称 删除数据库 drop database 数据库名称 2.创建表 create table 表名 ( 列名 类型(长度) ...

  8. Android Fragment 开发(一)

    最近在学习Fragment 的使用,想弄一个在子窗体中调用父的方法,一直报错,终于找到解决方法啦 父窗体名称:MainActivity 父中有一个public的方法show() 子窗体调用: Main ...

  9. CSS3 贝塞尔曲线实现

    cubic-bezier 曲线是 css3 动画的一个重要基石.另一个为 steps (ease 等都是 cubic-bezier 的特殊形式),css3 中的 cubic_bezier 曲线限制了首 ...

  10. Android开发之Bitmap的高效加载

    BitmapFactory类提供了四类方法:decodeFile, decodeResource, decodeStream和decodeByteArray 分别用于支持从文件系统,资源,输入流以及字 ...