# 基础

Maven是appache下的开源项目,项目管理工具,管理Java项目

  • 本地仓库:第一次会从远程仓库下载jar包,保存在本地。下次先从本地找,找不到再去远程仓库找
  • 远程仓库:自己架设的仓库,对外公开
  • 中央仓库 (opens new window):maven团队维护的仓库,用户只能下载,不能添加

# 安装配置

# Binary可执行版本,已编译好的可以直接使用
# Source源代码版本,需自己编译成可执行软件才可使用
# 我们选择已经编译好的windows版本进行安装:选择zip版本(linux选择tar.gz)
  • 第二步 maven环境配置
系统变量 # MAVEN_HOME=D:\maven\apache-maven-3.8.4
变量Path # 添加 %MAVEN_HOME%\bin
验证环境配置是否成功  # mvn -version 
  • 第三步 创建一个maven仓库目录,配置settings.xml,完成后输入命令:mvn help:system 测试
<!--在节点 localRepository 中添加自己仓库的地址-->
<localRepository>D:\JAVA\apache-maven\apache-maven-3.8.5</localRepository>

<!--配置阿里云镜像-->
<mirror>
	<id>alimaven</id>
	<mirrorOf>central</mirrorOf>
	<name>aliyun maven</name>
	<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>

<!--配置JDK-->
<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>
  • 第四步 添加 maven 到我们的 IDEA 中

maven-IDEA

# 常用命令

在生命周期中,执行后边的命令,会自动执行前面的命令

clean # 清除编译的target目录
compile #编译命令,将src/main/java下的文件编译为class文件输出到target目录下
test # 运行所有的测试方法
package # 打包命令,在target目录下会出现war包/jar包
install # 将当前项目安装到本地仓库中,其他项目引用本项目的jar包时不用去私服上下载jar包

# 创建项目

Java项目 # archetype(骨架) -> maven-archetype-quickstart
WEB项目 # archetype(骨架) -> maven-archetype-webapp
MVC项目 # 先创建WEB项目,Project Structure -> Modules -> 添加Java/Resource文件夹 -> Mask as

# Pom.xml配置

  • 依赖项:资源的唯一标识
groupId # 组织名  org.example
atifactId # 模块名称  maven-test1
version # 版本号
packaging # 打包类型  war/jar/pom
scope # 依赖范围
  • scope 依赖范围
compile 编译、测试、运行
# 比如:strus-core、spring-beans
# 打到war包或jar包

provided 编译、测试有效
# 比如:servlet-api就是编译和测试有用,在运行时不用(tomcat容器已提供)
# 不会打到war包

runtime:运行、测试有效
# 比如:jdbc驱动包,在运行和测试时需要通过jdbc驱动包(mysql驱动)连接数据库,编译不用
# 会打到war包

test:只是测试有效,只在单元测试类中用
# 比如:junit
# 不会打到war包

maven

注意

  • 如果是compile就不需要设置了,因为compile是scope的默认值
  • Tomcat中包含servlet-api,所以设置为provided,防止运行时有冲突
<dependencies>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.6</version>
		<scope>runtime</scope>
	</dependency>
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>servlet-api</artifactId>
		<version>2.5</version>
		<scope>provided</scope>
	</dependency>
</dependencies>
  • scope设置为import,可以解决 Maven 的单继承问题
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.4.RELEASE</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>
  • scope设置为system,可以调用本地的jar包
 <properties>
	<nacos.version>2.5.1</nacos.version>
	<nacos.lib.path>${project.basedir}/src/main/resources/lib</nacos.lib.path>
</properties>

<dependency>
	<groupId>com.alibaba.nacos</groupId>
	<artifactId>nacos-auth</artifactId>
	<version>${nacos.version}</version>
	<scope>system</scope>
	<systemPath>${nacos.lib.path}/nacos-auth-${nacos.version}.jar</systemPath>
</dependency>

注意

scope import 只能在 dependencyManagement 模块中使用

  • 修改项目的打包名称
<build>
  <!-- 服务打包的最终名称 -->
  <finalName>app</finalName>
  <plugins></plugins>
</build>

# 版本

# SNAPSHOT(快照版本):项目开发过程中临时输出的版本,称为快照版本
# RELEASE(发布版本)
# alpha版:内测版,bug多不稳定内部版本不断添加新功能
# beta版:公测版,不稳定(比alpha稳定些),bug相对较多不断添加新功能
# 纯数字版

