欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Maven快速学习教程

程序员文章站 2023-01-03 18:51:28
〇、为什么要Maven 在开发中经常需要依赖第三方的包,包与包之间存在依赖关系,版本间还有兼容性问题,有时还里要将旧的包升级或降级,当项目复杂到一定程度时包管理变得非常重要。 Maven是当前最受欢迎的Java项目管理构建自动化综合工具,类似以前Java中的Ant、node.js中的npm、dotN ......

〇、为什么要maven

在开发中经常需要依赖第三方的包,包与包之间存在依赖关系,版本间还有兼容性问题,有时还里要将旧的包升级或降级,当项目复杂到一定程度时包管理变得非常重要。

Maven快速学习教程

 

maven是当前最受欢迎的java项目管理构建自动化综合工具,类似以前java中的ant、node.js中的npm、dotnet中的nuget、php中的composer

maven这个单词来自于意第绪语(犹太语),意为知识的积累。

Maven快速学习教程

maven提供了开发人员构建一个完整的生命周期框架。开发团队可以自动完成项目的基础工具建设,maven使用标准的目录结构和默认构建生命周期。maven让开发人员的工作更轻松,同时创建报表,检查,构建和测试自动化设置。maven简化和标准化项目建设过程。处理编译,分配,文档,团队协作和其他任务的无缝连接。 maven增加可重用性并负责建立相关的任务。

每个java项目的目录结构都没有一个统一的标准,配置文件到处都是,单元测试代码到底应该放在那里也没有一个权威的规范。

因此,我们就要用到maven(使用ant也可以,不过编写ant的xml脚本比较麻烦)----一个项目管理工具。

maven主要做了两件事:

  1. 统一开发规范与工具
  2. 统一管理jar包

如果没有maven,你可能不得不经历下面的过程:

1 如果使用了spring,去spring的官网下载jar包;如果使用hibernate,去hibernate的官网下载jar包;如果使用log4j,去log4j的官网下载jar包.....
2 当某些jar包有依赖的时候,还要去下载对应的依赖jar包
3 当jar包依赖有冲突时,不得不一个一个的排查
4 执行构建时,需要使用ant写出很多重复的任务代码
5 当新人加入开发时,需要拷贝大量的jar包,然后重复进行构建
6 当进行测试时,需要一个一个的运行....检查

有了maven,它提供了三种功能:

1 依赖的管理:仅仅通过jar包的几个属性,就能确定唯一的jar包,在指定的文件pom.xml中,只要写入这些依赖属性,就会自动下载并管理jar包。
2 项目的构建:内置很多的插件与生命周期,支持多种任务,比如校验、编译、测试、打包、部署、发布...
3 项目的知识管理:管理项目相关的其他内容,比如开发者信息,版本等等

Maven快速学习教程

 

官网:

教程:

*仓库资源:

一、maven概要

1.1、maven定义

maven 是一个java项目管理工具,主要功能是统一开发规范与包的依赖管理。

maven项目对象模型(pom),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具

Maven快速学习教程

版本

maven有自己的版本定义和规则

构建

maven支持许多种的应用程序类型,对于每一种支持的应用程序类型都定义好了一组构建规则和工具集。

输出管理

maven可以管理项目构建的产物,并将其加入到用户库中。这个功能可以用于项目组和其他部门之间的交付行为

依赖关系

maven对依赖关系的特性进行细致的分析和划分,避免开发过程中的依赖混乱和相互污染行为

文档和构建结果

maven的site命令支持各种文档信息的发布,包括构建过程的各种输出,javadoc,产品文档等。

项目关系

一个大型的项目通常有几个小项目或者模块组成,用maven可以很方便地管理

移植性管理

maven可以针对不同的开发场景,输出不同种类的输出结果

1.2、maven的生命周期

maven把项目的构建划分为不同的生命周期(lifecycle)。粗略一点的话,它这个过程(phase)包括:编译、测试、打包、集成测试、验证、部署。maven中所有的执行动作(goal)都需要指明自己在这个过程中的执行位置,然后maven执行的时候,就依照过程的发展依次调用这些goal进行各种处理。

 

这个也是maven的一个基本调度机制。一般来说,位置稍后的过程都会依赖于之前的过程。当然,maven同样提供了配置文件,可以依照用户要求,跳过某些阶段。

 

三种生命周期

  下面列出了default、clean和site生命周期的所有构建阶段,这些阶段按照指定的顺序执行。


clean生命周期

执行阶段 描述说明
pre-clean 在实际的项目清理之前执行所需的过程
clean 删除前一个构建生成的所有文件
post-clean 执行完成项目清理所需的过程


default生命周期

执行阶段 描述说明
validate 验证项目是正确的,所有必要的信息都是可用的。
initialize 初始化构建状态,例如设置属性或创建目录。
generate-sources 生成包含在编译中的任何源代码。
process-sources 处理源代码,例如过滤任何值。
generate-resources 生成包含在包中的资源。
process-resources 将资源复制并处理到目标目录中,准备打包。
compile 编译项目的源代码。
process-classes 从编译后生成生成的文件,例如在java类上执行字节码增强。
generate-test-sources 生成包含在编译中的任何测试源代码。
process-test-sources 处理测试源代码,例如过滤任何值。
generate-test-resources 为测试创建资源。
process-test-resources 将资源复制并处理到测试目标目录中。
test-compile 将测试源代码编译到测试目标目录
process-test-classes 从测试编译后post-process生成文件,例如在java类上执行字节码增强。对于maven 2.0.5和以上。
test 使用合适的单元测试框架运行测试。这些测试不应该要求打包或部署代码。
prepare-package 在实际包装前执行必要的准备工作。这通常会导致包的一个未打包的、经过处理的版本。(maven 2.1及以上)
package 使用已编译的代码,并将其打包成可部署格式,例如jar。
pre-integration-test 执行集成测试之前需要执行的操作。这可能涉及到设置所需的环境等问题。
integration-test 在需要集成测试的环境中,处理并部署包。
post-integration-test 执行集成测试后所需要的操作。这可能包括清理环境。
verify 运行任何检查以验证包是否有效,并满足质量标准。
install 将该包安装到本地存储库中,作为本地其他项目的依赖项。
deploy 在集成或发布环境中完成,将最终包复制到远程存储库中,以便与其他开发人员和项目共享。

 

site生命周期

 

执行阶段 描述说明
pre-site 在实际的项目站点生成之前执行过程
site 生成项目的站点文档
post-site 执行确定站点生成的过程,并为站点部署做好准备
site-deploy 将生成的站点文档部署到指定的web服务器

注意:执行某个生命周期的某个阶段不会影响其它的生命周期!

如果要同时执行多个生命周期的阶段可在命令行输入多个命令,中间以空格隔开,例如: clean package 该命令执行clean生命周期的clean阶段和default生命周期的package阶段。

1.3、maven标准工程结构

maven的标准工程结构如下:

Maven快速学习教程

1.4、maven"约束优于配置"

所谓的"约定优于配置",在maven中并不是完全不可以修改的,他们只是一些配置的默认值而已。但是除非必要,并不需要去修改那些约定内容。maven默认的文件存放结构如下:

每一个阶段的任务都知道怎么正确完成自己的工作,比如compile任务就知道从src/main/java下编译所有的java文件,并把它的输出class文件存放到target/classes中。

maven来说,采用"约定优于配置"的策略可以减少修改配置的工作量,也可以降低学习成本,更重要的是,给项目引入了统一的规范。

 

1.5、maven的版本规范

maven使用如下几个要素来唯一定位某一个输出物:

groudid

团体、组织的标识符。团体标识的约定是,它以创建这个项目的组织名称的逆向域名(reverse domain name)开头。一般对应着java的包的结构。例如org.apache

artifactid 

单独项目的唯一标识符。比如我们的tomcat, commons等。不要在artifactid中包含点号(.)

version 

一个项目的特定版本。

packaging 

项目的类型,默认是jar,描述了项目打包后的输出。类型为jar的项目产生一个jar文件,类型为war的项目产生一个web应用。

 

maven有自己的版本规范,一般是如下定义 <major version>.<minor version>.<incremental version>-<qualifier> ,比如1.2.3-beta-01。要说明的是,maven自己判断版本的算法是major,minor,incremental部分用数字比较,qualifier部分用字符串比较,所以要小心 alpha-2alpha-15的比较关系,最好用 alpha-02的格式。

maven在版本管理时候可以使用几个特殊的字符串 snapshotlatestrelease。比如"1.0-snapshot"。各个部分的含义和处理逻辑如下说明:

snapshot

这个版本一般用于开发过程中,表示不稳定的版本。

latest

指某个特定构件的最新发布,这个发布可能是一个发布版,也可能是一个snapshot版,具体看哪个时间最后。

release

指最后一个发布版。

 

  • project:
    • 任何你想 build 的事物,maven都会把它们当作是一个 project。
    • 这些 project 被定义为 pom(project object model)。
    • 一个 project 可以依赖其他的project,一个 project 也可以有多个子project组成。
  • pom:
    • pom(pom.xml) 是 maven 的核心文件,它是指示 maven 如何工作的元数据文件,类似 ant 的 build.xml 文件。
    • pom.xml 文件应该位于每个 project 的根目录。
  • groupid:
    • 顾名思义,这个应该是公司名或组织名。
  • artifactid:
    • 构建出来的文件名,一般来说或,这个也是project名。
  • packaging:
    • 项目打包的类型,可以是将jar、war、rar、ear、pom,默认是jar。
  • version:
    • 项目的版本,项目的唯一标识由 groupid+artifactid+packaging+versionz 组成。
  • dependency:
    • 为了能够 build 或运行,一个典型的java project会依赖其他的包,在maven中,这些被依赖的包就被称为 dependency。
  • plug-in:
    • maven是有插件组织的,它的每一个功能都是由插件提供的,主要的插件是由 java 来写的,但是他也支持 beanshell 和 ant 脚本编写的插件。
  • repository:
    • 仓库用来存放artifact的,可以是本地仓库,也可以是远程仓库,maven是由一个默认的仓库
  • snapshot:
    • 工程中可以(也应该)有这样一个特殊的版本:这个版本可以告诉maven,该工程正在处于开发阶段,会经常更新(但还为发布)。当其他工程依赖此类型的artifact时,maven会在仓库中寻找该artifact的最新版本,并自动下载、使用该最新版本。

 

1.6、项目骨架maven archetype

什么是maven archetype? 简单的说就是一个maven项目的基础模板,利用这个模板我们就可快速的建立一个新的该类型项目,同时也可以建立自己的项目骨架。
maven所提供的archetype功能都是由插件maven archetype plugin完成的

官网地址:http://maven.apache.org/archetype/maven-archetype-plugin/

主要命令:

  • archetype:generate   从项目骨架创建一个maven项目,老版本里使用的是archetype:create 
  • archetype:create-from-project  根据一个项目创建项目骨架

使用archetype:generate创建项目

 mvn archetype:generate命令参数解释
项目相关参数:

参数

含义

groupid

当前应用程序隶属的group的id

artifactid 

当前应用程序的id

package

代码生成时使用的根包的名字,如果没有给出,默认使用archetypegroupid

原型有关参数表

 

参数 含义

archetypegroupid

原型(archetype)的group id

archetypeartifactid 

原型(archetype)id

archetypeversion 

原型(archetype)版本

archetyperepository

包含原型(archetype)的资源库

archetypecatalog

archetype分类,这里按位置分类有:
‘local’  本地,通常是本地仓库的archetype-catalog.xml文件
‘remote’  远程,是maven的*仓库
file://...' 直接指定本地文件位置archetype-catalog.xml
http://...' or 'https://...'  网络上的文件位置 archetype-catalog.xml
'internal'
默认值是remote,local

filter

查找时过滤artifactid or groupid:artifactid

package

代码生成时使用的根包的名字,如果没有给出,默认使用archetypegroupid

