使用Maven管理Java项目

630 查看

一、Maven入门

1.下载maven

Maven是基于项目对象模型(Project Object Model),可以通过一小段描述信息来管理项目的构建、报告和文档的项目管理工具,提供了一个仓库的概念,统一管理项目所依赖的第三方jar包,最大可能避免了由于环境变量的不同在不同电脑之间无法运行的问题,Struts2、Hibernate都是采用maven部署的项目。它是Apache软件基金会的一个开源项目,下载地址是:Apache Maven 注意:Maven3.3要求jdk版本为1.7及以上。将压缩包解压到任意目录:可以看到如下的目录结构:

2.配置Maven环境

新建环境变量M2_HOME,其值为maven的解压目录,并在path环境变量中引用M2_HOME下的bin目录:

shellM2_HOME:D:\Program Files (x86)\apache-maven-3.3.3

Path:...;%M2_HOME%\bin

接下来在命令行输入mvn -v命令可以查看版本:

3.使用maven创建helloworld项目

首先创建如下的目录结构

src
    |----main
        |----java
            |----package
    |----test
        |----java
            |----package
    |----resources
pom.xml

main/java目录下创建我们的java源代码:

javapackage org.gpf.maventest01.model;

public class HelloWorld {
    public String sayHelloWorld(){
        return  "Hello World!";
    }   
}

test/java目录下创建我们的测试代码(使用了Junit4测试框架):

javapackage org.gpf.maventest01.model;

import org.junit.*;
import static org.junit.Assert.*;

public class HelloWorldTest {

    @Test
    public void testSayHelloWorld(){
        assertEquals("Hello World!",new HelloWorld().sayHelloWorld());
    }
}

接下来编写pom.xml(可以参见Struts2,如图所示)

将其拷贝到项目的根目录,并修改为如下:

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>  <!-- maven版本,此值固定 -->

    <!-- 项目 -->
    <groupId>org.gpf.maventest01</groupId><!--项目包名-->
    <artifactId>maventest01</artifactId>  <!-- 模块名,建议使用项目名 -->
    <version>0.0.1SNAPSHOT</version>    <!--版本,此处为快照版本-->

    <!-- 依赖 -->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
</project>

接下来在命令行进入我们的项目输入mvn compile命令(首次运行会下载第三方插件和maven依赖的jar,请耐心等待),对该项目进行编译。

最后使用mvn test命令运行我们的测试用例:

此时发现项目的根目录下多了一个target目录,其中class目录就是生成的类文件,reports目录就是一系列测试报告。

运行mvn package命令可以打包我们的项目,会生成maventest-0.0.1SNAPSHOT.jar

二、Maven核心知识

1.常用构建命令

mvn -v 查看maven版本
compile 编译
test 测试
package 打包
clean 删除target(字节码和测试报告)
install 安葬jar包到本地仓库

如果一个项目需要利用到其他项目的jar包,一种方式是拷贝jar包并拷贝到classpath中,maven提供了一个更简单的策略,直接在本地仓库中查找即可。例如我们一个新的项目maven02项目需要使用到之前的maven01项目的HelloWorld类中的sayHelloWorld方法,使用maven可以这样:

  1. 在maven01项目中运行mvn install命令安装jar包到本地仓库。
  2. 创建maven02项目,在其中导入maven01项目的类。

src/main

javapackage org.gpf.maventest02.util;

import org.gpf.maventest01.model.HelloWorld;

public class Speak {
    public String sayHi(){
        return  new HelloWorld().sayHelloWorld();
    }   
}

src/test

javapackage org.gpf.maventest02.util;

import org.junit.*;
import static org.junit.Assert.*;

public class SpeakTest {

    @Test
    public void testSayHi(){
        assertEquals("Hello World!",new Speak().sayHi());
    }
}

3.在pom.xml添加依赖。

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>org.gpf.maventest02</groupId>
    <artifactId>maventest02</artifactId>
    <version>0.0.1SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
        <!-- 添加maven01的jar的依赖,可以从maven01项目的pom.xml中拷贝 -->
        <dependency>
            <groupId>org.gpf.maventest01</groupId>
            <artifactId>maventest01</artifactId>
            <version>0.0.1SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
  1. 使用mvn compile命令编译maven02项目。

2.使用archetype插件自动创建符合maven的目录骨架

  • 方式一:使用mvn archetype:generate根据提示一步步操作;
  • 方式二:使用mvn archetype:generate -D命令一次性生成全部。

3.maven中的坐标和仓库

maven中任何一个依赖、插件都可以被称为构件。所有构件通过坐标作为其唯一标识。

