Maven基础
Maven基础
本篇整理传统项目开发存在的问题、Maven 的简介与核心概念(目录结构、POM、仓库、生命周期)、环境搭建与配置、在 IDEA 中的使用、依赖作用范围,以及常见问题排查。
1. 传统项目开发存在的问题
- 项目中需要数量众多的
jar包,需要手动下载并引入,并且多个项目需要的jar包存在重复的问题; - 项目中需要的
jar包有版本兼容的问题,需要手动解决; - 项目中需要的
jar包又依赖其它的jar包,需要手动解决; - 一个项目做成一个工程,造成工程比较庞大,需要使用多模块来划分项目。
为了解决上述问题,我们引入 Maven(读音 ['meɪv(ə)n] 或 ['mevn])。
2. Maven 简介
Maven 是 Apache 软件基金会组织维护的一款自动化构建(build)工具,专注服务于 Java 平台的项目构建和依赖管理。Maven 这个单词的本意是:专家、内行。
Maven 是目前最流行的自动化构建工具,对于生产环境下多框架、多模块整合开发有重要作用,是一款在大型项目开发过程中不可或缺的重要工具。
Maven 的主要功能:
- Maven 可以整合多个项目之间的引用关系,我们可以根据业务和分层需要任意拆分一个项目;
- Maven 提供规范的管理各个常用
jar包及其各个版本,并且可以自动下载和引入项目中; - Maven 可以根据指定版本自动解决
jar包版本兼容问题; - Maven 可以把
jar包所依赖的其它jar包自动下载并引入项目。
类似的构建工具还有:Ant、Gradle。
构建从开始到结束有多个步骤,涉及到多个环节的协同工作:
| 环节 | 说明 |
|---|---|
| 清理 | 删除以前的编译结果,为重新编译做好准备 |
| 编译 | 将 Java 源程序编译为字节码文件 |
| 测试 | 针对项目中的关键点进行测试,确保项目在迭代开发过程中关键点的正确性 |
| 报告 | 在每一次测试后以标准的格式记录和展示测试结果 |
| 打包 | 将一个包含诸多文件的工程封装为一个压缩文件用于安装或部署。Java 工程对应 jar 包,Web 工程对应 war 包 |
| 安装 | 在 Maven 环境下特指将打包的结果(jar 包或 war 包)安装到本地仓库中 |
| 部署 | 将打包的结果部署到远程仓库,或将 war 包部署到服务器上运行 |
3. 搭建 Maven 环境
3.1 准备工作
由于 Maven 本身是基于 Java 开发的,所以要求必须安装 JDK。Maven 3.3+ 需要 JDK 1.7 或以上版本才能运行。
验证 JDK 是否安装并且能正常运行,在 DOS 窗口中运行下面的命令:
$ javac -version
$ java -version3.2 下载 Maven
下载地址:https://maven.apache.org/download.cgi,选择 apache-maven-3.6.3-bin.zip 下载。
3.3 解压安装包
使用解压软件将下载的安装包解压,并放置到一个没有中文和空格的目录下。
目录说明:
| 目录 | 说明 |
|---|---|
bin | 存放了 Maven 中的可执行程序,后续我们会使用这些程序 |
boot | 含有 plexus-classworlds 类加载器框架,Maven 使用该框架加载自己的类库 |
conf | 存放了 Maven 的配置文件,后续我们会对里面的 setting.xml 进行配置 |
lib | 含有 Maven 运行时所需要的 Java 类库 |
3.4 配置环境变量
参考 JDK 环境变量的配置,这里需要进行如下操作:
- 新建环境变量
MAVEN_HOME,值为 Maven 中bin的上一级目录的全路径; - 修改
Path环境变量,添加%MAVEN_HOME%\bin。
3.5 验证
在命令行窗口中运行下面的命令:
$ mvn -version如果出现了版本相关内容的输出,说明 Maven 配置成功:
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: C:\DevApp\Maven\apache-maven-3.6.3\bin\..
Java version: 1.8.0_261, vendor: Oracle Corporation, runtime: C:\DevApp\Java\jdk1.8.0_261\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"3.6 配置 Maven
上面的安装过程并不能满足我们的需求,还要对 Maven 进行配置。以下的配置均在 conf 目录下的 setting.xml 文件中进行。
提示
这些配置都不需要记,用到的时候直接拷贝就可以。
3.6.1 配置本地仓库位置
在生活中,仓库是用来存放东西的;在 Maven 中,仓库是用来存放 jar 包的,配置本地仓库就是配置 jar 包在本地的存放位置。
配置方式:
<localRepository>本地仓库位置,没有中文和空格的目录</localRepository>案例:
<localRepository>C:/DevApp/Maven/repository</localRepository>3.6.2 配置远程仓库位置
本地仓库不可能存放所有的 jar 包,对于本地没有的 jar 包,需要从远程仓库镜像下载。
默认的远程仓库在国内下载十分缓慢,我们有必要配置一个速度更快的仓库。在国内,我们一般使用阿里云的镜像,配置如下:
<!-- 阿里云仓库 -->
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central</mirrorOf>
</mirror>3.6.3 配置 Maven 默认的 JDK
Maven 默认的 JDK 是 1.5 版本的,我们需要将 JDK 版本修改成 1.8 版本,配置如下:
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
<!-- 让增加的 profile生效 -->
<activeProfiles>
<activeProfile>jdk-1.8</activeProfile>
</activeProfiles>4. Maven 的核心概念
4.1 Maven 工程约定目录结构
demo(Maven工程的根目录,目录名可以自定义)
|-- pom.xml(Maven工程的核心配置文件)
|-- src(存放源码的目录)
|-- main(主程序,简单来说就是我们写的非测试代码)
| |-- java(主程序的Java代码)
| |-- resources(主程序的配置文件,xml文件,properties文件等)
|-- test(测试程序)
|-- java(测试程序的Java代码)
|-- resources(测试程序的配置文件,xml文件,properties文件等)下面通过案例体会一下 Maven 的使用(了解即可,真正开发时还是用 IDE),步骤如下:
- 按照上面的目录结构将所有的文件夹都创建好,
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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qfedu</groupId>
<artifactId>demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
<resource.delimiter>@</resource.delimiter>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
</project>- 在
main/java目录下新建包com.qfedu.demo,并在包下新建文件MyApp.java,代码如下:
package com.qfedu.demo;
public class MyApp {
public int add(int a, int b) {
return a + b;
}
}- 在
main/resources目录下创建配置文件conf.properties,里面不需要有内容; - 进入
pom.xml所在的目录(也就是demo目录),打开 dos 窗口,执行mvn compile,这个命令的目的是编译程序; - 执行完成命令后,
demo目录下生成了target目录:main/java下的 java 文件编译后生成的 class 文件在target/classes目录中,main/resources目录下的配置文件也出现在了target/classes目录中。
4.2 POM 文件
POM(Project Object Model,项目对象模型):Maven 把一个项目的结构和内容抽象成一个模型,在 xml 文件中进行声明,以方便进行构建和描述。pom.xml 是 Maven 的灵魂,Maven 环境搭建好之后,所有的学习和操作都是关于 pom.xml 的。
pom 文件中的常用标签:
| 标签 | 说明 |
|---|---|
modelVersion | Maven 模型的版本,对于 Maven2 和 Maven3 来说,它只能是 4.0.0 |
groupId | 组织 id,一般是公司域名的倒写 |
artifactId | 项目名称,也是模块名称,对应 groupId 中项目中的子项目 |
version | 项目的版本号 |
groupId、artifactId、version | 三个元素生成了一个 Maven 项目的基本坐标,在众多的 Maven 项目中可以唯一定位到某一个项目。坐标也决定着将来项目在仓库中的路径及名称 |
packaging | 项目打包的类型,可以是 jar、war、rar、ear、pom,默认是 jar |
dependencies 和 dependency | Maven 的一个重要作用就是管理 jar 包。项目为了构建或运行,不可避免会依赖很多其他的 jar 包,在 Maven 中这些 jar 被称为依赖,使用标签 dependency 来配置。依赖的配置正是通过坐标来定位的,由此可以看出 Maven 把所有的 jar 包也都视为项目存在 |
properties | 定义属性 |
build | 表示与构建相关的配置 |
parent | 在 Maven 中,如果多个模块都需要声明相同的配置(例如相同的 groupId、version、相同的依赖或相同的组件配置等),也有类似 Java 的继承机制,用 parent 声明要继承的父工程的 pom 配置 |
modules | 在 Maven 的多模块开发中,为了统一构建整个项目的所有模块,可以提供一个额外的模块,该模块打包方式为 pom,并在其中使用 modules 聚合其它模块,这样通过本模块就可以一键自动识别模块间的依赖关系来构建所有模块,称为 Maven 的聚合 |
parent、modules | 在多模块项目中使用,暂时可以不用了解 |
4.3 仓库
4.3.1 仓库是什么
仓库是存放东西的,Maven 中的仓库是用来存放 jar 包的。Maven 的仓库可以存放:
- Maven 的插件,本质上也是一些 jar,这些 jar 可以完成一定的功能;
- 自己开发的项目的模块,最终也可以打成
jar包放在仓库中; - 第三方框架或工具的
jar包,比如 MySQL、Spring 的 jar 包。
4.3.2 分类
本地仓库:存在于当前电脑上,默认存放在 用户目录/.m2/repository,为本机上所有的 Maven 工程服务。我们可以通过 Maven 的配置文件 conf/setting.xml 修改本地仓库所在的目录(在 3.6.1 节中已经修改了本地仓库的位置)。
远程仓库:不在本机上,通过网络才能使用,多台电脑可以通过网络使用。分类如下:
| 类型 | 说明 |
|---|---|
| 中央仓库 | 通过 Internet 访问,为全世界所有 Maven 工程服务 |
| 中央仓库的镜像 | 架设在不同位置(欧洲、美洲、亚洲等),每个洲都有若干服务器,为中央仓库分担流量,减轻中央仓库的访问、下载压力。所在洲的用户首先访问的是本洲的镜像服务器 |
| 私服 | 在局域网环境中部署的服务器,为当前局域网范围内的所有 Maven 工程服务,公司中常常使用这种方式 |
在 3.6.2 节中我们已经修改了远程仓库的配置,将远程仓库修改成了阿里云的镜像。
4.3.3 Maven 对仓库的使用
Maven 查找依赖的顺序为:本地仓库 → 私服(如果配置了私服)→ 镜像仓库 → 中央仓库。
如果所有的仓库都没有,那么构建失败。
4.4 Maven 的生命周期及相关命令
Maven 的生命周期就是 Maven 构建项目的过程,包括:清理、编译、测试、报告、打包、安装、部署。
Maven 提供一个项目构建的模型,把编译、测试、打包、部署等都对应成一个个的生命周期阶段,并对每一个阶段提供相应的命令。开发人员只需要掌握一小堆命令,就可以完成项目的构建过程:
| 命令 | 说明 |
|---|---|
mvn clean | 清理(会删除原来编译和测试的目录,即 target 目录,但是已经 install 到仓库里的包不会删除) |
mvn compile | 编译主程序(会在当前目录下生成一个 target,里边存放编译主程序之后生成的字节码文件) |
mvn test-compile | 编译测试程序(会在当前目录下生成一个 target,里边存放编译测试程序之后生成的字节码文件) |
mvn test | 测试(会生成一个目录 surefire-reports,保存测试结果) |
mvn package | 打包主程序(会编译、编译测试、测试,并且按照 pom.xml 配置把主程序打包生成 jar 包或者 war 包) |
mvn install | 安装主程序(会把本工程打包,并且按照本工程的坐标保存到本地仓库中) |
mvn deploy | 部署主程序(会把本工程打包,按照本工程的坐标保存到本地仓库中,并且还会保存到私服仓库中,还会自动把项目部署到 web 容器中) |
5. Maven 在 IDEA 中的使用
5.1 IDEA 关联 Maven
在全局设置中进行如下操作:
- 选择本地 Maven 版本;
- 选择本地 Maven 的配置文件;
- 选择本地仓储的位置。