命令示例:
新建一个简单web项目
mvn archetype:generate -dgroupid=com.domain 
                       -dartifactid=webappdemo
                       -dpackage=com.domain.webappdemo
                       -darchetypeartifactid=maven-archetype-webapp 
                       -dversion=1.0 -dinteractivemode=no

新建一个struts2 web项目
mvn archetype:generate -b -dgroupid=com.mycompany.mysystem
                            -dartifactid=mywebapp
                            -darchetypegroupid=org.apache.struts
                            -darchetypeartifactid=struts2-archetype-convention
                            -darchetypeversion=<current_struts_version>
                            -dremoterepositories=http://struts.apache.org
maven默认提供的archetype类型可以参考

从一个已有项目生成一个archetype

mvn clean archetype:create-from-project -darchetype.properties=./archetype.properties -darchetype.filteredextentions=java,xml,jsp,properties,sql

这里首先定义了一个archetype.properties文件在命令行被执行的目录,里面的内容是
tableprefix是qucikstart项目里用到的,想在新项目中替换掉的内容。
-dfilteredextentions,因为maven默认不会扫描sql文件,而这里是希望修改tableprefix的.
properties参考

1.7、maven的项目对象模型

maven包含了一个项目对象模型 (project object model),一组标准集合,一个项目生命周期(project lifecycle),一个依赖管理系统(dependency management system),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。

Maven快速学习教程

项目对象模型 (project object model)

一个maven工程都有一个pom.xml文件,通过pom.xml文件定义项目的坐标、项目依赖、项目信息、插件目标等。

依赖管理系统(dependency management system)

通过maven的依赖管理对项目所依赖的jar 包进行统一管理。 比如:项目依赖junit4.9,通过在pom.xml中定义junit4.9的依赖即使用junit4.9,如下所示是junit4.9的依赖定义:

<!-- 依赖关系 -->
    <dependencies>
        <!-- 此项目运行使用junit,所以此项目依赖junit -->
        <dependency>
            <!-- junit的项目名称 -->
            <groupid>junit</groupid>
            <!-- junit的模块名称 -->
            <artifactid>junit</artifactid>
            <!-- junit版本 -->
            <version>4.9</version>
            <!-- 依赖范围:单元测试时使用junit -->
            <scope>test</scope>
        </dependency>
    </dependencies>

一个项目生命周期(project lifecycle)

使用maven完成项目的构建,项目构建包括:清理、编译、测试、部署等过程,maven将这些过程规范为一个生命周期,如下所示是生命周期的各各阶段:

 Maven快速学习教程

maven通过执行一些简单命令即可实现上边生命周期的各各过程,比如执行mvn compile执行编译、执行mvn clean执行清理。

一组标准集合

maven将整个项目管理过程定义一组标准,比如:通过maven构建工程有标准的目录结构,有标准的生命周期阶段、依赖管理有标准的坐标定义等。

插件(plugin)目标(goal)

maven 管理项目生命周期过程都是基于插件完成的。

maven坐标是一组可以惟一标识构件的三元组值

  • groupid,代表构件的实体或组织例如:org.inspur.loushang
  • artifactid,实际的构件的名称,例如framework
  • version,该构件件的版本号
  • packaging :定义maven项目打包的方式,首先,打包方式通常与所生成构件的文件扩展名对应,如上例中的packaging为jar,最终的文件名为my-app-0.0.1-snapshot.jar。也可以打包成war, ear等。当不定义packaging的时候,maven 会使用默认值jar

    classifier: 该元素用来帮助定义构建输出的一些附件。附属构件与主构件对应,如上例中的主构件为my-app-0.0.1-snapshot.jar,该项目可能还会通过一些插件生成如my-app-0.0.1-snapshot-javadoc.jar,my-app-0.0.1-snapshot-sources.jar, 这样附属构件也就拥有了自己唯一的坐标

二、安装与配置

其实主流的开发工具如idea、eclipse都集成了maven(可见重要性),但为了更加深刻的学习与管理该工具(比如多个ide共享的问题),个人建议还是单独安装比较好。

2.1、官网下载地址

