一、简述
1. Maven 作为依赖管理工具
项目需要的 jar 包规模大,下载来源复杂,
有些不规范,jar 包依赖关系复杂,使用
Maven之后,依赖所对应的 jar 包可以自
动下载,方便快捷又规范
2. Maven 作为构建管理工具
3. 构建
指使用原材料生产产品的过程
构建过程包含的主要的环节:
清理:清除上一次构建的结果,为下一次
构建做好准备
编译:Java源程序编译成 *.class 字节码文
件
测试:运行提前准备好的测试程序
报告:针对刚才测试的结果生成一个全面
的信息
打包:Java工程,jar包
Web工程,war包
安装:把一个Maven工程经过打包操作生
成的 jar 包或 war 包安装到 Maven
仓库
部署:jar 包,把一个 jar 包部署到 Nexus
私服服务器上
war 包,借助相关Maven插件(例如cargo),
将war包部署到 Tomcat 服务器上
4. 依赖
如果A工程里面用到了B工程的类、接口、配置文件
等等这样的资源,那么我们就可以说A依赖B
依赖管理中要解决的具体问题:
① jar 包的下载:使用Maven之后,jar包会从规
范的远程仓库下载到本地
② jar 包之间的依赖:通过依赖的传递性自动完成
③ jar 包之间的冲突:通过对依赖的配置进行调整,
让某些jar包不会被导入
5. Maven 的工作机制
二、Maven 核心程序解压和配置
1. 下载页面:Maven – Download Apache Maven
2. 解压核心文件:conf/settings.xml
3. 指定本地仓库
4. 配置阿里云提供的镜像仓库
Maven 下载 jar 包默认访问境外的中央仓库,
而国外网站速度很慢,改成阿里云提供的镜像
仓库,访问国内网站,可以让 Maven 下载 jar
包的时候速度更快
注释掉原代码,将下面 mirror 标签整体复制到
settings.xml 文件的mirrors 标签的内部
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
5. 配置 Maven 工程的基础 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>
6. 环境变量
(1) 检查 JAVA_HOME配置是否正确
验证代码:
C:\Users\Administrator>java -version
(2) 配置 MAVEN_HOME
(3) 配置PATH
验证代码:
C:\Users\Administrator>mvn -v
三、使用Maven:命令行环境
1. 根据坐标创建Maven工程
(1) Maven 核心概念:坐标
1) 三个向量
使用三个向量在Maven的仓库中唯一的定位到
一个jar包
grouopId:公司或组织的 Id,com.baidu.maven
artifactId:一个项目或者项目中的一个模块的 Id
pro01-baidu-maven
version:版本号,1.0-SNAPSHOT
SNAPSHOT 表示快照版本,正在迭代
过程中,不稳定的版本
RELEASE 表示正式版本
2) 坐标和仓库中jar包的存储路径之间的对应关系
坐标:
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
对应jar包在Maven本地仓库中位置:
Maven本地仓库根目录\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar
(2) 操作
① 创建目录作为后面操作的工作空间
例如:D:\maven-workspace\space201026
此时已有三个目录:
Maven 核心程序:中军大帐
Maven 本地仓库:兵营
本地工作空间:战场
② 在工作空间目录下打开命令行窗口
③ 使用命令生成 Maven工程
运行 mvn archetype:generate 命令
下面根据提示操作命令:
TIP
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 7:【直接回车,使用默认值】
Define value for property 'groupId': com.atguigu.maven
Define value for property 'artifactId': pro01-maven-java
Define value for property 'version' 1.0-SNAPSHOT: :【直接回车,使用默认值】
Define value for property 'package' com.atguigu.maven: :【直接回车,使用默认值】
Confirm properties configuration: groupId: com.atguigu.maven artifactId: pro01-maven-java version: 1.0-SNAPSHOT package: com.atguigu.maven Y: :【直接回车,表示确认。如果前面有输入错误,想要重新输入,则输入 N 再回车。】
④ 调整
Maven 默认生成的工程,对 junit 依赖的是较低
的 3.8.1 版本,我们可以改成较适合的 4.12 版本
自动生成的 App.java 和 AppTest.java 可以删除
<!-- 依赖信息配置 -->
<!-- dependencies复数标签:里面包含dependency单数标签 -->
<dependencies>
<!-- dependency单数标签:配置一个具体的依赖 -->
<dependency>
<!-- 通过坐标来依赖其他jar包 -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- 依赖的范围 -->
<scope>test</scope>
</dependency>
</dependencies>
⑤ 自动生成的 pom.xml 解读
<!-- 当前Maven工程的坐标 -->
<groupId>com.baidu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前Maven工程的打包方式,可选值有下面三种: -->
<!-- jar:表示这个工程是一个Java工程 -->
<!-- war:表示这个工程是一个Web工程 -->
<!-- pom:表示这个工程是“管理其他工程”的工程 -->
<packaging>jar</packaging>
<name>pro01-maven-java</name>
<url>http://maven.apache.org</url>
<properties>
<!-- 工程构建过程中读取源码时使用的字符集 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 当前工程所依赖的jar包 -->
<dependencies>
<!-- 使用dependency配置一个具体的依赖 -->
<dependency>
<!-- 在dependency标签内使用具体的坐标依赖我们需要的一个jar包 -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- scope标签配置依赖的范围 -->
<scope>test</scope>
</dependency>
</dependencies>
(3) Maven 核心概念:POM
POM:Project Object Medol,项目对象模型,
和DOM文档对象模型都是模型化思想的具体
体现
对应 pom.xml 就是 Maven工程的核心配置文件
模型化思想:POM表示将一个工程抽象为一个
模型,再用程序中的对象来描述。
开发中多将现实生活中的事物抽象
为模型,然后封装模型相关的数据
作为一个对象,这样就可以在程序
中计算与现实事物相关的数据
(3) Maven 核心概念:约定的目录结构
① 各个目录的作用
另外还有一个 target 目录专门存放构建
操作输出的结果
② 约定目录结构的意义
为了让构建过程能够尽可能的自动化完成,
所以必须约定目录结构
③ 约定大于配置,配置大于编码
2. 在Maven工程中编写代码
(1) 主体程序
主体程序指的是被测试的程序,同时也是将
来在项目中真正要使用的程序
package com.baidu.maven;
public class Calculator {
public int sum(int i, int j){
return i + j;
}
}
(2) 测试程序
package com.baidu.maven;
import org.junit.Test;
import com.baidu.maven.Calculator;
// 静态导入的效果是将Assert类中的静态资源导入当前类
// 这样一来,在当前类中就可以直接使用Assert类中的静态资源,不需要写类名
import static org.junit.Assert.*;
public class CalculatorTest{
@Test
public void testSum(){
// 1.创建Calculator对象
Calculator calculator = new Calculator();
// 2.调用Calculator对象的方法,获取到程序运行实际的结果
int actualResult = calculator.sum(5, 3);
// 3.声明一个变量,表示程序运行期待的结果
int expectedResult = 8;
// 4.使用断言来判断实际结果和期待结果是否一致
// 如果一致:测试通过,不会抛出异常
// 如果不一致:抛出异常,测试失败
assertEquals(expectedResult, actualResult);
}
}
3. 执行Maven的构建命令
(1) 要求
运行 Maven 中和构建操作相关的命令时,必须
进入到 pom.xml 所在的目录,如果没有在
pom.xml 所在的目录运行 Maven 的构建命令,
那么会看到以下错误信息
The goal you specified requires a project to execute but there is no POM in this directory
TIP
mvn -v 命令和构建操作无关,只要正确配置了
PATH,在任何目录下执行都可以。而构建相关
的命令要在 pom.xml 所在目录下运行——操作
哪个工程,就进入这个工程的 pom.xml 目录
(2) 清理操作
mvn clean
效果:删除 target 目录
(3) 编译操作
主程序编译:mvn compile
测试程序编译:mvn test-compile
主体程序编译结果存放的目录:target/classes
测试程序编译结果存放的目录:target/test-classes
(4) 测试操作
mvn test
测试的报告存放的目录:target/surefire-reports
(5) 打包操作
mvn package
打包的结果——jar 包,存放的目录:target
(6) 安装操作
mvn install
[INFO] Installing D:\maven-workspace\space201026\pro01-maven-java\target\pro01-maven-java-1.0-SNAPSHOT.jar to D:\maven-rep1026\com\atguigu\maven\pro01-maven-java\1.0-SNAPSHOT\pro01-maven-java-1.0-SNAPSHOT.jar
[INFO] Installing D:\maven-workspace\space201026\pro01-maven-java\pom.xml to D:\maven-rep1026\com\baidu\maven\pro01-maven-java\1.0-SNAPSHOT\pro01-maven-java-1.0-SNAPSHOT.pom
安装的效果是将本地构建过程中生成的 jar
包存入 Maven 本地仓库。这个 jar 包在
Maven 仓库中的路径是根据它的坐标生成
的
坐标信息如下:
<groupId>com.baidu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
在 Maven 仓库中生成的路径如下:
D:\maven-rep1026\com\baidu\maven\pro01-maven-java\1.0-SNAPSHOT\pro01-maven-java-1.0-SNAPSHOT.jar
另外,安装操作还会将 pom.xml 文件转换为
XXX.pom 文件一起存入本地仓库。
所以我们在 Maven 的本地仓库中想看一个
jar 包原始的 pom.xml 文件时,查看对应
XXX.pom 文件即可,它们是名字发生了改变,
本质上是同一个文件
4. 创建Maven版的Web工程
使用 mvn archetype:generate 命令生成 Web
工程时,需要使用一个专门的 archetype
这个专门生成 Web 工程骨架的 archetype 可以
参照官网看到它的用法:
参数 archetypeGroupId、archetypeArtifactId、
archetypeVersion 用来指定现在使用的 maven-
archetype-webapp 的坐标
(2) 操作
注意:如果在上一个工程的目录下执行 mvn
archetype:generate 命令,那么 Maven 会报错:
不能在一个非 pom 的工程下再创建其他工程。
所以不要再刚才创建的工程里再创建新的工程,
请回到工作空间根目录来操作
然后运行生成工程的命令:
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4
下面的操作按照提示执行:
TIP
Define value for property 'groupId': com.atguigu.maven Define value for property 'artifactId': pro02-maven-web Define value for property 'version' 1.0-SNAPSHOT: :【直接回车,使用默认值】
Define value for property 'package' com.atguigu.maven: :【直接回车,使用默认值】 Confirm properties configuration: groupId: com.atguigu.maven artifactId: pro02-maven-web version: 1.0-SNAPSHOT package: com.atguigu.maven Y: :【直接回车,表示确认】
(3) 生成的 pom.xml
确认打包的方式是 war 包形式
<packaging>war</packaging>
(4) 生成的 Web 工程的目录结构
webapp 目录下有 index.jsp
WEB-INF 目录下有 web.xml
(5) 创建 Servlet
① 在 main 目录下创建 java 目录
② 在 java 目录下创建 Servlet 类所在的
包的目录
③ 在包下创建 Servlet 类
package com.baidu.maven;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;
public class HelloServlet extends HttpServlet{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("hello maven web");
}
}
④ 在 web.xml 中注册 Servlet
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.baidu.maven.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/helloServlet</url-pattern>
</servlet-mapping>
(6) 在 index.jsp 页面编写超链接
<html>
<body>
<h2>Hello World!</h2>
<a href="helloServlet">Access Servlet</a>
</body>
</html>
TIP
JSP全称是 Java Server Page,和 Thymeleaf
一样,是服务器端页面渲染技术。这里我们不
必关心 JSP 语法细节,编写一个超链接标签即
可
(7) 编译
此时直接执行 mvn compile 命令出错:
DANGER
程序包 javax.servlet.http 不存在
程序包 javax.servlet 不存在
找不到符号
符号: 类 HttpServlet
……
上面的错误信息说明:我们的 Web 工程用到了
HttpServlet 这个类,而 HttpServlet 这个类属于
servlet-api.jar 这个 jar 包。此时我们说,Web
工程需要依赖 servlet-api.jar 包
(8) 配置对 servlet-api.jar 包的依赖
对于不知道详细信息的依赖可以到
网站查询,使用关键词搜索,然后在搜索
结果列表中选择适合的使用
比如,我们找到的 servlet-api 的依赖信息:
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
这样就可以把上面的信息加入 pom.xml,
重新执行 mvn compile 命令
(9) 将 Web 工程打包为 war 包
运行 mvn package 命令,生成 war 包的位置
如下图所示:
(10) 将 war 包部署到 Tomcat 上运行
启动Tomcat:
通过浏览器尝试访问:
http://localhost:8080/pro02-maven-web/index.jsp
5. 让Web工程依赖Java工程
一直都是 Web 工程依赖 Java 工程,没有反
过来 Java 工程依赖 Web 工程。
本质上来说,Web 工程依赖的 Java 工程其
实就是 Web 工程里导入的 jar 包。最终 Java
工程会变成 jar 包,放在 Web 工程的
WEB-INF/lib 目录下
(2) 操作
在 pro02-maven-web 工程的 pom.xml 中,找到
dependencies 标签,在 dependencies 标签中
做如下配置:
<!-- 配置对Java工程pro01-maven-java的依赖 -->
<!-- 具体的配置方式:在dependency标签内使用坐标实现依赖 -->
<dependency>
<groupId>com.baidu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
(3) 在 Web 工程中编写测试代码
① 补充创建目录
pro02-maven-web\src\test\java\com\baidu\maven
② 确认 web 工程依赖了 junit
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
③ 创建测试类
把 Java 工程的 CalculatorTest.java 类复制到
pro02-maven-wb\src\test\java\com\baidu\maven
目录下
(4) 执行 Maven 命令
① 测试命令
mvn test
说明:测试操作中会提前自动执行编译操作,
测试成功就说明编译也是成功的
② 打包命令
mvn package
通过查看 war 包内的结构,我们看到被 Web
工程依赖的 Java 工程确实是会变成 Web 工
程的 WEB-INF/lib 目录下的 jar 包
③ 查看当前 Web 工程所依赖的 jar 包的列表
mvn dependency:list
TIP
[INFO] The following files have been resolved:
[INFO] org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] com.baidu.maven:pro01-maven-java:jar:1.0-SNAPSHOT:compile
[INFO] junit:junit:jar:4.12:test
说明:javax.servlet:javax.servlet-api:jar:3.1.0:provided
格式显示的是一个 jar 包的坐标信息
格式是:
TIP
groupId:artifactId:打包方式:version:依赖的范围
④ 以树形结构查看当前 Web 工程的依赖信息
mvn dependency:tree
TIP
[INFO] com.atguigu.maven:pro02-maven-web:war:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:4.12:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] \- com.atguigu.maven:pro01-maven-java:jar:1.0-SNAPSHOT:compile
我们在 pom.xml 中并没有依赖 hamcrest-core,
但是它却被加入了我们依赖的列表。原因是:
junit 依赖了hamcrest-core,然后基于依赖的传
递性,hamcrest-core 被传递到我们的工程了
6. 依赖范围
(1) 依赖范围
标签的位置:dependencies/dependency/scope
标签的可选值:compile/test/provided/system/runtime/import
① compile 和 test 对比
main目录(空间) | test目录(空间) | 开发过程(时间) | 部署到服务器(时间) | |
compile | 有效 | 有效 | 有效 | 有效 |
test | 无效 | 有效 | 有效 | 无效 |
② compile 和 provided 对比
main目录(空间) | test目录(空间) | 开发过程(时间) | 部署到服务器(时间) | |
compile | 有效 | 有效 | 有效 | 有效 |
provided | 有效 | 有效 | 有效 | 无效 |
③ 结论
compile:通常使用的第三方框架的 jar 包这样在
项目实际运行时真正要用到的 jar 包都
是以 compile 范围进行依赖的。
比如 SSM 框架所需jar包
test:测试过程中使用的 jar 包,以 test 范围依赖
进来,比如 junit
provided:在开发过程中需要用到的"服务器上的
jar 包"
通常以 provided 范围依赖进来。比如 servlet-api、
jsp-api。而这个范围的 jar 包之所以不参与部署、不放
进 war 包,就是避免和服务器上已有的同类 jar 包产生
冲突,同时减轻服务器的负担
7. 依赖的传递性
(1) 传递的原则
在 A 依赖 B,B 依赖 C 的前提下,C 是否能够
传递到 A,取决于 B 依赖 C 时使用的依赖范围
① B 依赖 C 时使用 compile 范围:可以传递
② B 依赖 C 时使用 test 或 provided 范围:不能
传递,所以需要这样的 jar 包时,就必须在需要
的地方明确配置依赖才可以
8. 依赖的排除
当 A 依赖 B,B 依赖 C 而且 C 可以传递到 A 的
时候,A 不想要 C,需要在 A 里面把 C 排除掉
而往往这种情况都是为了避免 jar 包之间的冲突
所以配置依赖的排除其实就是阻止某些 jar 包的
传递,因为这样的 jar 包传递过来会和其他 jar
包冲突
配置方式:
<dependency>
<groupId>com.baidu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
<!-- 使用excludes标签配置依赖的排除 -->
<exclusions>
<!-- 在exclude标签中配置一个具体的排除 -->
<exclusion>
<!-- 指定要排除的依赖的坐标(不需要写version) -->
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
9. 继承
Maven工程之间,A 工程继承 B 工程
本质上是 A 工程的 pom.xml 中的配置继承
了 B 工程中 pom.xml 的配置
(2) 作用
在父工程中统一管理项目中的依赖信息,具体
来说是管理依赖信息的版本
背景:
① 对一个比较大型的项目进行了模块拆分
② 一个 project 下面,创建了很多个 module
③ 每一个 module 都需要配置自己的依赖信息
背后的需求:
① 在每一个 module 中各自维护各自的依赖信息
很容易发生出入,不易统一管理
② 使用同一个框架内的不同 jar 包,它们应该是
同一个版本,所以整个项目中使用的框架版本
需要统一
③ 使用框架时所需要的 jar 包组合(或者说依赖
信息组合)需要经过长期摸索和反复调试,最
终确定一个可用组合。这个耗费很大精力总结
出来的方案不应该在新的项目中重新摸索
小结:
通过在父工程中为整个项目维护依赖信息的组合既
保证了整个项目使用规范、准确的 jar 包;又能够
将以往的经验沉淀下来,节约时间和精力
(3) 操作
① 创建父工程
创建的过程和前面创建 pro01-maven-java 一样
工程名称:pro03-maven-parent
工程创建好之后,要修改它的打包方式:
<groupId>com.baidu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 pom -->
<packaging>pom</packaging>
只有打包方式为 pom 的 Maven 工程能够管理
其他 Maven 工程。打包方式为 pom 的 Maven
工程中不写业务代码,它是专门管理其他 Maven
工程的工程
② 创建模块工程
模块工程类似于 IDEA 中的 module,所以需要
进入 pro03-maven-parent 工程的根目录,然后
运行 mvn archetype:generate 命令来创建模块
工程
③ 查看被添加新内容的父工程 pom.xml
下面 modules 和 module 标签是聚合功能的配置
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
④ 解读子工程的 pom.xml
<!-- 使用parent标签指定当前工程的父工程 -->
<parent>
<!-- 父工程的坐标 -->
<groupId>com.baidu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 子工程的坐标 -->
<!-- 如果子工程坐标中的groupId和version与父工程一致,那么可以省略 -->
<!-- <groupId>com.baidu.maven</groupId> -->
<artifactId>pro04-maven-module</artifactId>
<!-- <version>1.0-SNAPSHOT</version> -->
⑤ 在父工程中配置依赖的统一管理
<!-- 使用dependencyManagement标签配置对依赖的管理 -->
<!-- 被管理的依赖并没有真正被引入到工程 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
⑥ 子工程中引用那些被父工程管理的依赖
关键点:省略版本号
<!-- 子工程引用父工程中的依赖信息时,可以把版本号去掉。 -->
<!-- 把版本号去掉就表示子工程中这个依赖的版本由父工程决定。 -->
<!-- 具体来说是由父工程的dependencyManagement来决定。 -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
</dependencies>
⑦ 在父工程中升级依赖信息的版本
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
然后在子工程中运行mvn dependency:list,效果如下:
TIP
[INFO] org.springframework:spring-aop:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-core:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-context:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-beans:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-expression:jar:4.1.4.RELEASE:compile
⑧ 在父工程中声明自定义属性
<!-- 通过自定义属性,统一指定Spring的版本 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 自定义标签,维护Spring版本数据 -->
<baidu.spring.version>4.3.6.RELEASE</baidu.spring.version>
</properties>
在需要的地方使用${}的形式来引用自定义的属性名:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${baidu.spring.version}</version>
</dependency>
真正实现 "一处修改,处处生效"
(4) 实际意义
10. 聚合
部分组成整体
(1) Maven 中的聚合
使用一个“总工程”将各个“模块工程”汇集起来,
作为一个整体对应完整的项目。
项目:整体
模块:部分
概念的对应关系:
从继承关系角度来看:
① 父工程
② 子工程
从聚合关系角度来看:
① 总工程
② 模块工程
(2) 好处
一键执行 Maven 命令:很多构建命令都可以
在“总工程”中一键执行
以 mvn install 命令为例:Maven 要求有父工
程时先安装父工程;有依赖的工程时,先安装
被依赖的工程。我们自己考虑这些规则会很麻
烦。但是工程聚合之后,在总工程执行 mvn
install 可以一键完成安装,而且会自动按照正
确的顺序执行
配置聚合之后,各个模块工程会在总工程中展
示一个列表,让项目中的各个模块一目了然
(3) 聚合的配置
在总工程中配置 modules 即可:
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
(4) 依赖循环问题
如果 A 工程依赖 B 工程,B 工程依赖 C 工程,
C 工程又反过来依赖 A 工程,那么在执行构建
操作时会报下面的错误:
DANGER
[ERROR] [ERROR] The projects in the reactor contain a cyclic reference:
这个错误的含义是:循环引用
四、使用 Maven:IDEA 环境
1. 创建父工程
(1) 创建 Project
(2) 开启自动导入
创建 Project 后,IDEA 会自动弹出下面提示,
我们选择『Enable Auto-Import』,意思是启
用自动导入
这个自动导入一定要开启,因为 Project、
Module 新创建或 pom.xml 每次修改时都应该
让 IDEA 重新加载 Maven 信息。这对 Maven
目录结构认定、Java 源程序编译、依赖 jar 包
的导入都有非常关键的影响
另外也可以通过 IDEA 的 Settings 设置来开启:
2. 配置 Maven 信息
每次创建 Project 后都需要设置 Maven 家目
录位置,否则 IDEA 将使用内置的 Maven
核心程序(不稳定)并使用默认的本地仓库
位置。这样一来,我们在命令行操作过程中
已下载好的 jar 包就白下载了,默认的本地
仓库通常在 C 盘,还影响系统运行
配置之后,IDEA 会根据我们在这里指定的
Maven 家目录自动识别到我们在 settings.xml
配置文件中指定的本地仓库
3. 创建 Java 模块工程
4. 创建 Web 模块工程
(1) 创建模块
按照前面的同样操作创建模块,此时这个模块
其实还是一个Java模块
(2) 修改打包方式
Web 模块将来打包当然应该是 war 包
<packaging>war</packaging>
(3) Web 设定
首先打开项目结构菜单:
然后到 Facets 下查看 IDEA 是否已经帮我们
自动生成了 Web 设定。正常来说只要我们确
实设置了打包方式为 war,那么 IDEA 就会自
动生成 Web 设定
如果没有,可手动创建
(4) 借助 IDEA 生成 web.xml
(5) 设置 Web 资源的根目录
结合 Maven 的目录结构,Web 资源的根目录
需要设置为 src/main/webapp 目录
5. 其他操作
(1) 在 IDEA 中执行 Maven 命令
① 直接执行
② 手动输入
如果有需要,还可以给命令后面附加参数:
# -D 表示后面要附加命令的参数,字母 D 和后面的参数是紧挨着的,中间没有任何其它字符
# maven.test.skip=true 表示在执行命令的过程中跳过测试
mvn clean install -Dmaven.test.skip=true
(2) 在 IDEA 中查看某个模块的依赖信息
(3) 工程导入
Maven工程除了自己创建的,还有很多情况
是别人创建的
1) 来自版本控制系统
目前我们通常使用的都是 Git(本地库) + 码
云(远程库) 的版本控制系统,结合 IDEA
的相关操作方式
2) 来自工程目录
① 工程压缩包
Maven 工程的 zip 压缩包:maven-rest-demo.zip
从码云或GitHub上也可以以 ZIP压缩格式对项目
代码打包下载
② 解压并打开
只要我们确认在解压目录下可以直接看到
pom.xml,那就能证明这个解压目录就是
我们的工程目录,那么接下来让 IDEA 打
开这个目录就可以了
③ 设置 Maven 核心程序位置
打开一个新的 Maven 工程,和新创建一个
Maven 工程是一样的,此时 IDEA 的 settings
配置中关于 Maven 仍然是默认值:
(4) 模块导入
① 在工程目录中,复制我们想要导入的模
块目录,粘贴到自己的工程目录下,在
IDEA 中执行导入
② 修改 pom.xml
刚刚导入的 module 的父工程坐标还是以
前的,需要改成我们自己的 project
最终效果:
③ 导入 Web 类型模块
其它操作和上面演示的都一样,只是多一步:
删除多余的、不正确的 web.xml 设置
五、其他核心概念
1. 生命周期
为了让构建过程自动化完成,Maven 设定
了三个生命周期,生命周期中的每一个环
节对应构建过程中的一个操作
生命周期名称 | 作用 | 各个环节 |
---|---|---|
Clean | 清理操作相关 | pre-clean clean post-clean |
Site | 生成站点相关 | pre-site site post-site deploy-site |
Default | 主要构建过程 | validate generate-sources process-sources generate-resources process-resources 复制并处理资源文件,至目标目录,准备打包。 compile 编译项目 main 目录下的源代码。 process-classes generate-test-sources process-test-sources generate-test-resources process-test-resources 复制并处理资源文件,至目标测试目录。 test-compile 编译测试源代码。 process-test-classes test 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。 prepare-package package 接受编译好的代码,打包成可发布的格式,如JAR。 pre-integration-test integration-test post-integration-test verify install将包安装至本地仓库,以让其它项目依赖。 deploy将最终的包复制到远程的仓库,以让其它开发人员共享;或者部署到服务器上运行(需借助插件,例如:cargo) |
特点:
① 前面三个生命周期彼此是独立的
② 在任何一个生命周期内部,执行任何一个
具体环节的操作,都是从本周期最初的位
置开始执行,直到指定的地方
2. 插件和目标
① 插件
Maven 的核心程序仅仅负责宏观调度,不做
具体工作,具体工作都是由 Maven 插件完成
的。
例如:编译就是由 maven-compiler-plugin-3.1.jar
插件来执行的
② 目标
一个插件可以对应多个目标,而每一个目标
都和生命周期中的某一个环节对应
Default 生命周期中有 compile 和 test-compile
两个和编译相关的环节,这两个环节对应 compile
和 test-compile 两个目标,而这两个目标都是由
maven-compiler-plugin-3.1.jar 插件来执行的
3. 仓库
本地仓库:在当前电脑上,为电脑上所有 Maven
工程服务
远程仓库:需要联网
局域网:我们自己搭建的 Maven 私服,例如
使用 Nexus 技术
Internet:
中央仓库
镜像仓库:内容和中央仓库保持一致,但
是能够分担中央仓库的负载,同时让
用户能够就近访问提高下载速度,
例如:Nexus aliyun
建议:不要中央仓库和阿里云镜像混用,否则
jar 包来源不纯,彼此冲突
专门搜索 Maven 依赖信息的网站: