JavaWeb了解之Maven

目录
  前言
    1. 配置maven环境(MAC)
    2. 核心概念
  1. 手动创建Maven项目(手动搭建目录结构)
  2. 快速生成Maven项目(使用终端命令)
  3. 使用Eclipse/MyEclipse开发Maven项目
  4. 实际开发(多模块/多层)

一个开源的(使用纯Java语言编写,因此跨平台:Windows、Linux、Mac)项目管理工具(自动化构建、依赖管理、项目信息管理、生成文档、创建报告、发布、部署、配置管理),主要用于Java项目,也可用于C#、Ruby、Scala等其他语言编写的项目。

为什么要使用Maven(即:使用Maven的好处):
  1. 自动化构建
    项目的完整构建过程:【清理项目】→【编译项目】→【测试项目】→【生成测试报告】→【打包项目】→【部署项目】
    构建命令如下:
      1. mvn clean命令(清理项目)
        会清除项目根目录下的target目录。
      2. mvn compile命令(编译项目)
        会在项目根目录下生成target目录。
      3. mvn test命令(测试项目)
        执行测试代码。
      4. mvn package(打包项目)
        会在target目录下生成打包好的jar包
      5. mvn install(部署项目)
        默认会将jar包部署在本地Maven仓库
  2. 依赖管理(最大的好处)
    自动下载项目所需要的jar包,并管理jar包之间的依赖关系。
    如果一个Maven构建所产生的构件(如:Jar文件)被其他项目引用,那么该构件就是其他项目的依赖。当Maven项目需要声明某一个依赖时,通常只需要在其pom.xml中配置该依赖的坐标信息,Maven会根据坐标自动将依赖下载到项目中。
  3. 项目信息
    pom.xml文件中包含了:项目描述、SCM 地址、许可证信息、开发者信息 等项目信息。
  4. Mava使用标准的目录结构(明确约定了Java源代码和编译好的代码所放置的目录),只需定义一个pom.xml文件(Maven的核心,存放在项目根目录下,标识项目为Maven项目),然后把源码放到约定的目录中。
    pom.xml文件(位于项目根目录下,3个必填元素:groupId、artifactId、version)
      1. 包含了项目的构建信息:项目的基本信息(组织名、项目名、版本号、开发者、邮件列表)、所依赖的jar包、插件。
      2. 可以被继承,子模块的pom.xml会继承父模块的pom.xml。
      3. 所有的POM均继承自一个父POM(Super POM,包含了一些可以被继承的默认设置:默认目录结构、输出目录、插件、仓库和报表目录)。执行mvn help:effective-pom命令可查看SuperPOM的默认配置和本项目POM的配置。
    约定的目录
      1. src/main/java(java源代码)
      2. src/main/resources(资源文件)   
      3. src/test/java(测试源代码)   
      4. src/test/resources(测试资源文件)
      5. target(打包输出文件)
      6. target/classes(编译输出文件)     

Maven的默认远程仓库

前言

  1. 配置Maven环境(MAC)

官网下载Maven,并解压到Library目录下

Maven框架目录说明:
  1. bin目录
    存放:mvn运行的脚本
  2. boot目录
    存放:plexus-classworlds类加载器框架
  3. conf目录
    存放:settings.xml配置文件
  4. lib目录
    存放:Maven运行时所需要的java类库
  5. LICENSE.txt, NOTICE.txt, README.txt 

配置Maven环境(在终端下执行)
  vim ~/.bash_profile    修改环境变量(路径中不要出现中文)
        export MAVEN_PATH=/Library/maven3.5.3
        export PATH=$PATH:$MAVEN_PATH/bin
  source ~/.bash_profile       保存立刻生效
  mvn -v    查看是否安装成功
  1. 核心概念

Maven是通过仓库对依赖进行管理的,当Maven项目需要某个依赖时(可在Maven的中央仓库中搜索并获取该依赖包的Maven坐标),只要在其pom.xml文件中配置该依赖的Maven坐标信息(即 依赖声明),Maven会根据坐标自动将对应的依赖包下载到本地仓库中并引用。

1. Maven坐标
  在平面几何中,坐标(x,y)可以标识平面中唯一的一个点。在开发中,Maven坐标可以唯一确定一个项目。
  由以下4部分(1、2、3为必填,4为可选)组成:
    1. groupId:组织标识
    2. artifactId:项目名
    3. version:项目的当前版本
      分为2种版本:
        1. SNAPSHOT快照版本(版本号中带有-SNAPSHOT的版本为快照版本,不稳定)
          在不更改版本号的前提下,构建时会从远程仓库上下载最新的快照版本。
          只应该在该依赖为组织内部的项目(正在开发,功能经常更新)时使用(避免了每次发布版本后都要通知组织内其他团队更新版本),当该项目经过完善测试后,需要上线时,应该将项目从快照版本更改为发布版本。如果使用三方依赖(即 组织外部的项目)的快照版本会造成潜在的风险。
          默认情况下对于快照本本的构件,Maven会每天从仓库中获取一次更新,也可以使用mvn clean package -U强制Maven检查更新。
        2. RELEASE稳定版本
          在不更改版本号的前提下,构建时会先从本地仓库查找。
    4. packaging:项目的打包方式(最常见的是:jar---默认、jar、war)
2. 配置项目依赖的jar包(在pom.xml文件的dependency元素中配置该依赖包的Maven坐标信息)
  <dependencies>
    <dependency>
      <groupId>com.sst.cx</groupId>
      <artifactId>hello-maven</artifactId>
      <version>SNAPSHOT-0.0.1</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