2.2、配置环境变量

注意:安装maven之前,必须先确保你的机器中已经安装了jdk

1.解压压缩包(以apache-maven-3.3.9-bin.zip为例)

2.添加环境变量maven_home,值为apache-maven-3.3.9的安装路径

Maven快速学习教程

3.path环境变量的变量值末尾添加%maven_home%\bin

4.cmd输入mvn –version,如果出现maven的版本信息,说明配置成功。

Maven快速学习教程

5.命令行创建maven项目

方法一:

输入命令 mvn archetype:generate,按回车,根据提示输入参数,如果是第一次使用,需要下载插件,稍等几分钟即可。

Maven快速学习教程

方法二:

 在命令中指定参数

mvn archetype:generate -dgroupid=com.mycompany.app -dartifactid=myapp -darchetypeartifactid=maven-archetype-quickstart -dinteractivemode=false

 执行结果:Maven快速学习教程

 新建一个简单web项目

mvn archetype:generate -dgroupid=com.zhangguo  -dartifactid=webappdemo  -dpackage=com.zhangguo.webappdemo  -darchetypeartifactid=maven-archetype-webapp   -dversion=1.0 -dinteractivemode=no

2.3、本地仓储配置

从*仓库下载的jar包,都会统一存放到本地仓库中。我们需要配置本地仓库的位置。

打开maven安装目录,打开conf目录下的setting.xml文件。

可以参照下图配置本地仓储位置。

Maven快速学习教程

 

你还可以在运行时指定本地仓库位置:

mvn clean install -dmaven.repo.local=/home/juven/myrepo/

2.4、*仓库配置

当构建一个maven项目时,首先检查pom.xml文件以确定依赖包的下载位置,执行顺序如下:

1、从本地资源库中查找并获得依赖包,如果没有,执行第2步。