# 父工程与子模块显示在同一层级

父工程与子模块显示在同一层级

# 高级

# 依赖冲突

这里所说的依赖冲突是指项目依赖的某一个jar包,有多个不同的版本,因而造成类包版本冲突

# 同级特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的
# 不同级路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
# 如果想更全面的查看Maven中各个坐标的依赖关系,可以点击Maven面板中的show Dependencies

依赖冲突

# 可选依赖和排除依赖

  • 可选依赖指对外隐藏当前所依赖的资源---不透明
<dependency>
    <groupId>com.itheima</groupId>
    <artifactId>maven_03_pojo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--隐藏当前工程所依赖的资源,隐藏后的资源不再具有依赖传递性-->
	<!--当前项目可用,引用当前项目的不再能用-->
    <optional>true</optional>
</dependency>
  • 排除依赖指主动断开依赖的资源,被排除的资源无需指定版本---不需要
<dependency>
    <groupId>com.itheima</groupId>
    <artifactId>maven_04_dao</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--已经有依赖的事实,排除依赖是隐藏对当前资源的依赖关系-->
    <exclusions>
        <exclusion>
            <groupId>com.itheima</groupId>
            <artifactId>maven_03_pojo</artifactId>
        </exclusion>
    </exclusions>
</dependency>

# 聚合

  • 聚合:将多个模块组织成一个整体,同时进行项目构建的过程称为聚合
  • 聚合工程:通常是一个不具有业务功能的"空"工程(有且仅有一个pom文件)
<?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.itheima</groupId>
    <artifactId>maven_01_parent</artifactId>
    <version>1.0-RELEASE</version>
    <packaging>pom</packaging>
    
    <!--设置管理的模块名称,module顺序不重要,系统会根据依赖关系来自动决定执行的顺序-->
	<!--各模块都在当前pom.xml的父目录一级-->
    <modules>
        <module>../maven_02_ssm</module>
        <module>../maven_03_pojo</module>
        <module>../maven_04_dao</module>
    </modules>
</project>

项目的打包方式,我们接触到的有三种,分别是

  • jar:默认情况,说明该项目为java项目
  • war:说明该项目为web项目
  • pom:说明该项目为聚合或继承项目

# 继承

  • 在父工程的 dependencyManagement 中配置依赖管理,提供可选择的依赖资源
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
    </dependencies>
    ...
</dependencyManagement>
  • 在子工程中配置当前工程所继承的父工程,配置使用父工程中可选依赖的坐标
<parent>
    <groupId>com.itheima</groupId>
    <artifactId>maven_01_parent</artifactId>
    <version>1.0-RELEASE</version>
    <!--快速找到父工程的pom文件的相关路径,可以不写-->
    <relativePath>../maven_01_parent/pom.xml</relativePath>
</parent>

<dependencies>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
		<!--不需要配置版本-->
    </dependency>
</dependencies>

# 属性

  • 父工程中定义属性
<properties>
    <spring.version>5.2.10.RELEASE</spring.version>
    <junit.version>4.12</junit.version>
    <mybatis-spring.version>1.3.0</mybatis-spring.version>
</properties>
  • 修改依赖的version
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
</dependency>

# 配置文件加载属性

  • 父工程定义属性
<properties>
   <jdbc.url>jdbc:mysql://127.1.1.1:3306/ssm_db</jdbc.url>
</properties>
  • jdbc.properties文件中引用属性
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=${jdbc.url}
jdbc.username=root
jdbc.password=root

# 多环境开发

  • 父工程配置多个环境,并指定默认激活环境
<profiles>
    <!--开发环境env_dep-->
    <profile>
        <id>env_dep</id>
        <properties>
            <jdbc.url>jdbc:mysql://127.1.1.1:3306/ssm_db</jdbc.url>
        </properties>
        <!--设定是否为默认启动环境-->
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <!--生产环境env_pro-->
    <profile>
        <id>env_pro</id>
        <properties>
            <jdbc.url>jdbc:mysql://127.2.2.2:3306/ssm_db</jdbc.url>
        </properties>
		<!--设定是否为默认启动环境-->
		<activation>
			<activeByDefault>true</activeByDefault>
		</activation>
    </profile>
    <!--测试环境env_test-->
    <profile>
        <id>env_test</id>
        <properties>
            <jdbc.url>jdbc:mysql://127.3.3.3:3306/ssm_db</jdbc.url>
        </properties>
    </profile>