说明:
  1. dependencies元素可以有多个dependency子元素,每一个dependency元素对应一个项目所依赖的jar包。
  2. groupId、artifactId、version可以唯一确定所要依赖的jar包。
  3. scope(依赖范围)用来控制依赖和 编译、测试、运行的classpath之间的关系。
    1. compile
      默认依赖范围。对于编译、测试、运行三种classpath都有效。如:log4j。
    2. test
      测试依赖范围。只对于测试classpath有效。如:Junit
    3. provided
      已提供依赖范围。对于编译、测试的classpath有效,但对于运行无效(因为外部容器已经提供)如:servlet-api。
    4. runtime
      运行时依赖范围。对于测试、运行的classpath有效。如:jdbc驱动实现依赖即JDBC-driver(编译时只需JDK提供的jdbc接口)。
    5. system
      系统依赖范围(效果与provided的依赖范围一致)。用于添加非Maven仓库的本地依赖(依赖包为本地jar包时必须设置为system,并添加systemPath元素设置jar包路径)。
      会导致项目的可移植性降低,一般不推荐使用。
    6. import
      导入依赖范围。该依赖范围只能与dependencyManagement元素配合使用才有效,其功能是将目标pom.xml文件中dependencyManagement的配置导入合并到当前pom.xml的dependencyManagement中。
  4. optional:依赖是否可选
  5. type:依赖的类型(默认值:jar,大部分情况下该元素不必声明)
  6. exclusions:用来排除传递性依赖。
  7. 依赖具有传递性(间接依赖):A.jar依赖B.jar,B.jar依赖C.jar(A对于B的依赖为:第一直接依赖,B对于C的依赖为:第二直接依赖),则A.jar也依赖于C.jar。
    通过这种依赖传递关系,会使依赖关系树迅速增长到一个很大的量级,很有可能会出现依赖重复、依赖冲突等情况,可通过以下方式解决:
      1. 依赖范围
        Maven在对项目进行编译、测试、运行时,会分别使用三套不同的classpath。Maven项目构建时,在不同阶段引入到classpath中的依赖是不同的。如:编译(测试/运行)时,会将与编译(测试/运行)相关的依赖引入到编译(测试/运行)classpath 中。
        可以使用pom.xml文件的scope元素(依赖范围)来控制依赖与3套classpath之间的关系。
        传递性依赖的依赖范围受第一直接依赖和第二直接依赖的范围影响(参见下表)规律如下:
          1. 当第二直接依赖的范围是 compile 时,传递性依赖的范围与第一直接依赖的范围一致;
          2. 当第二直接依赖的范围是 test 时,传递性依赖不会被传递;
          3. 当第二直接依赖的范围是 provided 时,只传递第一直接依赖的范围也为 provided 的依赖,且传递性依赖的范围也为 provided;
          4. 当第二直接依赖的范围是 runtime 时,传递性依赖的范围与第一直接依赖的范围一致,但 compile 例外,此时传递性依赖的范围为 runtime。
      2. 依赖调节
        当间接依赖存在重复的多条引入路径时,可通过依赖调节来确定间接依赖的引入路径。
        遵循以下2条原则:
          1. 引入路径短者优先;
            如:A->B->C->D(1.0)、A->X->D(2.0) 只会引入D(2.0)
          2. (路径长度相同的情况下)先声明者优先;
      3. 可选依赖(优先级高于排除依赖)
        在dependency元素中加<optional>true</optional>,默认值为false:表示可以向下传递成为间接依赖。
      4. 排除依赖
        不再包含该间接依赖(使用exclusion元素设置要排除的依赖)。
        若对于同一个间接依赖同时使用排除依赖和可选依赖进行设置,那么可选依赖的取值必须为false,否则排除依赖无法生效。
      5. 【依赖管理】
        子模块可以通过继承获得父模块中声明的全部依赖,可能会引入不必要的依赖,可通过dependencyManagement(通常用于配合继承 或 依赖范围import)进行依赖管理。
        dependencyManagement元素的特性:
          1. 在该元素下声明的依赖不会实际引入到模块中,只有在dependencies元素下同样声明了该依赖,才会引入到模块中。
          2. 该元素能够约束dependencies下依赖的使用(即:dependencies声明的依赖若未指定版本,则使用dependencyManagement中指定的版本,否则将覆盖dependencyManagement中的版本)。
        由于dependencyManagement元素是可以被继承的,因此可以在父模块pom.xml中使用 dependencyManagement元素声明所有子模块的依赖,然后在各个子模块pom.xml中使用dependencies 元素声明实际用到的依赖即可。这样既可以让子模块能够继承父模块的依赖配置,还能避免引入不必要的依赖。

例(导入本地依赖jar包):
        <!-- 外部依赖/本地依赖(其jar包无法从任何仓库中下载) -->
        <dependency>
            <groupId>www.sst.cx</groupId>
            <artifactId>helloMaven</artifactId>
             <!-- 依赖范围 -->
            <scope>system</scope>
            <version>1.0-SNAPSHOT</version>
            <!-- 依赖所在位置 -->
            <systemPath>/Users/cx/maven/helloMaven/target/helloMaven-1.0-SNAPSHOT.jar</systemPath>
        </dependency>
    </dependencies>

例(排除依赖)
    <dependencies>
        <dependency>
            <groupId>www.sst.cx</groupId>
            <artifactId>hello</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <!-- 设置要排除的依赖,无需指定版本 -->
                    <groupId>www.sst.cx</groupId>
                    <artifactId>world</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

例(依赖管理)
    <!-- dependencyManagement标签用于控制子模块的依赖版本等信息(该标签只用来控制版本,不能引入依赖) -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.9</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!-- 声明要引入的依赖 -->
    <dependencies>
        <dependency>
            <!-- dependencyManagement元素中已经定义完整的依赖声明,这里可省略version和scope -->
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>

例(依赖管理---继承)
    父项目
    <packaging>pom</packaging>
    <!-- 
      定义maven变量,可使用${}引用这些变量。
      可将所有依赖的版本信息以Maven变量的形式提取出来,更方便管理。
      可统一项目内依赖的版本,避免版本不一致、降低依赖冲突。
    -->
    <properties>    
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <log4j.version>1.2.17</log4j.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <!-- 引用的properties标签中定义的变量 -->
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    子项目
    <parent>
        <groupId>com.sst.cx</groupId>
        <artifactId>hello</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <dependencies>
        <dependency>
            <!-- 会继承父项目的dependencyManagement,因此这里可省略:版本号、依赖范围 -->
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </dependency>
    </dependencies>

例(import依赖范围)
    <!--定义依赖管理-->
    <dependencyManagement>
        <dependencies>
            <!--导入依赖管理配置-->
            <dependency>
                <groupId>www.sst.cx</groupId>
                <artifactId>Hello</artifactId>
                <version>1.0</version>
                <scope>import</scope>
                <!-- 类型一般为pom -->
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!-- 声明依赖 -->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>
第一直接依赖/第二直接依赖 compile test provided runtime
compile compile - - runtime
test test - - test
provided provided - provided provided
runtime runtime - - runtime
3. Maven仓库(存放依赖、插件的地方)
  用来统一存储所有Maven共享构件(任何一个 依赖、插件、项目构建的输出,都可以称为构件)的位置。每个构件在仓库中的唯一存储路径(根据唯一Maven坐标定义)大致为:groupId/artifactId/version/artifactId-version.packaging。
  项目构建时会加载依赖jar包,会首先从本地仓库中寻找,如果找到则引用,如果没有找到则从Maven中央仓库查找并下载到本地仓库然后引用,如果在中央仓库没有找到,则从pom.xml文件中设置的远程仓库查找并下载到本地仓库然后引用,如果还没有找到则停止构建并报错。

仓库分类
  1. 本地仓库
    每个用户只有一个本地仓库,默认为~/.m2/repository目录(第一次执行mvn命令时创建),~代表的是用户目录
    修改本地仓库的位置:
      maven文件夹|conf文件夹|settings.xml文件的<setting>下+ <localRepository>/Users/cx/Workspaces/repository</localRepository>
    构件只有储存在本地仓库中,才能被其他的 Maven 项目使用。构件想要进入本地仓库,除了从远程仓库下载到本地仓库外,还可以使用命令 mvn install 将本地项目的输出构件安装到本地仓库中。
  2. 远程仓库
    1. 中央仓库(Maven默认的远程仓库,当本地仓库未找到时会首先从中央仓库查找)
      URL地址:http://search.maven.org/。可以在这里搜索需要的三方依赖包。
      该仓库由Maven社区管理、不需要在项目中配置该地址、需要联网。
    2. 私服
      是一种特殊的远程仓库(架设在局域网内的仓库,用来代理所有外部的远程仓库)。可以节省带宽,比外部的远程仓库更加稳定。
      <repositories>
        <repository>
            <id>hello.lib1</id>
            <url>http://内部域名/maven2/lib1</url>
        </repository>
      </repositories>
    3. 其他公共仓库
      如: JBoss Maven 库、Java.net Maven 库