2、从maven默认*仓库中查找并获得依赖包(http://repo1.maven.org/maven2/),如果没有,执行第3步。


3、如果在pom.xml中定义了自定义的远程仓库,那么也会在这里的仓库中进行查找并获得依赖包,如果都没有找到,那么maven就会抛出异常。

 修改默认*仓库地址

 Maven快速学习教程

常用地址:

1、http://www.sonatype.org/nexus/  私服nexus工具使用
2、http://mvnrepository.com/ (推荐)
3、http://repo1.maven.org/maven2
4、http://maven.aliyun.com/nexus/content/groups/public/  阿里云  (强力推荐)
5、http://repo2.maven.org/maven2/ 私服nexus工具使用
6、http://uk.maven.org/maven2/
7、http://repository.jboss.org/nexus/content/groups/public
8、http://maven.oschina.net/content/groups/public/  
9、http://mirrors.ibiblio.org/maven2/
10、http://maven.antelink.com/content/repositories/central/
11、http://nexus.openkoala.org/nexus/content/groups/koala-release/
12、http://maven.tmatesoft.com/content/groups/public/

完整配置文件:

Maven快速学习教程
<?xml version="1.0" encoding="utf-8"?>

<!--
licensed to the apache software foundation (asf) under one
or more contributor license agreements.  see the notice file
distributed with this work for additional information
regarding copyright ownership.  the asf licenses this file
to you under the apache license, version 2.0 (the
"license"); you may not use this file except in compliance
with the license.  you may obtain a copy of the license at

    http://www.apache.org/licenses/license-2.0

unless required by applicable law or agreed to in writing,
software distributed under the license is distributed on an
"as is" basis, without warranties or conditions of any
kind, either express or implied.  see the license for the
specific language governing permissions and limitations
under the license.
-->

<!--
 | this is the configuration file for maven. it can be specified at two levels:
 |
 |  1. user level. this settings.xml file provides configuration for a single user,
 |                 and is normally provided in ${user.home}/.m2/settings.xml.
 |
 |                 note: this location can be overridden with the cli option:
 |
 |                 -s /path/to/user/settings.xml
 |
 |  2. global level. this settings.xml file provides configuration for all maven
 |                 users on a machine (assuming they're all using the same maven
 |                 installation). it's normally provided in
 |                 ${maven.home}/conf/settings.xml.
 |
 |                 note: this location can be overridden with the cli option:
 |
 |                 -gs /path/to/global/settings.xml
 |
 | the sections in this sample file are intended to give you a running start at
 | getting the most out of your maven installation. where appropriate, the default
 | values (values used when the setting is not specified) are provided.
 |
 |-->
<settings xmlns="http://maven.apache.org/settings/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
          xsi:schemalocation="http://maven.apache.org/settings/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <!-- localrepository
   | the path to the local repository maven will use to store artifacts.
   |
   | default: ${user.home}/.m2/repository
  <localrepository>/path/to/local/repo</localrepository>
  -->
  <localrepository>h:\installfiles\javakit\mavenres</localrepository>
  <!-- interactivemode
   | this will determine whether maven prompts you when it needs input. if set to false,
   | maven will use a sensible default value, perhaps based on some other setting, for
   | the parameter in question.
   |
   | default: true
  <interactivemode>true</interactivemode>
  -->

  <!-- offline
   | determines whether maven should attempt to connect to the network when executing a build.
   | this will have an effect on artifact downloads, artifact deployment, and others.
   |
   | default: false
  <offline>false</offline>
  -->

  <!-- plugingroups
   | this is a list of additional group identifiers that will be searched when resolving plugins by their prefix, i.e.
   | when invoking a command line like "mvn prefix:goal". maven will automatically add the group identifiers
   | "org.apache.maven.plugins" and "org.codehaus.mojo" if these are not already contained in the list.
   |-->
  <plugingroups>
    <!-- plugingroup
     | specifies a further group identifier to use for plugin lookup.
    <plugingroup>com.your.plugins</plugingroup>
    -->
  </plugingroups>

  <!-- proxies
   | this is a list of proxies which can be used on this machine to connect to the network.
   | unless otherwise specified (by system property or command-line switch), the first proxy
   | specification in this list marked as active will be used.
   |-->
  <proxies>
    <!-- proxy
     | specification for one proxy, to be used in connecting to the network.
     |
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>proxyuser</username>
      <password>proxypass</password>
      <host>proxy.host.net</host>
      <port>80</port>
      <nonproxyhosts>local.net|some.host.com</nonproxyhosts>
    </proxy>
    -->
  </proxies>

  <!-- servers
   | this is a list of authentication profiles, keyed by the server-id used within the system.
   | authentication profiles can be used whenever maven must make a connection to a remote server.
   |-->
  <servers>
    <!-- server
     | specifies the authentication information to use when connecting to a particular server, identified by
     | a unique name within the system (referred to by the 'id' attribute below).
     |
     | note: you should either specify username/password or privatekey/passphrase, since these pairings are
     |       used together.
     |
    <server>
      <id>deploymentrepo</id>
      <username>repouser</username>
      <password>repopwd</password>
    </server>
    -->

    <!-- another sample, using keys to authenticate.
    <server>
      <id>siteserver</id>
      <privatekey>/path/to/private/key</privatekey>
      <passphrase>optional; leave empty if not used.</passphrase>
    </server>
    -->
<server> 
    <id>admin</id> 
    <username>admin</username> 
    <password>admin</password>
</server>
</servers>

  <!-- mirrors
   | this is a list of mirrors to be used in downloading artifacts from remote repositories.
   |
   | it works like this: a pom may declare a repository to use in resolving certain artifacts.
   | however, this repository may have problems with heavy traffic at times, so people have mirrored
   | it to several places.
   |
   | that repository definition will have a unique id, so we can create a mirror reference for that
   | repository, to be used as an alternate download site. the mirror site will be the preferred
   | server for that repository.
   |-->
  <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>nexus-aliyun</id>  
    <mirrorof>*,!jeecg,!jeecg-snapshots</mirrorof>  
    <name>nexus aliyun</name>  
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>  
  </mirror>
&

                    
                
(0)
打赏 Maven快速学习教程 微信扫一扫

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

Maven快速学习教程
验证码: Maven快速学习教程