# Maven使用教程
# 安装和配置
Maven是一个Java环境下的包管理和项目构建工具
# 安装
建议使用v3.8.x版本如 apache-maven-3.8.6-bin.zip
下载后解压至本地
# 环境配置
安装maven之前,首先要安装Java,并配置Java环境
- 首先需要配置MAVEN_HOME,即maven安装包解压后的根目录
E:\Program Files\maven\apache-maven-3.8.6
- 然后在Path中添加
%MAVEN_HOME%\bin
- 测试
mvn -v
# 功能配置
找到maven根目录下,conf/setting.xml
文件,添加如下配置
- 配置本地仓库地址
<localRepository>H:\Program_Data\maven\maven_repository</localRepository>
- 配置国内阿里镜像
<mirrors>
<!-- 中央仓库在中国的镜像 -->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>
</mirrors>
- 配置JDK版本项目构建,也可以在pom.xml中通过插件解决(非必要)
<profile>
<id>jdk-17</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>17</jdk>
</activation>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
</properties>
</profile>
# 仓库地址
官方仓库地址:https://mvnrepository.com/
阿里云镜像:
- https://maven.aliyun.com/repository/central maven官方仓库的镜像
- https://maven.aliyun.com/repository/public(推荐) 还包含其他仓库的包
华为云镜像:https://mirrors.huaweicloud.com/repository/maven/
腾讯云镜像:http://mirrors.cloud.tencent.com/nexus/repository/maven-public/
# IDEA配置本地Maven
这样只能配置当前项目的Maven地址,每次打开新的项目,还需要重新配置比较麻烦
解决办法:在文件——新建项目设置——新项目的设置中,配置一遍maven,这样打开新的项目,就会使用我们配置好的本地maven
但是旧的项目打开,还是需要重新在IDEA配置maven的
# 创建Maven工程
# Maven工程的GAVP
Maven工程相对之前的项目,多出一组gavp属性,gav需要我们在创建项目的时候指定,p有默认值,我们先行了解下这组属性的含义:
Maven 中的 GAVP 是指 GroupId、ArtifactId、Version、Packaging 等四个属性的缩写,其中前三个是必要的,而 Packaging 属性为可选项。这四个属性主要为每个项目在maven仓库中做一个标识,类似人的姓-名!有了具体标识,方便后期项目之间相互引用依赖等!
GAV遵循一下规则:
1) GroupID 格式:com.{公司/BU }.业务线.[子业务线],最多 4 级。
说明:{公司/BU} 例如:alibaba/taobao/tmall/aliexpress 等 BU 一级;子业务线可选。
正例:com.taobao.tddl 或 com.alibaba.sourcing.multilang
2) ArtifactID 格式:产品线名-模块名。语义不重复不遗漏,先到仓库中心去查证一下。
正例:tc-client / uic-api / tair-tool / bookstore
3) Version版本号格式推荐:主版本号.次版本号.修订号
1) 主版本号:当做了不兼容的 API 修改,或者增加了能改变产品方向的新功能。
2) 次版本号:当做了向下兼容的功能性新增(新增类、接口等)。
3) 修订号:修复 bug,没有修改方法签名的功能加强,保持 API 兼容性。
例如: 初始→1.0.0 修改bug → 1.0.1 功能调整 → 1.1.1等
Packaging定义规则:
指示将项目打包为什么类型的文件,idea根据packaging值,识别maven项目类型!
packaging 属性为 jar(默认值),代表普通的Java工程,打包以后是.jar结尾的文件。
packaging 属性为 war,代表Java的web工程,打包以后.war结尾的文件。
packaging 属性为 pom,代表不会打包,用来做继承的父工程。
# 创建Java SE项目
Java SE项目主要指使用Java标准版进行开发,通常是桌面应用或基于控制台的应用。
特点:
- 直接使用Java标准库开发
- 通常不涉及Web开发的内容
- 使用Swing、JavaFX等创建控制台、桌面应用程序
# 创建Java Web项目
Java Web项目用于创建动态网站或Web应用程序,通常基于Servlet规范,需要部署在Web服务器如(Tomcat、Jetty)上,包含前端和后端。
特点:
- 使用JSP、Servlet开发动态网页
- 需要配置
Web.xml
或使用注解来定义Servlet和过滤器 - 通常需要手动管理配置和依赖
- 适合中小型Web应用
# 手动创建
创建一个maven的Java se工程
修改pom.xml的文件打包方式,保存后刷新,IDEA项目设置中就能看到Web模块
<packaging>war</packaging>
- 设置web资源路径和web.xml路径
# 插件创建
- 安装插件JBLJAVAToWeb
- 创建java se模块
- 模块上右键,点击插件生成,和手动创建是一样的作用
运行JavaWeb项目,需要编辑配置,使用本地的Tomcat,部署选项卡选择war exploded
# 创建SpringBoot项目
SpringBoot项目用于创建独立的、生产级的Spring应用程序,通常是后端服务,提供自动配置和内嵌服务器(Tomcat)
特点:
- 自动配置:减少了配置文件和代码冗余
- 内嵌服务器:可以直接运行
- 依赖管理:使用Maven或gradle管理项目依赖
- 易于集成各种Spring模块
# Maven工程的项目结构
比较常见的一种项目结构
|-- pom.xml # Maven 项目管理文件
|-- src
|-- main # 项目主要代码
| |-- java # Java 源代码目录
| | `-- com/example/myapp # 开发者代码主目录
| | |-- controller # 存放 Controller 层代码的目录
| | |-- service # 存放 Service 层代码的目录
| | |-- dao # 存放 DAO 层代码的目录
| | `-- model # 存放数据模型的目录
| |-- resources # 资源目录,存放配置文件、静态资源等
| | |-- log4j.properties # 日志配置文件
| | |-- spring-mybatis.xml # Spring Mybatis 配置文件
| | `-- static # 存放静态资源的目录
| | |-- css # 存放 CSS 文件的目录
| | |-- js # 存放 JavaScript 文件的目录
| | `-- images # 存放图片资源的目录
| `-- webapp # 存放 WEB 相关配置和资源
| |-- WEB-INF # 存放 WEB 应用配置文件
| | |-- web.xml # Web 应用的部署描述文件
| | `-- classes # 存放编译后的 class 文件
| `-- index.html # Web 应用入口页面
`-- test # 项目测试代码
|-- java # 单元测试目录
`-- resources # 测试资源目录
# 注意事项
如何正确的选择包的版本号?
- 在maven仓库https://mvnrepository.com/
- 搜索查看依赖的版本,和使用人数,复制GAV到pmx.xml文件中
# 构建Maven工程
# 命令方式构建
命令 | 描述 |
---|---|
mvn compile | 编译项目,生成target文件 |
mvn package | 打包项目,生成jar或war文件 |
mvn clean | 清理编译或打包后的项目结构 |
mvn install | 打包后上传到maven本地仓库 |
mvn deploy | 只打包,上传到maven私服仓库 |
mvn site | 生成站点 |
mvn test | 执行测试源码 |
# 可视化方式构建
注意:打包(package)和安装(install)的区别是什么
打包是将工程打成jar或war文件,保存在target目录下
安装是将当前工程所生成的jar或war文件,安装到本地仓库,会按照坐标保存到指定位置
# 依赖管理
Maven的依赖管理也是重要功能之一,能够帮助开发人员自动解决软件包依赖问题,避免出现版本冲突和依赖缺失等问题。
通过定义 POM 文件,Maven 能够自动解析项目的依赖关系,并通过 Maven 仓库自动下载和管理依赖,从而避免了手动下载和管理依赖的繁琐工作和可能引发的版本冲突问题。
# 核心配置GAVP
pom.xml
<!-- xml的模型版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.companyname.project-group,maven会将该项目打成的jar包放本地路径:/com/companyname/project-group -->
<groupId>com.companyname.project-group</groupId>
<!-- 项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
<artifactId>project</artifactId>
<!-- 版本号 -->
<version>1.0.0</version>
<!--打包方式
默认:jar
jar指的是普通的java项目打包方式! 项目打成jar包!
war指的是web项目打包方式!项目打成war包!
pom不会讲项目打包!这个项目作为父工程,被其他工程聚合或者继承!
-->
<packaging>jar/pom/war</packaging>
# 依赖配置管理
pom.xml
依赖管理和依赖添加
<!--
通过编写依赖jar包的gav必要属性,引入第三方依赖!
scope属性是可选的,可以指定依赖生效范围!
依赖信息查询方式:
1. maven仓库信息官网 https://mvnrepository.com/
2. mavensearch插件搜索
-->
<dependencies>
<!-- 引入具体的依赖包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<!-- 依赖范围 -->
<scope>runtime</scope>
</dependency>
</dependencies>
依赖版本统一提取和维护,本质是定义变量和引用变量
<!--声明版本-->
<properties>
<!--命名随便,内部制定版本号即可!-->
<junit.version>4.12</junit.version>
<!-- 也可以通过 maven规定的固定的key,配置maven的参数!如下配置编码格式!-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--引用properties声明版本 -->
<version>${junit.version}</version>
</dependency>
</dependencies>
依赖提取在Springboot中很有用,例如可以指定Springboot的版本,随后像securiy、jpa、redis的starter都可以引用相同的版本,不容易出错
# 依赖范围(重要)
通过设置坐标的依赖范围(scope),可以设置 对应jar包的作用范围:编译环境、测试环境、运行环境
scope默认是compile
依赖范围 | 描述 |
---|---|
compile | 编译依赖范围,scope 元素的缺省值。使用此依赖范围的 Maven 依赖,对于三种 classpath 均有效,即该 Maven 依赖在上述三种 classpath 均会被引入。例如,log4j 在编译、测试、运行过程都是必须的。 |
test | 测试依赖范围。使用此依赖范围的 Maven 依赖,只对测试 classpath 有效。例如,Junit 依赖只有在测试阶段才需要。 |
provided | 已提供依赖范围。使用此依赖范围的 Maven 依赖,只对编译 classpath 和测试 classpath 有效。例如,servlet-api 依赖对于编译、测试阶段而言是需要的,但是运行阶段,由于外部容器已经提供,故不需要 Maven 重复引入该依赖。 |
runtime | 运行时依赖范围。使用此依赖范围的 Maven 依赖,只对测试 classpath、运行 classpath 有效。例如,JDBC 驱动实现依赖,其在编译时只需 JDK 提供的 JDBC 接口即可,只有测试、运行阶段才需要实现了 JDBC 接口的驱动。 |
system | 系统依赖范围,其效果与 provided 的依赖范围一致。其用于添加非 Maven 仓库的本地依赖,通过依赖元素 dependency 中的 systemPath 元素指定本地依赖的路径。鉴于使用其会导致项目的可移植性降低,一般不推荐使用。 |
import | 导入依赖范围,该依赖范围只能与 dependencyManagement 元素配合使用,其功能是将目标 pom.xml 文件中 dependencyManagement 的配置导入合并到当前 pom.xml 的 dependencyManagement 中。 |
# 依赖下载失败
# 原因与解决方案
使用Maven构建项目时,可能会发生依赖下载错误的情况,主要原因有以下几种:
- 网络故障或仓库服务器宕机,无法连接至 Maven 仓库
- 依赖项的版本号或配置文件中的版本号错误,或者依赖项没有正确定义
- 本地 Maven 仓库或缓存被污染或损坏
解决方案:
- 检查网络连接和 Maven 仓库服务器状态
- 确保依赖项的版本号与项目对应的版本号匹配,不能想当然修改包的坐标信息
- 清除本地 Maven 仓库缓存(lastUpdated 文件),因为只要存在lastupdated缓存文件,刷新也不会重新下载。
# 脚本清除
或者可以将清除lastUpdated文件的操作写在一个脚本文件中,手动创建文件"clearLastUpdated.bat",名字任意,但是后缀必须是bat,将以下内容复制到文件中
cls
@ECHO OFF
SET CLEAR_PATH=H:
SET CLEAR_DIR=H:\Program_Data\maven\maven_repository(本地仓库路径)
color 0a
TITLE ClearLastUpdated For Windows
GOTO MENU
:MENU
CLS
ECHO.
ECHO. * * * * ClearLastUpdated For Windows * * * *
ECHO. * *
ECHO. * 1 清理*.lastUpdated *
ECHO. * *
ECHO. * 2 查看*.lastUpdated *
ECHO. * *
ECHO. * 3 退 出 *
ECHO. * *
ECHO. * * * * * * * * * * * * * * * * * * * * * * * *
ECHO.
ECHO.请输入选择项目的序号:
set /p ID=
IF "%id%"=="1" GOTO cmd1
IF "%id%"=="2" GOTO cmd2
IF "%id%"=="3" EXIT
PAUSE
:cmd1
ECHO. 开始清理
%CLEAR_PATH%
cd %CLEAR_DIR%
for /r %%i in (*.lastUpdated) do del %%i
ECHO.OK
PAUSE
GOTO MENU
:cmd2
ECHO. 查看*.lastUpdated文件
%CLEAR_PATH%
cd %CLEAR_DIR%
for /r %%i in (*.lastUpdated) do echo %%i
ECHO.OK
PAUSE
GOTO MENU
# 模拟错误
这里模拟下错误的处理方式:
- 断开电脑的网络连接,pom添加如下配置,发现无法下载依赖,即使恢复网络,仍然下载失败
- 找到maven本地仓库路径对应的包,删除
.lastUpdated
文件
- 用maven重新加载项目,可以看到,依赖正常了。
# Build构建配置
- 指定打包名称
<!-- 最终打包出来的war包就是maven_web-1.0.war -->
<build>
<finalName>maven_web-1.0</finalName>
</build>
- 指定打包文件:在java文件夹添加xml文件,默认不会被打包
<build>
<!--设置要打包的资源位置-->
<resources>
<resource>
<!--设置资源所在目录-->
<directory>src/main/java</directory>
<includes>
<!--设置包含的资源类型-->
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
- 配置依赖插件:如修改JDK版本、mybatis分页插件、tomcat插件等等
<build>
<plugins>
<!-- java编译插件,配jdk的编译版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8090</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<server>tomcat7</server>
</configuration>
</plugin>
</plugins>
</build>
注意:
- IDEA深度集成了Maven的构建系统,它会
识别项目类型
(packaging元素),并使用相应的插件来执行任务- 但是如果想使用指定版本的插件,就需要自行配置插件
# 依赖传递与依赖冲突(重要)
# 依赖传递特性
传递的原则
在A依赖B、B依赖C的情况下,C能否传递到A,取决于B依赖于C时使用的依赖范围及配置
- B依赖C时使用
compile
或runtime
范围,可以传递 - B依赖C时使用test或provided范围,则不能传递。因此必须在需要的模块中明确引入
- B依赖C时配置了
optional
标签,则不能传递
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
<optional>true</optional>
</dependency>
# 依赖冲突特性
当直接引用或间接引用出现了相同的jar包,一个项目就会出现两个相同的jar包。
maven自动解决依赖冲突问题,会按照自己的原则,进行重复依赖选择。同时也提供了手动解决冲突的方式
解决依赖冲突(如何选择重复依赖)方式:
自动选择原则
最短路径原则(第一原则)
A—>B—>C—>D—>E—>X(version 0.0.1)
A—>F—>X(version 0.0.2)
则A依赖于X(version 0.0.2)。
依赖路径长度相同情况下,则“先声明优先”(第二原则)
A—>E—>X(version 0.0.1)
A—>F—>X(version 0.0.2)
在<depencies></depencies>中,先声明的,路径相同,会优先选择!
手动排除
<!--引入B工程-->
<dependency>
<groupId>com.oldstag</groupId>
<artifactId>maven_B</artifactId>
<version>1.0-SNAPSHOT</version>
<!--手动排除-->
<exclusions>
<exclusion>
<!--不需要写version-->
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</exclusion>
</exclusions>
</dependency>
注意:
- IDEA2023.3.4版本maven依赖冲突的颜色提示有误,但是代码中引入的是正确的版本
- 手动排除后,IDEA的maven管理页面直接就不会显示这个依赖了
# Maven工程继承和聚合
# 继承关系(重要)
使用场景:
- 对一个大的项目进行么
模块拆分
- 每一个project下,创建了很多个module
- 每个module都需要自己的配置信息
隐藏的需求是:
- 每个module各自维护依赖信息,很容易发生出入,不易于统一管理
- 同一个框架的不同jar包,应该是
同一个版本
- 使用框架的jar包组合,需要经过长期摸索和反复调试,最终确定一个可用组合,不应该在新项目中重新摸索
继承的语法:
- 父工程
<groupId>com.oldstag</groupId>
<artifactId>maven_parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!--父工程不需要写java代码,打包方式设置为POM-->
<packaging>pom</packaging>
- 子工程
<!--使用parent标签指定当前工程的父工程-->
<parent>
<!--父工程坐标-->
<groupId>com.oldstag</groupId>
<artifactId>maven_parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 子工程的坐标 -->
<!-- 如果子工程坐标中的groupId和version与父工程一致,那么可以省略 -->
<artifactId>maven_child</artifactId>
注意:
- 在父工程上右键创建可自动生成子工程配置文件
- 子工程会无条件继承父工程的依赖
父工程依赖统一管理:
- 父工程声明版本
<!-- 使用dependencyManagement标签配置对依赖的管理 -->
<!-- 被管理的依赖并没有真正被引入到工程 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 子项目引用
<dependencies>
<!--子工程有需要可以引入,这里可以省略version-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
</dependencies>
思考:什么时候需要使用
dependencyManagement
?
- 当项目模块比较多,需要集中管理的依赖也比较多时,可以使用以简化版本管理
- 当依赖比较少时,直接使用dependencies就行
# 聚合关系
Maven 聚合是指将多个项目组织到一个父级项目中,以便一起构建和管理的机制。聚合可以帮助我们更好地管理一组相关的子项目,同时简化它们的构建和部署过程。
聚合作用
- 管理多个子项目:通过聚合,可以将多个子项目组织在一起,方便管理和维护。
- 构建和发布一组相关的项目:通过聚合,可以在一个命令中构建和发布多个相关的项目,简化了部署和维护工作。
- 优化构建顺序:通过聚合,可以对多个项目进行顺序控制,避免出现构建依赖混乱导致构建失败的情况。
- 统一管理依赖项:通过聚合,可以在父项目中管理公共依赖项和插件,避免重复定义。
聚合语法:父项目中包含子项目列表
<project>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<!-- 子工程的路径名 -->
<modules>
<module>child-project1</module>
<module>child-project2</module>
</modules>
</project>
# Maven私服(后面用到再补充)
# 简介
P46