仓库可以管理项目的依赖。仓库可以分为本地仓库和远程仓库,如果本地仓库中找不到就会在远程仓库中查找并下载,如果远程仓库找不到就会报错。maven远程仓库的地址可以在maven安装目录的lib目录的maven-model-builder-3.3.3.jar中找到,如图所示:

pom.xml打开。

镜像仓库

由于maven的中央仓库位于国外,速度慢,也有可能其他原因无法访问,我们可以使用国内的镜像仓库。配置镜像仓库需要修改conf/settings.xml,打开该文件修改mirror标签如下:

xml <mirrors>
    <!-- mirror
     | Specifies a repository mirror site to use instead of a given repository. The repository that
     | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
     | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
     |
    <mirror>
      <id>mirrorId</id>
      <mirrorOf>repositoryId</mirrorOf>
      <name>Human Readable Name for this Mirror.</name>
      <url>http://my.repository.com/repo/path</url>
    </mirror>
     -->
      <mirror>
      <id>maven.net.cn</id>
      <mirrorOf>central</mirrorOf>
      <name>central mirror in china</name>
      <url>http://maven.net.cn/content/groups/public</url>
    </mirror>
  </mirrors>

maven仓库默认是放在用户目录的.m2隐藏目录下的,Windows系统就是C:\Users\用户名\.m2,我们需要将仓库迁移到其他目录,修改conf/settings.xml,如图所示:

settings.xml复制到E:/tmp/mavenproject/repo,这样更新maven就不需要重新配置settings.xml了。

4.在MyEclipse中使用maven

MyEclipse默认安装了maven插件,极大简化了操作。在使用MyEclipse创建项目之前需要进行如下的配置:

  1. 配置maven安装目录(自带的可能有错)

  2. 给jre添加一个运行时参数(错误-Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match.的解决方案)

使用MyEclipse创建Maven项目的步骤(注意选择合适的Junit版本,默认是3.8.1,我们需要该变成4.10)如下:



接下来在MyEclipse中运行maven项目,右键项目名---Run As会出现如下菜单:

在弹出的的对话框的Goals中输入maven命令(compile、test、package等)即可。

5.maven的生命周期和插件

maven有3个独立的阶段。

clean(清理)

  • pre-clean
  • clean
  • post-clean

default(构建、最核心)

  • compile
  • test
  • package
  • install

site(生成项目站点)

  • pre-site
  • site(生成项目的站点文档)
  • post-site
  • site-deploy(发布站点到服务器)

Maven是基于插件的,我们可以在http://maven.apache.org/plugins/index.html找到合适的插件,例如源代码打包插件source插件。