</profiles>
  • 在资源文件中使用 properties 中的值
jdbc.url=@jdbc.url@
  • 在 Spring Boot 应用中读取属性
Component
public class DatabaseConfig {
    
    @Value("${db.url}")
    private String databaseUrl;
    
    @Value("${app.environment}")
    private String environment;
}
  • 命令行实现环境切换
mvn 指令    -P 环境定义ID[环境定义中获取]
mvn install -P env_test

# 编译插件

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>3.14.0</version>
			<configuration>
				<source>17</source>
				<target>17</target>
				<encoding>UTF-8</encoding>
				<!--注解的处理路径,这些注解是在编译的时候才会动态处理-->
				<annotationProcessorPaths>
					<path>
					    <!--javadoc注解-->
						<groupId>com.github.therapi</groupId>
						<artifactId>therapi-runtime-javadoc-scribe</artifactId>
						<version>0.15.0</version>
					</path>
					<path>
					    <!--lombok注解-->
						<groupId>org.projectlombok</groupId>
						<artifactId>lombok</artifactId>
						<version>1.18.36</version>
					</path>
					<path>
					    <!--配置注解-->
						<groupId>org.springframework.boot</groupId>
						<artifactId>spring-boot-configuration-processor</artifactId>
						<version>3.4.7</version>
					</path>
					<path>
					    <!--mapstruct注解-->
						<groupId>io.github.linpeilie</groupId>
						<artifactId>mapstruct-plus-processor</artifactId>
						<version>1.4.8</version>
					</path>
					<path>
					    <!--使用lombok的时候mapstruct能正确处理-->
						<groupId>org.projectlombok</groupId>
						<artifactId>lombok-mapstruct-binding</artifactId>
						<version>0.2.0</version>
					</path>
				</annotationProcessorPaths>
				<compilerArgs>
				    <!--在编译的时候参数名不发生改变-->
					<arg>-parameters</arg>
				</compilerArgs>
			</configuration>
		</plugin>
	<plugins>
<build>

# 跳过测试

  • 方式一:IDEA工具实现跳过测试按钮Toggle 'Skip Tests'
  • 方式二:命令行跳过测试
mvn 指令 -D skipTests
mvn package -D skipTests
  • 方式三:配置插件实现跳过测试
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.5.3</version>
            <configuration>
			    <argLine>-Dfile.encoding=UTF-8</argLine>
				<!-- 根据打包环境执行对应的@Tag测试方法,@Tag("dev") -->
				<groups>${profiles.active}</groups>
				<!-- 排除标签,@Tag("exclude")不进行测试-->
				<excludedGroups>exclude</excludedGroups>
                <skipTests>false</skipTests>
                <!--
				skipTests:如果为true,则跳过所有测试,如果为false,则不跳过测试
				excludes:哪些测试类不参与测试,即排除,针对skipTests为false来设置的
				includes: 哪些测试类要参与测试,即包含,针对skipTests为true来设置的
				-->
                <excludes>
                    <exclude>**/BookServiceTest.java</exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

# 打包插件

<build>
	<finalName>appName</finalName>
	<plugins>
	    <!-- springboot项目默认的打包工具,默认会将所有文件都打进来-->
		<!-- 即打包自己项目的class文件+环境变量+静态资源文件+依赖jar-->
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<version>2.5.15</version>
			<configuration>
			    <!-- 如果没有该配置,devtools不会生效 -->
				<fork>true</fork>
				<!-- 跳过repackage,只保留maven-jar-plugin生成的普通jar -->
				<skip>true</skip> 
			</configuration>
			<executions>
				<execution>
					<goals>
					    <!--会将 maven 生成的原始包,重新打包repackage成一个可执行的 Fat JAR-->
						<!--并将原始 JAR 重命名为 *.jar.original 作为备份-->
						<goal>repackage</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
		
		<!-- maven 打包,不会将依赖的jar打包进去-->
		<!-- 打 jar 包-->
		<plugin>   
			<groupId>org.apache.maven.plugins</groupId>   
			<artifactId>maven-jar-plugin</artifactId>   
			<version>3.1.0</version> 
	   </plugin>
	   <!-- 打 war 包-->
	   <plugin>
			<groupId>org.apache.maven.plugins</groupId>   
			<artifactId>maven-war-plugin</artifactId>   
			<version>3.1.0</version>   
			<configuration>
				<failOnMissingWebXml>false</failOnMissingWebXml>
				<warName>appWarName</warName>
			</configuration>   
	   </plugin>     
	</plugins>