5.2 创建普通 Maven 项目
5.2.1 新建项目
在新建项目界面,选择 Maven 并选择 SDK 的版本:

为项目命名,选择项目存放位置,设置项目的 GAV 坐标:

5.2.2 导入依赖
这里以导入 MySQL 驱动举例。
5.2.2.1 查找依赖
网址:https://mvnrepository.com/,进入网站后,搜索 mysql:

进入上图中的链接,出现如下图所示的界面,该界面罗列了 MySQL 驱动的所有版本:

按照上图的示例,选择 5.1.49,出现如下图所示界面:

5.2.2.2 导入依赖到项目中
将上面查到的 MySQL 驱动的 GAV 坐标拷贝到项目的 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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qfedu</groupId>
<artifactId>mvntest</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- MySQL驱动坐标 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
<!-- 关于scope后续会讲到 -->
<scope>runtime</scope>
</dependency>
</dependencies>
</project>5.2.2.3 同步依赖
引入坐标后,同步依赖,确认导入。
单击 pom.xml 右上角的图标,同步依赖。Idea2020 无法自动同步,只能手动同步依赖。手动同步依赖之后,右上角的图标消失:

5.2.3 测试
在 src/main 下新建 Java 类,运行 main 方法测试:
package com.qfedu.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class MyTest {
public static void main(String[] args) throws Exception {
//四大参数
String driverName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
String username = "root";
String password = "root";
//SQL语句
String sql = "select * from user";
//加载驱动
Class.forName(driverName);
//获取连接
Connection connection = DriverManager.getConnection(url, username, password);
//获取PreparedStatement
PreparedStatement statement = connection.prepareStatement(sql);
//发送SQL
ResultSet rSet = statement.executeQuery();
//处理结果
while(rSet.next()) {
String u = rSet.getString("username");
String p = rSet.getString("password");
System.out.println(u + ":" + p);
}
//释放资源
rSet.close();
statement.close();
connection.close();
}
}5.3 创建及部署 Web 项目
创建 Maven 版本的 web 项目,可以基于普通 Maven 项目进行。
5.3.1 修改打包方式
在 pom.xml 中设置 packaging:

5.3.2 引入 web 开发相关依赖
这里需要引入 JSP 和 Servlet 依赖:
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>5.3.3 修改项目结构
此时项目中没有存放 web 资源及配置文件的目录,按照下图的操作创建 web.xml,注意路径的写法(需要补全相关内容):

创建存放 web 资源的目录,这里按照图示操作,不需要修改任何内容,最后单击 OK 就可以了:

完成上述操作,项目 src/main 目录下会产生 webapp 目录,这个目录和之前 JavaWeb 阶段的 web 目录作用和地位是一样的。这个目录中包括 WEB-INF 目录,WEB-INF 中包括 web.xml 文件。后续开发过程中的 JSP 文件都放在这个目录下。
之前我们在 web 目录下创建 lib 目录用来存放 jar 包;由于现在创建的是 Maven 工程,导入 jar 包直接在 pom.xml 中导入就可以了。
5.3.4 编写代码
新建 Servlet,代码如下:
package com.qfedu.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "TestServlet", value = "/TestServlet")
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("<p>Hello World</p>");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}5.3.5 部署 Web 项目
在 Tomcat 中部署项目,整个过程和 JavaWeb 阶段中部署项目的过程完全相同:


5.3.6 测试
启动 Tomcat,访问 Servlet 测试。
6. 依赖作用范围
6.1 什么是依赖作用范围
依赖作用范围指 jar 包生效的时间段,即 jar 的生命周期。
6.2 如何设置
在 pom.xml 中设置依赖时使用 scope 设置:
<!-- MySQL驱动坐标 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
<scope>runtime</scope>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>6.3 依赖作用范围详解
| 作用范围 | 生效阶段 | 说明 |
|---|---|---|
compile | 编译、运行、测试均有效 | 默认的依赖有效范围。如果定义依赖关系时没有明确指定依赖有效范围,则默认采用该范围 |
provided | 编译、测试时有效,运行时无效 | 意味着打包的时候可以不用包进去,别的设施(Web Container)会提供。事实上该依赖理论上可以参与编译、测试、运行等周期。例如 servlet-api:运行项目时,容器已经提供,就不需要 Maven 重复地引入一遍了 |
runtime | 运行、测试时有效,编译代码时无效 | 在实际的项目(非开源、企业内部系统)中,和 compile 区别不是很大。例如 JDBC 驱动实现:项目代码编译只需要 JDK 提供的 JDBC 接口,只有在测试或运行项目时才需要实现上述接口的具体 JDBC 驱动 |
test | 只在测试时有效 | 包括测试代码的编译、执行。例如 Junit |
system | 编译、测试时有效,运行时无效 | 和 provided 的区别是:使用 system 范围的依赖时必须通过 systemPath 元素显式地指定依赖文件的路径。由于此类依赖不是通过 Maven 仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用 |
7. 常见问题
问题:IDEA 中 Maven 项目依赖出现红色波浪线。

原因:网络原因导致下载资源到一半没成功。
解决方法:单击 IDEA Maven 窗口上方的刷新按钮。

如果还不能解决,可以在 Windows 下新建如下内容的 .bat 文件并运行,再单击刷新按钮。注意 REPOSITORY_PATH 的值:
set REPOSITORY_PATH=本地仓库的绝对路径
rem 正在搜索...
for /f "delims=" %%i in ('dir /b /s "%REPOSITORY_PATH%\*lastUpdated*"') do (
del /s /q %%i
)
rem 搜索完毕
pause8. 小结
- Maven 解决两大问题:依赖管理(用坐标从仓库自动下载 jar)与项目构建(用生命周期命令完成清理、编译、测试、打包、安装、部署);
- 全局配置在
conf/setting.xml中完成:本地仓库位置、远程仓库镜像、默认 JDK 版本; - 依赖的
scope决定 jar 在编译、测试、运行哪个阶段生效,默认为compile。