镜像(通常会和私服配合使用)
  如果仓库A提供了仓库B的所有内容,那么仓库A是仓库B的一个镜像(即 仓库B中的任何一个构件都能从它的镜像中获取)。
  国内开发人员由于网络原因,直接从中央仓库下载构件时,速度较慢或不稳定,通常会使用中央仓库的国内镜像站(目前国内使用最多最稳定的中央仓库镜像分别是:阿里云镜像、华为云镜像)来解决该问题(完全屏蔽被镜像仓库,当镜像仓库不稳定或停止服务后不会去被镜像仓库中下载构件)。
  只需要在Maven安装目录下的setting.xml文件中添加mirrors节点(配置镜像的相关信息)。
    <mirror>
        <id>aliyun</id>
        <mirrorOf>central</mirrorOf>
        <name>aliyun</name>
        <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
    <mirror>
        <id>huaweicloud</id>
        <name>mirror from maven huaweicloud</name>
        <mirrorOf>central</mirrorOf>
        <url>https://repo.huaweicloud.com/repository/maven/</url>
    </mirror>
  说明:
    1. id、name、url 分别表示镜像的 唯一标识、名称、地址。
    2. mirrorOf值为central,表示该配置为中央仓库的镜像,所有对于中央仓库的请求都会转到该镜像。
    3. mirrorOf的取值类型有:
      1. *  
        匹配所有远程仓库(所有对于远程仓库的请求都会被拦截,并跳转到 url 元素指定的地址)
      2. external:*
        匹配所有远程仓库,使用 localhost 和 file:// 协议的除外(即 匹配所有不在本机上的远程仓库)。
      3. repo1,repo2
        匹配仓库 repo1 和 repo2。使用逗号分隔多个远程仓库。
      4. *,!repo1
        匹配所有远程仓库,repo1除外。使用感叹号将仓库从匹配中排除。
  与私服配合使用(用户所需的所有构件都能从私服中获取,此时私服就是所有仓库的镜像)
    由于 Maven 私服可以代理所有外部的公共仓库(包括中央仓库),因此对于组织内部的用户来说,使用一个私服就相当于使用了所有需要的外部仓库,这样就可以将配置集中到私服中,简化 Maven 本身的配置。
      <mirror>
        <id>nexus</id>
        <mirrorOf>*</mirrorOf>
        <name>nexus</name>
        <url>http://localhost:8082/nexus/content/groups/sst_repository_group/</url>
      </mirror>
    能够帮助我们建立私服的软件被称为Maven仓库管理器(Repository Manager),主要有以下 3 种: 
      1. Apache Archiva
      2. JFrog Artifactory
      3. Sonatype Nexus(当前最流行)
4. Maven生命周期
  对所有的构建过程(项目清理、初始化、编译、测试、打包、部署、站点生成)进行抽象和统一。
  生命周期是抽象的,其本身不能做任何实际工作,这些实际工作(如:源代码编译)都通过调用Maven插件中的插件目标完成的。
  生命周期中的每个构建过程都可以绑定一个或多个插件目标,且Maven为大多数的构建步骤都绑定了默认的插件(如:针对源代码编译的插件是maven-compiler-plugin、针对集成测试的插件是maven-surefire-plugin等)。

Maven有3套相互独立(可单独或组合使用)的生命周期:
  注意:
    1. 执行某个阶段,该阶段所在生命周期之前的所有阶段都会被运行(如:mvn post-clean会执行 pre-clean、clean、post-clean)。
    2. 相互独立:执行某个生命周期的某个构建阶段时,不会影响其他生命周期。
  1. Clean Lifecycle(在构建之前进行清理工作)共3个阶段。
    1. pre-clean 
      执行一些需要在clean之前完成的工作。
    2. clean 
      移除所有上一次构建生成的文件。
    3. post-clean 
      执行一些需要在clean之后立刻完成的工作。
  2. Default Lifecycle(构建的核心部分:编译、测试、打包、部署等)。
    1. validate
      验证项目是否正确以及所有必要信息是否可用。
    2. initialize
      初始化构建状态。
    3. generate-sources
      生成编译阶段需要的所有源码文件。
    4. process-sources
      处理源码文件(如:过滤某些值)。
    5. generate-resources
      生成项目打包阶段需要的资源文件。
    6. process-resources 
      处理资源文件,并复制至输出目录,为打包阶段做准备。
    7. compile 
      编译项目的源代码到输出目录。
    8. process-classes
      处理编译生成的字节码文件
    9. generate-test-sources
      生成编译阶段需要的测试源代码。
    10. process-test-sources
      处理测试资源,并复制到测试输出目录。
    11. generate-test-resources
      生成项目测试阶段需要的资源文件。
    12. process-test-resources 
      复制并处理测试资源文件,至目标测试目录。
    13. test-compile 
      编译测试源代码到测试输出目录。
    14. process-test-classes
    15. test 
      使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。
    16. prepare-package
      在真正打包之前,执行一些必要的操作。
    17. package 
      将编译好的代码打包成可发布的格式(如:JAR、WAR、EAR)。
    18. pre-integration-test
      在集成测试执行之前,执行所需的操作(如:设置环境变量)。
    19. integration-test
      处理和部署所需的包到集成测试能够运行的环境中。
    20. post-integration-test
      在集成测试被执行后执行必要的操作(如:清理环境)。
    21. verify
      对集成测试的结果进行检查,以保证质量达标。
    22. install 
      将包安装至本地仓库(供其它项目依赖)。
    23. deploy 
      将包复制到远程的仓库(供其它开发者/项目依赖)。
  3. Site Lifecycle(生成项目站点文档、部署站点) 共4个阶段。
    1. pre-site
      执行一些需要在生成站点文档之前完成的工作。
    2. site 
      生成项目的站点文档。
    3. post-site 
      执行一些需要在生成站点文档之后完成的工作,并且为部署做准备。
    4. site-deploy 
      将生成的站点文档部署到特定的服务器上
  可以通过在生命周期的各个阶段定义目标来修改这部分的操作行为。
5. Maven插件(完全依赖Maven的生命周期)
  1. Maven的核心包仅仅定义了抽象的生命周期(并不包含任何Maven插件),具体的任务都是交由插件(以独立构件的形式存在, 只有在Maven需要使用某个插件时,才会去仓库中下载)完成的。
    插件分为2种类型:
      1. Build plugins  
        在项目构建过程中执行(在 pom.xml 中的 build 元素中配置)
      2. Reporting plugins  
        在网站生成过程中执行(在 pom.xml 中的 reporting  元素中配置)
  2.(为了提高代码的复用性)每个插件都能实现多个功能,每个功能就是一个插件目标(即:Maven插件是插件目标的集合)。可以把插件理解为一个类,而插件目标是类中的方法,调用插件目标就能实现对应的功能。在终端调用执行构建阶段的命令时,可以从终端输出中看到都调用了哪些插件目标。
    插件目标的通用写法为 [插件名]:[插件目标名]
      例:maven-compiler-plugin:compile
    执行插件目标的语法为 mvn [插件名]:[目标名]
      例(调用 maven-compiler-plugin 插件的 compile 目标):mvn compiler:compile
  3. 为了完成某个具体的构建任务,Maven的生命周期需要与插件目标相互绑定(如:代码编译任务对应了default生命周期的compile阶段,而maven-compiler-plugin插件的compile目标能够完成这个任务,因此将它们进行绑定就能达到代码编译的目的)。如果多个目标绑定到同一个生命周期阶段,其执行顺序与插件声明顺序一致(先声明的先执行,后声明的后执行)。
    1. 内置绑定
      Maven 默认为一些核心的生命周期阶段绑定了插件目标,当用户调用这些阶段时,对应的插件目标就会自动执行相应的任务。
      1. clean生命周期
        clean绑定了:maven-clean-plugin:clean(清理 Maven 的输出目录)
      2. default生命周期
        process-resources绑定了:maven-resources-plugin:resources(复制资源文件到输出目录)
        compile绑定了:maven-compiler-plugin:compile(编译代码到输出目录)
        process-test-resources 绑定了:maven-resources-plugin:testResources(复制测试资源文件到测试输出目录)
        test-compile绑定了:maven-compiler-plugin:testCompile(编译测试代码到测试输出目录)
        test绑定了:maven-surefire-plugin:test(执行测试用例)
        package绑定了:maven-jar-plugin:jar/maven-jar-plugin:war(创建项目 jar/war 包)
        install绑定了:maven-install-plugin:install(将项目输出的包文件安装到本地仓库)
        deploy绑定了:maven-deploy-plugin:deploy(将项目输出的包文件部署到到远程仓库)
      3. site生命周期
        site绑定了:maven-site-plugin:site(生成项目站点)
        site-deploy绑定了:maven-site-plugin:deploy(部署项目站点)
    2. 自定义绑定
      开发员可以将某个插件目标绑定到Maven生命周期的某个阶段上。
  4.【插件管理】
    使用pluginManagement元素管理插件。和dependencyManagement元素的原理十分相似:在pluginManagement元素中可以声明插件及插件配置,但不会发生实际的插件调用行为,只有在pom.xml中配置了真正的plugin元素,且其groupId和artifactId与pluginManagement元素中配置的插件匹配时,pluginManagement元素的配置才会影响到实际的插件行为。
    应当在父模块中使用pluginManagement元素对所有插件版本进行统一声明(即使各个模块对于同一插件的具体配置不尽相同),避免出现版本冲突或插件不稳定等问题。