编辑pom.xml,配置source插件(可以参见source插件文档

xml<project>
  ...
  <build>
        <plugins>
        <plugin>
          <!-- 配置插件 -->
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-source-plugin</artifactId>
          <version>2.4</version>
          <!-- 绑定插件到package阶段,如果运行package命令将会打包源代码 -->
          <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>jar-no-fork</goal>
                </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
    ...
<project>

使用clean package命令,运行结果:

6.pom.xml文件解析

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">

  <!-- 指定当前pom的版本 -->
  <modelVersion>4.0.0</modelVersion>

    <!-- 主项目坐标 -->
  <groupId>org.gpf.maventest</groupId> <!-- 域名倒置+项目名,也就是包名 -->
  <artifactId>maventest-demo</artifactId><!-- 项目名+模块名 -->
  <version>0.0.1-SNAPSHOT</version><!-- 版本号(3个数字) 大版本.分支版本.小版本snapshot(快照)|alpha(内测)|beta(公测)|Release(稳定)|GA(正式)-->
  <packaging>jar</packaging><!-- 打包方式,默认是jar,还可以是war、zip、pom -->

    <!-- 项目信息 -->
  <name>maventest-demo</name><!-- 项目描述名 -->
  <url>http://maven.apache.org</url><!-- 项目地址 -->
  <description></description><!-- 项目描述 -->
  <developers></developers><!-- 开发人员列表 -->
  <licenses></licenses><!-- 许可证信息 -->
  <organization></organization><!-- 组织信息 -->

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

    <!-- 依赖列表 -->
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <type></type>
      <scope>test</scope><!-- 依赖范围,只能在test -->
      <optional></optional><!-- 依赖是否可选,默认是false -->
      <exclusions><!-- 排除依赖传递传递列表 -->
        <exclusion></exclusion>
      </exclusions>
    </dependency>
  </dependencies>

    <!-- 依赖管理,定义在父模块中供子模块继承使用 -->
  <dependencyManagement>
    <dependencies>
        <dependency></dependency>
    </dependencies>
  </dependencyManagement>

    <!-- 对构建提供支持 -->
  <build>
    <!-- 插件列表 -->
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <version>2.4</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>jar-no-fork</goal>
                </goals>
            </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <!-- 指定父模块 -->
  <parent></parent>
  <!-- 多模块编译 -->
  <modules>
    <module></module>
  </modules>
</project>

7.依赖范围

maven提供了3种classpath(编译、测试、运行),例如上面的pom.xml的Junit框架的scope属性为test。http://maven.apache.org/guides/introduction/introduction-to-dependency...上提供了6种依赖范围:

  • compile:缺省值,编译、测试都有效
  • provided:编译,测试都有效,但是在运行时并不会加入。例如Servlet API,因为Web容器本身有,如果加入就会出现冲突。
  • runtime:测试、运行有效。
  • test:仅测试时有效。
  • system:与本机相关,可移植性差。
  • import:导入的依赖范围,仅适用在dependencyManager中,表示从其他pom导入dependency配置。

8.依赖传递

创建3个maven项目,grandfather、father、son,其中father依赖grandfather,son又依赖father,他们之间构成依赖。

例如在Father项目的pom.xml中添加对GradFather的依赖,只需要在dependency标签中指定GrandFather的坐标即可,就像下面这样:

xml<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
         <groupId>com.maventest</groupId>
        <artifactId>GrandFather</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>

类似的在Son项目中添加对Father的依赖。现在构建Son需要先构建GrandFather和Father。对GrandFather和Father进行clean install命令,再对Son项目进行compile命令即可。构建完成后3个项目的目录结构如图:

此时发现Son依赖了2个项目GrandFather和Father,如果仅仅希望Son依赖Father可以将GrandFather的坐标进行依赖排除

xml<dependencies>
    <dependency>
        <groupId>com.maventest</groupId>
        <artifactId>Father</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <exclusions>
            <exclusion>
                <groupId>com.maventest</groupId>
                <artifactId>GrandFather</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

9.依赖冲突

依赖冲突有2条原则:

  • 短路优先(优先解析路径短的版本),例如有以下2个依赖:A-->B-->C-->x.jar,A-->D--x.jar(优先)
  • 路径相同,先声明先优先。

10.聚合与继承

如果我们的项目要使用到以上的GrandFather、Father、Son3个模块,就可以使用聚合。新建一个relationship项目,修改其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.maventest</groupId>
  <artifactId>relationship</artifactId>
  <version>0.0.1-SNAPSHOT</version>
<!-- 注意package的值为pom -->
  <packaging>pom</packaging>

  <name>relationship</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

<!-- 导入模块 -->
  <modules>
    <module>../GrandFather</module>
    <module>../Father</module>
    <module>../Son</module>
  </modules>
</project>```

在relationship项目运行`clean install`命令将会依次生成3个jar并加入本地仓库。

在以上的项目中项目中每次都要配置Junit的依赖,我们可以向java编程那样将公共的模块抽取出来,这种方式叫做继承。新建一个maven项目,命名为common,其`pom.xml`配置如下:

```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.maventest.common</groupId>
  <artifactId>common</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>

  <name>common</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <junit-version>3.8.1</junit-version>
  </properties>

<dependencyManagement>
    <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit-version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

</project>

这是项目可能有红色的小叉,由于父模块不需要测试,我们可以删除src/test重新更新maven项目(右键项目-->Maven ForMyEclipse-->Update Project Configuration),发现红色的叉消失。在子模块中我们可以这样使用:

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.maventest</groupId>
  <artifactId>GrandFather</artifactId>
  <version>0.0.2-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>GrandFather</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

<!-- 引入父模块坐标 -->
<parent>
    <groupId>com.maventest.common</groupId>
    <artifactId>common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </dependency>
  </dependencies>
</project>

三、使用Maven建立Web项目

新建一个maven项目,ArcheType选择webapp,如图所示:


pom.xml中配置tomcat插件(可参见Tomcat官方文档)。

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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.maventest.webdemo</groupId>
  <artifactId>webdemo</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>webdemo Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>webdemo</finalName>
    <plugins>
         <plugin>
          <groupId>org.apache.tomcat.maven</groupId>
          <artifactId>tomcat7-maven-plugin</artifactId>
          <version>2.2</version>
        </plugin>
    </plugins>
  </build>
</project>

clean-->package-->部署项目到Tomcat即可。

四、常见问题和解决方案

1.jdk版本不符合的问题

Eclipse中的jdk版本显示为1.5,但是编译使用的版本是1.7,可以参考以下的conf/settings.xml的配置:

xml<profile>
<id>jdk-1.7</id>
<activation> 
<activeByDefault>true</activeByDefault>
<jdk>1.7</jdk> 
</activation>

<properties> 
<maven.compiler.source>1.7</maven.compiler.source> 
<maven.compiler.target>1.7</maven.compiler.target> 
<maven.compiler.compilerVersion>1.7</maven.compiler.compilerVersion> 
</properties> 
</profile>