</build>

注意

在大多数标准的 Spring Boot 项目中,通常只需要配置 spring-boot-maven-plugin,而不需要显式配置 maven-jar-plugin。 这是因为 maven-jar-plugin 是 Maven 的核心插件之一,即使不写出来,Maven 也会在打包过程中自动调用它来生成最初的普通 JAR 包。 随后,spring-boot-maven-plugin 的 repackage 目标会对这个原始 JAR 进行再加工,生成可执行的 Fat JAR。

# 工程模块统一版本依赖

  • 插件会生成一个简化版的 pom.xml 文件(通常为 .flattened-pom.xml),去除不必要的继承和依赖管理
  • 在安装 install 和部署 deploy 阶段,Maven 会使用这个扁平化的 POM 文件,而不是原始的 POM 文件
  • 通过在父模块中定义版本号,如 ${revision},所有子模块可以继承该版本号,从而实现版本的统一管理
<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>flatten-maven-plugin</artifactId>
	<version>1.3.0</version>
	<configuration>
		<!-- 配置扁平化后的 POM 文件的名称 -->
		<flattenedPomFilename>pom-xml-flattened</flattenedPomFilename>
		<!-- 是否更新原始 POM 文件 -->
		<updatePomFile>true</updatePomFile>
		<!-- 指定扁平化模式,resolveCiFriendliesOnly 表示仅解析 CI 友好的占位符 -->
		<flattenMode>resolveCiFriendliesOnly</flattenMode>
	</configuration>
	<executions>
		<!-- 定义插件的执行配置 -->
		<execution>
			<!-- 执行的唯一标识 -->
			<id>flatten</id>
			<!-- 指定插件绑定的生命周期阶段 -->
			<phase>process-resources</phase>
			<!-- 定义执行的目标 -->
			<goals>
				<!-- 执行扁平化操作 -->
				<goal>flatten</goal>
			</goals>
		</execution>
		<!-- 定义清理阶段的执行配置 -->
		<execution>
			<!-- 清理阶段的唯一标识 -->
			<id>flatten.clean</id>
			<!-- 指定清理阶段绑定的生命周期阶段 -->
			<phase>clean</phase>
			<!-- 定义清理阶段执行的目标 -->
			<goals>
				<!-- 执行清理操作 -->
				<goal>clean</goal>
			</goals>
		</execution>
	</executions>
</plugin>

# 配置资源处理

Maven在默认情况下是从当前项目的src\main\resources下读取文件进行打包

<build>
    <resources>
	     <resource>
		    <!-- ${project.basedir}:当前项目所在目录,相当于所有子项目都添加了资源目录过滤 -->
			<directory>${project.basedir}/src/main/resources</directory>
			<!-- 所有文件,关闭过滤 -->
			<filtering>false</filtering>
		</resource>
        <resource>
            <directory>${project.basedir}/src/main/resources</directory>
			<!-- 匹配文件进行过滤 -->
			<includes>
				<include>application*</include>
				<include>bootstrap*</include>
				<include>logback*</include>
			</includes>
            <!--启用过滤 即该资源中的变量将会被过滤器中的值替换,即能够解析${},默认是false -->
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

# 仓库设置

<!-- 仓库地址 -->
<repositories>
	<repository>
		<id>public</id>
		<name>huawei nexus</name>
		<url>https://mirrors.huaweicloud.com/repository/maven/</url>
		<releases>
			<enabled>true</enabled>
		</releases>
	</repository>
</repositories>
<!-- 插件仓库地址 -->
<pluginRepositories>
	<pluginRepository>
		<id>public</id>
		<name>huawei nexus</name>
		<url>https://mirrors.huaweicloud.com/repository/maven/</url>
		<releases>
			<enabled>true</enabled>
		</releases>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</pluginRepository>
</pluginRepositories>

# 将jar包打包到本地仓库

  • 将下载的jar包放到一个你知道的位置,比如我放在 D:/maven/repository/ojdbc6.jar
  • 然后打开cmd,执行:
# install:可以将项目本身编译并打包到本地仓库
# install-file:安装文件
mvn install:install-file -Dfile=/D:/maven/repository/ojdbc6.jar # 指定要打的包的文件位置
                         -DgroupId=com.oracle # 指定当前包的groupId
						 -DartifactId=ojdbc6  # 指定当前包的artifactfactId
						 -Dversion=11.2.0.1.0 # 指定当前包的版本
						 -Dpackaging=jar 
						 -DgeneratePom=true   # 是否生成pom文件

maven-install

  • 根据install位置找到需要的jar,放在maven本地仓库指定路径,最后引入
# D:\maven\repository\com\oracle\ojdbc\ojdbc6\11.2.0.1.0

# 私服

私服是一台独立的服务器,用于解决团队内部的资源共享与资源同步问题。Nexus是Sonatype公司的一款maven私服产品 下载地址 (opens new window)

# 使用cmd进入到解压目录下的bin,执行如下命令启动nexus服务器
nexus.exe /run nexus

# 访问地址为
http://localhost:8081

# 首次登录重置密码
用户名:admin  密码:根据登录提示进入文件查看初始密码

# 修改基础配置信息
etc目录中nexus-default.properties

注意

安装路径不能有中文

# 私服仓库的分类

宿主仓库hosted(用于上传)
# 小组内自己用的,自主研发的
# 无法从中央仓库获取的资源,比如Oracle,因为是付费产品,所以中央仓库没有
  
代理仓库proxy(用于下载)
# 所有项目组公用的,仓库组内只有一个
# 代理远程仓库,转调中央仓库,通过nexus访问中央仓库
  
仓库组group(用于下载)
# 将若干个仓库组成一个群组,用来打包下载
# 仓库组不能保存资源,属于设计型仓库

私服仓库的分类

# 本地仓库访问私服配置

  • 私服上配置仓库:创建名为xxx-snapshot和xxx-release宿主仓库hosted
  • 配置本地Maven对私服的访问权限
<!--在本地Maven的配置文件settings.xml中进行配置-->
<servers>
    <server>
        <id>itheima-snapshot</id>
        <username>admin</username>
        <password>admin</password>
    </server>
    <server>
        <id>itheima-release</id>
        <username>admin</username>
        <password>admin</password>
    </server>
</servers>
  • 配置私服的访问路径
<!--在本地Maven的配置文件settings.xml中进行配置-->
<mirrors>
    <mirror>
        <!--配置仓库组的ID-->
        <id>maven-public</id>
        <!--*代表所有内容都从私服获取-->
        <mirrorOf>*</mirrorOf>
        <!--私服仓库组maven-public的访问路径-->
        <url>http://localhost:8081/repository/maven-public/</url>
    </mirror>
</mirrors>

配置私服的访问路径

# 私服资源上传与下载

  • 配置工程上传私服的具体位置
 <!--配置当前工程保存在私服中的具体位置-->
<distributionManagement>
    <repository>
        <!--和maven/settings.xml中server中的id一致,表示使用该id对应的用户名和密码-->
        <id>itheima-release</id>
         <!--release版本上传仓库的具体地址-->
        <url>http://localhost:8081/repository/itheima-release/</url>
    </repository>
    <snapshotRepository>
        <!--和maven/settings.xml中server中的id一致,表示使用该id对应的用户名和密码-->
        <id>itheima-snapshot</id>
        <!--snapshot版本上传仓库的具体地址-->
        <url>http://localhost:8081/repository/itheima-snapshot/</url>
    </snapshotRepository>
</distributionManagement>
  • 发布资源到私服或者执行Maven命令
mvn deploy
  • 现在发布是在itheima-snapshot仓库中,如果想发布到itheima-release仓库中就需要将父工程和子模块parent标签里继承父工程parent中的version修改成RELEASE即可。
<groupId>com.itheima</groupId>
<artifactId>maven_01_parent</artifactId>
<version>1.0-RELEASE</version>
<packaging>pom</packaging>
	
	
<parent>
    <groupId>com.itheima</groupId>
    <artifactId>maven_01_parent</artifactId>
    <version>1.0-RELEASE</version>
    <!--快速找到父工程的pom文件的相关路径,可以不写-->
    <relativePath>../maven_01_parent/pom.xml</relativePath>
</parent>

注意

要发布的项目都需要配置分配管理distributionManagement标签,要么在自己的pom.xml中配置,要么在其父项目中配置,然后子项目中继承父项目即可

# 私服配置阿里云镜像

如果私服中没有对应的jar,会去中央仓库下载,速度很慢。可以配置让私服去阿里云中下载依赖。 私服配置阿里云镜像