例(自定义绑定:将maven-antrun-plugin插件的run目标绑定到Clean Lifecycle的3个阶段,执行mvn post-clean时会在各阶段输出添加的自定义文本信息。该插件也可绑定到Default Lifecycle、Site Lifecycle的构建阶段)
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>maven</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <!-- junit依赖 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>compile</scope>
        </dependency>
        <!-- log4j依赖 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- 添加插件 maven-antrun-plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.1</version>
                <executions>
                    <execution>
                        <!--自定义阶段 id -->
                        <id>www.sst.cx pre-clean</id>
                        <!--阶段 -->
                        <phase>pre-clean</phase>
                        <!--目标 -->
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <!--配置 -->
                        <configuration>
                            <!-- 执行的任务 -->
                            <tasks>
                                <!-- 输出自定义文本信息 -->
                                <echo>预清理阶段,Hello</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <!--自定义阶段 id -->
                        <id>www.sst.cx clean</id>
                        <!--阶段 -->
                        <phase>clean</phase>
                        <!--目标 -->
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <!--配置 -->
                        <configuration>
                            <!-- 执行的任务 -->
                            <tasks>
                                <!-- 输出自定义文本信息 -->
                                <echo>清理阶段,Hello</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <!--自定义阶段 id -->
                        <id>www.sst.cx post-clean</id>
                        <!--阶段 -->
                        <phase>post-clean</phase>
                        <!-- 目标 -->
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <!--配置 -->
                        <configuration>
                            <!-- 执行的任务 -->
                            <tasks>
                                <!-- 输出自定义文本信息 -->
                                <echo>后清理阶段,Hello</echo>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
说明:
  1. 除了插件的坐标信息之外,还通过 executions 元素定义了一些执行配置。executions 下的每一个 executin 子元素都可以用来配置执行一个任务。
  2. id:任务的唯一标识。
  3. phase:插件目标需要绑定的生命周期阶段。
  4. goals:用于指定一组插件目标,其子元素 goal 用于指定一个插件目标。
  5. configuration:该任务的配置,其子元素 tasks 用于指定该插件目标执行的任务。

例(添加maven-site-plugin插件 生成站点)
    <build>
        <plugins>
            <!-- 添加site插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.7.1</version>
            </plugin>
        </plugins>
    </build>
  执行mvn site命令:可生成站点文件(css目录、images目录、一些html文件,用来展示项目信息)并输出到target目录的site目录下。

例(maven-invoker-plugin插件 在本项目构建完成后对其他项目进行构建,无论是否存在依赖关系)
  实现Maven的自动化构建的2种方案
    1. 使用maven-invoker-plugin插件
    2. 使用持续集成(CI)服务器自动管理构建自动化(如:Jenkins)
    <build>
        <plugins>
            <!-- 添加invoker 插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-invoker-plugin</artifactId>
                <version>3.2.2</version>
                <configuration>
                    <debug>true</debug>
                    <!-- 需要构建项目的目录,没有设置pomIncludes元素时表示构建该目录下的所有项目 -->
                    <projectsDirectory>/Users/cx/maven</projectsDirectory>
                    <!-- 指定需要构建项目的pom文件 -->
                    <pomIncludes>
                        <pomInclude>secondMaven/pom.xml</pomInclude>
                        <pomInclude>thirdMaven/pom.xml</pomInclude>
                    </pomIncludes>
                </configuration>
                <executions>
                    <execution>
                        <id>id-integration-test</id>
                        <!-- 执行的目标 -->
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
  执行mvn help:describe -Dplugin=invoker命令可查看maven-invoker-plugin插件绑定的生命周期阶段(integration-test阶段及以后都可以触发该插件)

例(maven-dependency-plugin插件 查看该模块的依赖列表)
  执行插件目标:mvn dependency:list

例(maven-source-plugin插件 将其插件目标 jar-no-fork 绑定到 default 生命周期的 verify 阶段上)
    <!-- 添加插件管理 -->
    <build>
        <pluginManagement>
            <plugins>
                <!-- 声明插件(并没有引入插件,所以不会调用插件目标) -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-source-plugin</artifactId>
                    <version>3.2.1</version>
                    <executions>
                        <!--将 jar-no-fork 目标绑定到 verify 阶段-->
                        <execution>
                            <id>www.sst.cx</id>
                            <phase>verify</phase>
                            <goals>
                                <goal>
                                    jar-no-fork
                                </goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
        <!-- 声明并引入maven-source-plugin插件 -->
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
6. 聚合(用于快速构建项目)
  如果想一次构建多个项目模块,可以创建一个额外的项目(类似父项目,但只有pom.xml文件,没有目录结构)在pom.xml(其packaging打包方式为pom)中使用module元素配置(相对路径)需要构建的其他项目。
  聚合模块在构建时,Maven会先解析聚合模块的pom.xml、分析需要构建的模块,并根据这些模块之间的关系计算出构建顺序,然后根据这个顺序依次构建各个模块。
  <modules>
       <module>../Hello</module>  
       <module>../HelloFriend</module>        
       <module>../MakeFriends</module>
  </modules>
7. 继承(用于消除重复配置)
  把相同的配置(如:grouptId、version等)提取出来作为公共配置放在父项目(其packaging打包类型必须为pom)中,其他子项目再通过继承的方式拥有公共配置。
  <parent>  
    <groupId>com.sst.cx.maven</groupId>
    <artifactId>ParentProject</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <!-- 父模块pom.xml文件的相对路径 -->
    <relativePath>../ParentProject/pom.xml</relativePath>  
  </parent>

可继承的pom元素
  1. groupId    项目组ID
  2. version    项目版本
  3. description    项目的描述信息
  4. organization   项目的组织信息
  5. inceptionYear  项目的创始年份
  6. url    项目的URL地址
  7. developers     项目的开发者信息
  8. contributors   项目的贡献者信息
  9. distributionManagement     项目的部署配置
  10. issueManagement   项目的缺陷跟踪系统信息
  11. ciManagement  项目的持续集成系统信息
  12. scm   项目的版本控制系统信息
  13. mailingLists  项目的邮件列表信息
  14. properties    自定义的Maven属性
  15. dependencies  项目的依赖配置
  16. dependencyManagement  项目的依赖管理配置
  17. repositories  项目的仓库配置
  18. build     包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等
  19. reporting     包括项目的报告输出目录配置、报告插件配置等

例(继承与聚合)
===》1. 父项目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.sst.cx.maven</groupId>
    <artifactId>Parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Parent</name>
    <url>http://maven.apache.org</url>
    <!-- 对Hello1、Hello2 这2个项目进行聚合 -->
    <modules>
        <module>../Hello1</module>
        <module>../Hello2</module>
    </modules>
    <!-- 定义属性 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>4.9</junit.version>
        <maven.version>0.0.1-SNAPSHOT</maven.version>
    </properties>
    <!-- 用dependencyManagement进行jar包依赖管理 -->
    <dependencyManagement>
        <!-- 配置jar包依赖 -->
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <!-- 访问junit.version属性 -->
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.sst.cx.maven</groupId>
                <artifactId>Hello1</artifactId>
                <!-- 访问maven.version属性 -->
                <version>${maven.version}</version>
                <scope>compile</scope>
            </dependency>
            <dependency>
                <groupId>com.sst.cx.maven</groupId>
                <artifactId>Hello2</artifactId>
                <!-- 访问maven.version属性 -->
                <version>${maven.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
===》2. Hello1项目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>
  <artifactId>Hello1</artifactId>
      <!-- 继承Parent项目中的pom.xml配置 -->
       <parent>  
          <groupId>com.sst.cx.maven</groupId>
          <artifactId>Parent</artifactId>
          <version>0.0.1-SNAPSHOT</version>
          <!-- 使用相对路径 -->
          <relativePath>../Parent/pom.xml</relativePath>  
       </parent>
    <dependencies>
        <dependency>
            <!-- Parent项目的pom.xml文件配置中已经指明了要使用的Junit的版本号,因此在这里添加junit的依赖时,
            可以不指明<version></version>和<scope>test</scope>,会直接从Parent项目的pom.xml继承 -->
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>
</project>
===》3. Hello2项目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>
    <artifactId>Hello2</artifactId>
    <name>Hello2</name>
    <!-- 继承Parent项目中的pom.xml配置 -->
    <parent>
        <groupId>com.sst.cx.maven</groupId>
        <artifactId>Parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../Parent/pom.xml</relativePath>
    </parent>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <!-- Hello2项目中使用到了Hello1项目中的类,因此需要添加对Hello1.jar的依赖 
        Hello1.jar的<version>和<scope>也已经在Parent项目的pom.xml文件配置中已经指明了,因此这里也可以省略不写了
        -->
        <dependency>
            <groupId>com.sst.cx.maven</groupId>
            <artifactId>Hello1</artifactId>
        </dependency>
    </dependencies>
</project>
===》4. 在MyEclipse中构建
  选中Parent项目→【Run As】→【Maven install】
  Maven就会一次性构建Parent、Hello1、Hello2这3个项目
8. Profile
  项目通常都会有多个不同的运行环境(开发环境、测试环境、生产环境),不同环境的构建过程很可能是不同的(如:数据源配置、插件、依赖的版本等)。每次将项目部署到不同的环境时,都需要修改相应的配置,费时且易错。Maven引入了Profile(可以为不同的环境定制不同的构建过程)解决这一问题。
  有3种类型(作用范围不同):
    1. Per Project(只对当前项目有效)    
      在Maven项目的pom.xml中配置。  
    2. Per User(对本机上该用户所有Maven项目有效)     
      在默认仓库(用户主目录/.m2/settings.xml)中配置。     
    3. Global(对本机上所有Maven项目有效)  
      在Maven安装目录(maven/conf/settings.xml)中配置。
  1. 声明Profile:
    通过profiles元素来声明一组Profile配置,该元素下可以包含多个profile子元素,每个profile元素(通常都要包含一个id子元素,用来标识当前Profile)表示一个Profile配置。除了id子元素,Profile中还可以声明一些其他的POM元素(不同位置的Profile所能声明的POM元素不同)。
    1. pom.xml中
      project元素     
        repositories元素   
        pluginRepositories元素         
        dependencies元素       
        plugins元素        
        dependencyManagement元素       
        distributionManagement元素         
        modules元素        
        properties元素         
        reporting元素          
        build元素     
          plugins元素
          defaultGoal元素
          resources元素
          testResources元素
          directory元素
          filters元素
          finalName元素
          pluginManagement元素
          filters元素
    2. setting.xml中(声明的Profile是无法保证能够随着pom.xml一起被分发的,因此Maven不允许用户在该类型的Profile中修改或增加依赖或插件等配置信息),只能声明以下范围较为宽泛的元素:
      1. repositories:仓库配置。
      2. pluginRepositories:插件仓库配置。
      3. properties:键值对。
  2. 激活Profile(切换环境)
    有6种方式:
      1. 命令行激活
        使用mvn 命令行参数 -P加上Profile的id(多个 id 之间使用逗号隔开)
        例:mvn clean test -Ptest 
      2. settings.xml文件显示激活
        在本地仓库的settings.xml文件中添加(来激活指定Profile):
          <activeProfiles>
            <activeProfile>test</activeProfile>
          </activeProfiles>
        在终端执行:mvn clean test
      3. 系统属性激活(当某个系统属性存在时,激活指定的 Profile)
        在定义Profile时,添加(当系统属性user存在且值等于prod时,自动激活该Profile):
          <activation>
              <property>
                <name>user</name>
                <value>prod</value>
              </property>
          </activation>
        在终端执行:mvn clean test -Duser=prod 
      4. 操作系统环境激活
        在定义Profile时,添加(根据操作系统环境,自动激活指定的Profile):
          <activation>
              <os>
                  <name>Windows 10</name>
                  <family>Windows</family>
                  <arch>amd64</arch>
                  <version>10.0</version>
              </os>
          </activation>
        在终端执行:mvn clean test
      5. 文件存在与否激活
        在定义Profile时,添加(当 env.prod.properties 文件存在,且 env.test.properties 文件不存在时,激活该 Profile):
          <activation>
            <file>
                <exists>./src/main/resources/env.prod.properties</exists>
                <missing>./src/main/resources/env.test.properties</missing>
            </file>
          </activation>
        在终端执行:mvn clean test 
      6. 默认激活
        在定义Profile时,添加(指定该Profile默认激活):
          <activation>
            <activeByDefault>true</activeByDefault>
          </activation>
        在终端执行:mvn clean test 

例:
  1. 在项目的src/main/resources目录下创建3个properties环境配置文件。
    1. env.properties:默认配置文件
    2. env.test.properties:测试环境配置文件
    3. env.prod.properties:生产环境配置文件
  2. 在pom.xml中定义3个不同的Profile(并将maven-antrun-plugin:run插件目标绑定到 default 生命周期的 test 阶段上)。
    <profiles>
        <!-- test环境配置 -->
        <profile>
            <id>test</id>
            <activation>
                <property>
                    <name>env</name>
                    <value>test</value>
                </property>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-antrun-plugin</artifactId>
                        <version>1.3</version>
                        <executions>
                            <execution>
                                <phase>test</phase>
                                <goals>
                                    <goal>run</goal>
                                </goals>
                                <configuration>
                                    <tasks>
                                        <!--输出  -->
                                        <echo>使用 env.test.properties,将其配置信息复制到 /Users/cx/hello/target/classes/user.properties 中
                                        </echo>
                                        <!-- 在target/calsses目录下生成user.properties,并将env.test.properties的内容复制到user.properties中 -->
                                        <!--  -->
                                        <copy file="src/main/resources/env.test.properties"
                                              tofile="${project.build.outputDirectory}/user.properties"/>
                                    </tasks>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
        <!-- 默认环境配置 -->
        <profile>
            <id>normal</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-antrun-plugin</artifactId>
                        <version>1.3</version>
                        <executions>
                            <execution>
                                <phase>test</phase>
                                <goals>
                                    <goal>run</goal>
                                </goals>
                                <configuration>
                                    <tasks>
                                        <echo>使用 env.properties,将其配置信息复制到  /Users/cx/hello/target/classes/user.properties 中
                                        </echo>
                                        <copy file="src/main/resources/env.properties"
                                              tofile="${project.build.outputDirectory}/user.properties"/>
                                    </tasks>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
        <!--生产环境配置  -->
        <profile>
            <id>prod</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-antrun-plugin</artifactId>
                        <version>1.3</version>
                        <executions>
                            <execution>
                                <phase>test</phase>
                                <goals>
                                    <goal>run</goal>
                                </goals>
                                <configuration>
                                    <tasks>
                                        <echo>使用 env.prod.properties,将其配置信息复制到 /Users/cx/hello/target/classes/user.properties 中
                                        </echo>
                                        <copy file="src/main/resources/env.prod.properties"
                                              tofile="${project.build.outputDirectory}/user.properties"/>
                                    </tasks>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
9. 自动化部署
  Maven项目的部署通常包括以下步骤:
    1. 将项目代码提交到 SVN 或 Git 等版本控制系统中,并进行标记。
    2. 从 SVN 或 Git 上下载完整的项目代码。
    3. 构建应用。
    4. 将构建输出的 WAR 或 JAR 文件存放在指定的公共网络位置中。
    5. 从指定网络中获取文件,并部署到生产环境上。
    6. 更新项目文档以及版本号。
  以上这些工作通常由多个不同的团队协作完成(如:项目开发员负责项目代码的提交、项目管理员负责项目的构建工作、运维人员负责将构建好的应用文件部署到生产环境上等)。任何一个环节出现问题,都由可能导致 bug 甚至生产事故的发生(如:新版本构建完成后,没有发布到指定的网络位置中,导致运维人员再次将旧版本构件部署到生产环境中)。 
  为了避免以上问题发生,通常采用如下的架构来管理项目:
    1. Git(版本控制工具):管理项目源代码。
    2. Maven:负责编译和发布项目。
    3. Nexus(远程仓库管理工具):管理构建生成的二进制文件。

maven-release-plugin插件(用来实现自动化部署)常用的命令(目标)
  1. mvn release:clean  
    如果上次发布过程不成功,则使用该命令清理工作空间。
  2. mvn release:rollback   
    若上一次发布过程不成功,回滚对代码和配置所做的更改。
  3. mvn release:prepare    
    1. 检查是否存在 任何未提交的本地更改。
    2. 检查是否存在 SNAPSHOT版本的依赖项。
    3. 修改pom.xml中的配置,将应用的版本从SNAPSHOT快照版本修改为RLEASE正式版本(如:将1.0-SNAPSHOT修改为1.0)。
    4. 针对修改后的pom.xml进行测试,确保一切正常。
    5. 提交修改后的pom.xml。
    6. 将正式版本的代码提交到Git,并进行标记。
    7. 修改pom.xml中的配置,将正式版本升级为更高的快照版本(如:将1.0升级到 1.1-SNAPSHOT),以便以后继续使用快照版本进行开发。
    8. 将修改后的pom.xml提交到Git。
  4. mvn release:perform    
    从Git中检出上面标记的正式版代码,并执行命令mvn deploy将正式版本的构件部署到Nexus中。

步骤:
  1. 创建Maven项目
  2. 上传项目到Github
  3. 在pom.xml中配置Git、Nexus 
    <!--配置Git地址-->
    <scm>
        <url></url>
        <connection>scm:git:https://github.com/xxx/mavenAutoDeployDemo.git</connection>
        <developerConnection>scm:git:https://github.com/xxx/mavenAutoDeployDemo.git</developerConnection>
    </scm>
    <!--配置Nexus地址-->
    <distributionManagement>
        <repository>
            <id>hello_Release_hosted</id>
            <url>http://localhost:8082/nexus/content/repositories/hello_Release_hosted/</url>
        </repository>
        <snapshotRepository>
            <id>Snapshot</id>
            <url>http://localhost:8082/nexus/content/repositories/hello_Snapshot_hosted/</url>
        </snapshotRepository>
    </distributionManagement>
    <!-- 插件 -->
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-project-info-reports-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <!--配置 maven-release-plugin 插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-release-plugin</artifactId>
                <version>2.5.3</version>
                <configuration>
                    <useReleaseProfile>false</useReleaseProfile>
                    <goals>deploy</goals>
                    <checkModificationExcludes>
                        <checkModificationExclude>.idea</checkModificationExclude>
                    </checkModificationExcludes>
                    <autoVersionSubmodules>true</autoVersionSubmodules>
                </configuration>
            </plugin>
        </plugins>
    </build>
  4. 执行mvn scm:checkin -Dmessage="代码提交日志" 提交代码到Git。
  5. 执行mvn release:prepare(全部直接回车,使用默认的发布版本、SCM发布标签、开发版本)当发布完成后,项目的版本号会自动更新,并且将正式版发布到指定的Release库中。。
  6. 执行mvn release:perform 将正式版本的构件发布到Nexus中。
  7. 访问Nexus用户界面,查看仓库列表,选中名称为hello_Release_hosted的宿主仓库,点击Browse Index选项卡,查看该仓库中的构件。可以看到mavenAutoDeployDemo-1.0.jar已经被部署到Nexus仓库中。

1. 手动创建Maven项目(手动搭建目录结构)

  1. 第一个Maven项目(Hello World)
1. 项目目录结构(规定)
  在项目根目录下创建src目录和pom.xml文件
  在src目录下创建main目录和test目录
  在main目录和test目录下分别创建java目录和resources目录
  
 MavenProject(项目根目录)
   |----src
   |     |----main
   |     |     |----java ——存放Java文件
   |     |     |----resources ——存放项目资源文件(如:spring, hibernate配置文件)
   |     |----test
   |     |     |----java ——存放所有测试Java文件(如:JUnit测试类)
   |     |     |----resources ——存放项目资源文件(如:spring, hibernate配置文件)
   |----target ——项目输出位置(编译后自动生成,不需要主动创建)
   |----pom.xml ——用于标识该项目是一个Maven项目,包含了项目构建的信息(项目信息、项目依赖等)
2. pom.xml文件内容如下

<!-- 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">
    <!-- 
        所有的Maven项目都必须配置如下这四个配置项。
        由groupId、artifactId、version可以唯一确定一个项目。 
    -->
    <!-- 1. pom版本 -->
    <modelVersion>4.0.0</modelVersion>
    <!-- 2. 创建项目的组织(一般是域名倒写)-->
    <groupId>com.sst.cx</groupId>
    <!-- 3. 项目名(组织下的唯一标识) -->
    <artifactId>hello-maven</artifactId>
    <!-- 4. 项目版本(SNAPSHOT表示是快照版本) -->
    <version>SNAPSHOT-0.0.1</version>

    <!-- 项目的所依赖的jar包 -->
    <dependencies>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.9</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
</project>

说明:
  1. project的其他常用子元素
    <!-- 项目名 -->
    <name>hello-maven</name>
    <!-- 项目的打包方式(jar、war、ear等) -->
    <packaging>jar</packaging>
    <!-- 项目的属性配置 -->
    <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <!-- 项目的仓库地址 -->
    <url>http://maven.apache.org</url>
    <build>
      <finalName>my-WebApp</finalName>
    </build>
3. 在main的java目录下创建com.sst.cx包,在包下创建Hello.java

package com.sst.cx;
public class Hello {
    public String sayHelloWorld(String name) {
          return name + ": Hello World!";
    }
}
4. 在main的test目录下创建com.sst.cx包,在包下创建HelloTest.java

package com.sst.cx;
import org.junit.Test;
import static junit.framework.Assert.*;
public class HelloTest {
    @Test
    public void testHello(){
        Hello hello = new Hello();
        String results = hello.sayHelloWorld("cx");
        assertEquals("cx: Hello World!",results);
    }
}
5. 在终端下跳转到项目根目录,执行mvn install命令
  可以看到会自动生成target目录
    classes目录存放:编译好的Java代码(.class文件,可使用:java www.sst.cx.Hello命令运行主启动类/测试类)。
    test-classes目录存放:编译好的Java测试代码(.class文件)。
    surefire-reports目录存放:运行测试用例生成的测试报告。
    打包好的jar包:hello-maven-SNAPSHOT-0.0.1.jar。
  可以看到已经将jar包上传到本地仓库中。
mvn install

mvn install续

自动生成的target目录

本地仓库
  1. 在其他项目中使用上例生成的jar包
1. 项目目录结构
  同上
2. 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.sst.cx</groupId>
    <artifactId>hello-maven2</artifactId>
    <version>SNAPSHOT-0.0.1</version>
    <!-- 项目的所依赖的jar包 -->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>
      <dependency>
          <groupId>com.sst.cx</groupId>
          <artifactId>hello-maven</artifactId>
          <version>SNAPSHOT-0.0.1</version>
          <scope>compile</scope>
      </dependency>
    </dependencies>
</project>
3. 在main的java目录下创建com.sst.cx包,在包下创建HelloWorld.java

package com.sst.cx;
import com.sst.cx.Hello;  // 引用依赖包中的类
public class HelloWorld {
    public String sayHello() {
          Hello hello=new Hello();
          String content=hello.sayHelloWorld(getMyName());
          return content;
    }
    public String getMyName() {
          return "cx";
    }
}
4. 在main的test目录下创建com.sst.cx包,在包下创建HelloWorldTest.java

package com.sst.cx;
import org.junit.Test;
import static junit.framework.Assert.*;
public class HelloWorldTest {
    @Test
    public void testHello(){
        HelloWorld hello = new HelloWorld();
        String results = hello.sayHello();
        assertEquals("cx: Hello World!",results);
    }
}
5. 在终端下跳转到项目根目录,执行mvn install命令

2. 快速生成Maven项目(使用终端命令)

  1. 快速生成Java项目
在终端下执行如下命令(会自动生成项目的目录结构):
  方式1(mvn archetype:generate命令)
    mvn archetype:generate -DgroupId=com.sst.cx -DartifactId=hello-maven3 -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
  方式2(mvn archetype:create命令)有问题
    mvn archetype:create -DgroupId=com.sst.cx -DartifactId=hello-maven3 -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
  方式3(随后再填写项目信息)
    mvn archetype:generate

会自动生成如下项目目录结构:
  pom.xml文件
  src目录
    main目录
      java目录
    test目录
      java目录
还需要手动创建如下目录:
  src/main/resources、src/test/resources

说明:
  1. archetype(Maven项目的模板工具包,定义了Maven项目的基本架构,提供了数千种创建Maven项目的模板)
    MavenArchetype由以下5个模块组成:
      1. maven-archetype-plugin:Archetype插件,提供了ArcheType的所有功能(Maven的所有功能都是通过插件实现的)。执行mvn archetype:generate插件目标可快速创建Maven项目。
      2. archetype-packaging:用于描述Archetype的生命周期与构建项目软件包。
      3. archetype-models:用于描述类与引用。
      4. archetype-common:核心类。
      5. archetype-testing:用于测试Archetype的内部组件。
  2. groupId                       
    项目的组织名标识符(包名,会在java目录下生成对应的包路径)
  3. artifactId                     
    项目名
  4. archetypeArtifactId(近3000个)                
    指定mvn项目骨架/Archetype模板(用于快速生成项目的目录结构和pom.xml文件):
      1. maven-archetype-quickstart(表示创建一个Java项目);
      2. maven-archetype-webapp(表示创建一个JavaWeb项目);
      3. maven-archetype-archetype;
      4. maven-archetype-j2ee-simple;
      5. maven-archetype-mojo;
      6. maven-archetype-portlet;
      7. maven-archetype-profiles (currently under development);
      8. maven-archetype-simple (currently under development);
      9. maven-archetype-site;
      10. maven-archetype-site-simple;
  5. interactiveMode                 
    是否使用交互模式
  6. version
    版本号
  7. package
部署项目
  mvn install
运行jar包(执行jar包中的com.sst.cx.App类的main方法)
  java -cp target/hello-maven3-1.0-SNAPSHOT.jar com.sst.cx.App


  1. 快速生成JavaWeb项目
在终端下执行如下命令:
  【仅仅是指定的DarchetypeArtifactId不同】
  方式1(mvn archetype:generate命令)
    mvn archetype:generate -DgroupId=com.sst.cx -DartifactId=hello-maven4 -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
  方式2(mvn archetype:create命令)有问题
    mvn archetype:create -DgroupId=com.sst.cx -DartifactId=hello-maven4 -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

会自动生成如下项目目录结构:
  pom.xml文件
  src目录
    main目录
      resources目录
      webapp目录
        index.jsp文件
        WEB-INF目录
          web.xml文件
还需要手动创建如下目录:
  src/main/java、src/test/java、src/test/resources
运行项目
  方式1. 使用mvn package打包项目(会在target目录下生成war包),将war包放在Tomcat/webapps下,启动Tomcat服务器即可在浏览器中访问。
  方式2. 在Web项目中集成Jetty并发布运行。
    1. 在pom.xml文件中添加
      <build>
        <finalName>hello-maven4</finalName>
        <pluginManagement>
          <!--配置Jetty-->
          <plugins>
            <plugin>
              <groupId>org.mortbay.jetty</groupId>   
              <artifactId>maven-jetty-plugin</artifactId>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    2. 在终端执行如下命令(即可在浏览器中访问)
      mvn jetty:run

访问项目
  在浏览器中输入http://localhost:8080/hello-maven4/
将war包放置在Tomcat的webapps目录下

启动Tomcat,访问项目

3. 使用Eclipse/MyEclipse开发Maven项目

Eclipse提供了很多实用的插件(如:FindBugs、Spring IDE、m2eclipse等)
  m2eclipse(Eclipse默认已经安装)是一款将Maven集成到Eclipse中的插件(可在Eclipse中执行Maven命令、创建Maven项目、修改pom.xml等),主要功能如下:
    1. 创建和导入Maven项目
    2. 管理依赖并与 Eclipse 的 classpath 集成
    3. 自动下载依赖
    4. 自动解析依赖
    5. 使用 Maven 模板(Maven Archetype)创建项目
    6. 浏览和搜索远程仓库中内容
    7. 可视化管理 POM 文件
    8. 图形化依赖分析
  1. 导入已有项目
Eclipse/MyEclipse:右键|Import|Maven|Existing Maven Projects | 导入Maven项目
IDEA:File  |  Open选择Maven项目根目录(Open as:Maven project)
1

2

3
  1. 新建Maven项目(会自动生成相关目录结构)
右键 | New | Project | Maven Project
如果勾选Create a simple project之后则不能选择archetype。
项目栏点右键,选择New,选择Project

选择MavenProject


勾选Create a simple project

不勾选Create a simple project
  1. 运行Maven项目(使用Maven命令构建Maven项目)
Eclipse/MyEclipse

选中项目 | 右键 | Run As
  Maven build... :可自定义Maven组合命令(可配置:Maven命令的默认名称、是否更新Snapshot,是否开启调试输出、添加运行参数等)
  Maven build :会展示之前自定义的Maven命令列表(如果只有一个自定义命令,会直接执行;如果没有自定义命令或自定义命令不完整,则和Maven build...命令跳转的界面一样)。
选中项目,右键,选择RunAs

自定义Maven命令
IDEA

在工作区的最右侧提供了一个Maven工具窗口(可以完成所有与Maven相关的操作),可通过以下3种方式中执行Maven命令:
  1. 使用 Run Anything 窗口。
    打开Run Anything 窗口:点击“m”按钮 或 在IDEA中连续两次按下Ctrl键。
    输入或选择下方列表中的Maven目标,回车即可执行。
    如果一个项目包含多个模块,且需要在特定的模块中执行 Maven 目标,则需要在 Run Anything 窗口右上角从“Project”列表中切换到所需的模块,然后再执行的 Maven 目标执行。 
  2. 使用上下文菜单。
    展开项目名下面的LifeCycle,右键单击Maven目标,在上下文菜单选择 Run '项目名 [Maven 目标]'(例如:Run 'secondEclipse [clean]'),即可执行该目标。
  3. 创建运行配置来执行一个或一组Maven目标。
    展开项目名下面的LifeCycle,同时选择一个或多个Maven目标,然后单击鼠标右键,选择 Create Run Configuration... 或 Modify Run Configuration... 
    在创建运行配置窗口,我们可以为 Maven 目标指定 Maven 命令和参数等,设置完成后,点击 OK 按钮保存该运行配置。
    配置完成后,在 Maven 工具窗口下自动生成了一个 Run Configurations 节点,再该节点下可以看到运行配置列表。
    在运行配置列表中,双击目标,或右键点击该目标然从上下文菜单中选择 Run,即可运行该目标。
Maven工具窗口,位于工作区的最右侧

使用Run Anything窗口

使用上下文菜单

创建运行配置-1

创建运行配置-2

使用运行配置
  1. 新建Maven Web项目(会自动生成相关目录结构)
右键 | New | Project | Maven Project|不勾选Create a simple project|选择Web类型的Archetype(列表会有延迟)

选中项目 | 右键 | Run As|选择Maven install,将生成的war包放置在Tomcat/webapps目录下,启动Tomcat,就可以在浏览器中访问。
如果项目的index.jsp和pom.xml文件报错。

在pom.xml文件中添加
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>3.3.1</version>
  </plugin>
可解决pom.xml文件报错问题。

index.jsp报错暂时忽略,可正常打包。

更换JDK

设置 | java | Installation JREs 
    必须1.6以上
更换JDK

修改UserSettings(修改本地仓库位置)

创建自定义本地仓库目录,将maven的conf目录下的settings.xml复制到该目录下。
在maven安装目录/conf目录下的settings.xml的settings元素下添加:<localRepository>/Users/cx/Workspaces/repository</localRepository>

MyEclipse:Preferences | MyEclipse | Maven | UserSettings 选择本地仓库目录下的settings.xml 
Eclipse:Preferences  |  Maven  | UserSettings 选择本地仓库目录下的settings.xml 
修改本地仓库位置

使用本地安装的Maven

Eclipse默认使用内嵌的Maven(版本较新),往往和本地安装的Maven版本不一致。
使用Eclipse内嵌的Maven存在2个风险:
  1. 新版本的Maven往往不够稳定,容易出现一些意想不到的错误;
  2. 使用命令行与Eclipse构建的过程或结果不一致。

MyEclipse:Preferences | MyEclipse | Installations | Add选择本地Maven安装目录  |  Apply
Eclipse:Preferences  |  Maven  |  Installations  |  Add选择本地Maven安装目录  |  Apply
IDEA:File  |  Settings  |  Build,Execution,Deployment  |  Build Tools  |  Maven 选择本地Maven安装目录、本地仓库目录  

使用本地安装的Maven

IDEA使用本地安装的Maven、修改本地仓库目录

4. 实际开发(多模块/多层)

为了便于后期维护,一般都会进行分层开发:
  domain(域模型层)
  dao(数据库访问层)
  service(业务逻辑层)
  web(表现层)

分层后的项目结构如下:
  system-parent
      |----pom.xml
      |----system-domain
                |----pom.xml
      |----system-dao
                |----pom.xml
      |----system-service
                |----pom.xml
      |----system-web
                |----pom.xml
1. 创建system-parent

mvn archetype:generate -DgroupId=com.sst.cx -DartifactId=system-parent -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

删除system-parent目录下的src目录;并将pom.xml中的<packaging>jar</packaging>中的jar改为pom(表示它是一个被继承的模块)。
2. 创建system-domain、system-dao、system-service、system-web

cd system-parent
mvn archetype:generate -DgroupId=com.sst.cx -DartifactId=system-domain -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
mvn archetype:generate -DgroupId=com.sst.cx -DartifactId=system-dao -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
mvn archetype:generate -DgroupId=com.sst.cx -DartifactId=system-service -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
mvn archetype:generate -DgroupId=com.sst.cx -DartifactId=system-web -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

会在system-parent目录中的pom.xml文件自动添加
  <modules>
    <module>system-domain</module>
    <module>system-dao</module>
    <module>system-service</module>
    <module>system-web</module>
  </modules>

修改system-domain、system-dao、system-service、system-web目录中的pom.xml文件:
  1. 去掉groupId、version、dependencies(注意:不是parent元素下的);
  2. 添加<packaging>jar</packaging>(除了system-web设为war,其他都设为jar);
  3. 添加:
    <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

修改system-dao目录中的pom.xml文件,添加对system-domain模块的依赖:
  <dependencies>
    <!--
      system-dao需要使用到system-domain中的类,所以需要添加对system-domain模块的依赖
    -->
    <dependency>
      <groupId>com.sst.cx</groupId>
      <artifactId>system-domain</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>

修改system-service目录中的pom.xml文件,添加对system-dao模块的依赖:
  <dependencies>
    <!--
      system-service依赖system-dao和system-domain,只需添加system-dao依赖即可
    -->
    <dependency>
      <groupId>com.sst.cx</groupId>
      <artifactId>system-dao</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>

修改system-web目录中的pom.xml文件,添加对system-service模块的依赖:
  <dependencies>
    <!--
      system-web依赖system-service
    -->
    <dependency>
      <groupId>com.sst.cx</groupId>
      <artifactId>system-service</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>system-web</finalName>
    <plugins>
      <!--配置Jetty插件-->
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
3. 打包项目、发布项目、在浏览器中访问

cd system-parent
mvn clean install
会在各子模块中自动创建target目录,并生成jar包。web并生成system-web.war包。

cd system-web/
mvn jetty:run
浏览器输入http://localhost:8080/system-web/,如果出现Hello World!则表示成功。
7. 导入MyEclipse/Eclipse进行开发。

Import|Maven|Existing Maven Projects|选择system-parent目录|勾选所有pom.xml(默认会购选)
浏览器访问
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容