maven
1.介绍与下载
1.1介绍
- Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供构建和依赖管理支持的工具
1.1.1构建
Java 项目开发过程中,构建指的是使用『原材料生产产品』的过程。
-
原材料
-
Java 源代码
-
基于 HTML 的 Thymeleaf 文件
-
图片
-
配置文件
-
.....
-
-
产品
- 一个可以在服务器上运行的项目构建过程包含的主要的环节:
- 清理:删除上一次构建的结果,为下一次构建做好准备
- 编译:Java 源程序编译成 *.class 字节码文件
- 测试:运行提前准备好的测试程序
- 报告:针对刚才测试的结果生成一个全面的信息
- 打包
- Java工程:jar包
- Web工程:war包
- 安装:把一个 Maven 工程经过打包操作生成的 jar 包或 war 包存入 Maven 仓库
- 部署
- 部署 jar 包:把一个 jar 包部署到 Nexus 私服服务器上
- 部署 war 包:借助相关 Maven 插件(例如 cargo),将 war 包部署到 Tomcat 服务器上
- 一个可以在服务器上运行的项目构建过程包含的主要的环节:
1.1.2依赖
- 如果 A 工程里面用到了 B 工程的类、接口、配置文件等等这样的资源,那么我们就可以说 A 依赖 B。例如:
- junit-4.12 依赖 hamcrest-core-1.3
- thymeleaf-3.0.12.RELEASE 依赖 ognl-3.1.26
- ognl-3.1.26 依赖 javassist-3.20.0-GA
- thymeleaf-3.0.12.RELEASE 依赖 attoparser-2.0.5.RELEASE
- thymeleaf-3.0.12.RELEASE 依赖 unbescape-1.1.6.RELEASE
- thymeleaf-3.0.12.RELEASE 依赖 slf4j-api-1.7.26
- 依赖管理中要解决的具体问题:
- jar 包的下载:使用 Maven 之后,jar 包会从规范的远程仓库下载到本地
- jar 包之间的依赖:通过依赖的传递性自动完成
- jar 包之间的冲突:通过对依赖的配置进行调整,让某些jar包不会被导入
1.2下载
- 打开官网:https://maven.apache.org/
- 点击下载,选择对应的版本
- 解压
1.3配置
1.3.1配置阿里云提供的镜像仓库
Maven 下载 jar 包默认访问境外的中央仓库,而国外网站速度很慢。改成阿里云提供的镜像仓库,访问国内网站,可以让 Maven 下载 jar 包的时候速度更快。
-
找到
conf
目录下的settings.xml
文件 -
找到
mirror
标签,将原有的例子配置注释掉-
<mirror> <id>maven-default-http-blocker</id> <mirrorOf>external:http:*</mirrorOf> <name>Pseudo repository to mirror external repositories initially using HTTP.</name> <url>http://0.0.0.0/</url> <blocked>true</blocked> </mirror>
-
-
加入阿里云的镜像仓库地址
-
<mirror> <id>nexus-aliyun</id> <mirrorOf>central</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror>
-
1.3.2配置 Maven 工程的基础 JDK 版本
如果按照默认配置运行,Java 工程使用的默认 JDK 版本是 1.5,而我们熟悉和常用的是 JDK 1.8 版本。修改配置的方式是:将 profile 标签整个复制到 settings.xml 文件的 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>
1.3.3配置 MAVEN_HOME
- 复制
maven
存放的路径 - 新建系统变量
1.3.4配置PATH
- 在系统变量找到
path
- 点击新建,将这个添加上去
1.3.5验证
- 验证是否配置成功
- 输入命令:
mvn -v
- 出现这样的代码即为配置成功
2.使用(命令行)
2.1创建项目
①使用
mvn archetype:generate
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 7:【直接回车,使用默认值】
Define value for property 'groupId': [项目名称]
Define value for property 'artifactId':[模块名称]
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
-
含义
- POM:Project Object Model,项目对象模型。和 POM 类似的是:DOM(Document Object Model),文档对象模型。它们都是模型化思想的具体体现。
-
模型化思想
- POM 表示将工程抽象为一个模型,再用程序中的对象来描述这个模型。这样我们就可以用程序来管理项目了。我们在开发过程中,最基本的做法就是将现实生活中的事物抽象为模型,然后封装模型相关的数据作为一个对象,这样就可以在程序中计算与现实事物相关的数据。
-
对应的配置文件
-
POM 理念集中体现在 Maven 工程根目录下 pom.xml 这个配置文件中。所以这个 pom.xml 配置文件就是 Maven 工程的核心配置文件。其实学习 Maven 就是学这个文件怎么配置,各个配置有什么用。
-
<!-- 当前Maven工程的坐标 --> <groupId>com.atguigu.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>
-
④约定的目录结构
- 各个目录的作用
- 另外还有一个 target 目录专门存放构建操作输出的结果
- 约定目录结构的意义
- Maven 为了让构建过程能够尽可能自动化完成,所以必须约定目录结构的作用。
- 例如:Maven 执行编译操作,必须先去 Java 源程序目录读取 Java 源代码,然后执行编译,最后把编译结果存放在 target 目录。
- Maven 为了让构建过程能够尽可能自动化完成,所以必须约定目录结构的作用。
- 约定大于配置
- Maven 对于目录结构这个问题,没有采用配置的方式,而是基于约定。这样会让我们在开发过程中非常方便。如果每次创建 Maven 工程后,还需要针对各个目录的位置进行详细的配置,那肯定非常麻烦。
- 目前开发领域的技术发展趋势就是:约定大于配置,配置大于编码。
2.2构建
①要求
-
运行 Maven 中和构建操作相关的命令时,必须进入到 pom.xml 所在的目录。如果没有在 pom.xml 所在的目录运行 Maven 的构建命令,那么会看到下面的错误信息:
-
The goal you specified requires a project to execute but there is no POM in this directory
-
-
mvn -v 命令和构建操作无关,只要正确配置了 PATH,在任何目录下执行都可以。而构建相关的命令要在 pom.xml 所在目录下运行——操作哪个工程,就进入这个工程的 pom.xml 目录。
②clean
-
mvn clean 删除 target 目录
③编译
-
主程序编译
-
mvn compile
-
-
测试程序编译
-
mvn test-compile
-
-
主体程序编译结果存放的目录:
target/classes
-
测试程序编译结果存放的目录:
target/test-classes
④测试
-
mvn test 执行代码
-
测试的报告存放的目录:
target/surefire-reports
⑤打包
-
mvn package
-
打包的结果——jar 包,存放的目录,
target
⑥安装
-
mvn install
2.3创建web工程
①使用
注意:如果在上一个工程的目录下执行 mvn archetype:generate 命令,那么 Maven 会报错:不能在一个非 pom 的工程下再创建其他工程。所以不要再刚才创建的工程里再创建新的工程,请回到工作空间根目录来操作。
-
mvn archetype:generate -D archetypeGroupId=org.apache.maven.archetypes -D archetypeArtifactId=maven-archetype-webapp -D archetypeVersion=1.4
-
Define value for property 'groupId': 项目名称 Define value for property 'artifactId': 工程名称 Define value for property 'version' 1.0-SNAPSHOT: :【直接回车,使用默认值】 Define value for property 'package' com.chenchen.maven: :【直接回车,使用默认值】 Confirm properties configuration: groupId: com.chenchen.maven artifactId: maven-web version: 1.0-SNAPSHOT package: com.chenchen.maven Y: :【直接回车,表示确认】
②导入依赖
-
对于不知道详细信息的依赖可以到https://mvnrepository.com/网站查询。使用关键词搜索,然后在搜索结果列表中选择适合的使用。
-
比如:servlet-api 的依赖信息
-
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>
-
2.4依赖
①范围
-
标签的位置:
dependencies/dependency/scope
-
标签的可选值:compile/test/provided/system/runtime/import
main目录(空间) test目录(空间) 开发过程(时间) 部署到服务器(时间) compile 有效 有效 有效 有效 test 无效 有效 有效 无效 provided 有效 有效 有效 无效 -
compile:通常使用的第三方框架的 jar 包这样在项目实际运行时真正要用到的 jar 包都是以 compile 范围进行依赖的。比如 SSM 框架所需jar包。
-
test:测试过程中使用的 jar 包,以 test 范围依赖进来。比如 junit。
-
provided:在开发过程中需要用到的“服务器上的 jar 包”通常以 provided 范围依赖进来。
- 比如 servlet-api、jsp-api。
- 而这个范围的 jar 包之所以不参与部署、不放进 war 包,就是避免和服务器上已有的同类 jar 包产生冲突,同时减轻服务器的负担。
- 说白了就是:“服务器上已经有了,你就别带啦!”
②传递性
- 在 A 依赖 B,B 依赖 C 的前提下,C 是否能够传递到 A,取决于 B 依赖 C 时使用的依赖范围。
- B 依赖 C 时使用 compile 范围:可以传递
- B 依赖 C 时使用 test 或 provided 范围:不能传递,所以需要这样的 jar 包时,就必须在需要的地方明确配置依赖才可以。
③依赖的排除
-
当 A 依赖 B,B 依赖 C 而且 C 可以传递到 A 的时候,A 不想要 C,需要在 A 里面把 C 排除掉。
- 而往往这种情况都是为了避免 jar 包之间的冲突。
- 所以配置依赖的排除其实就是阻止某些 jar 包的传递。因为这样的 jar 包传递过来会和其他 jar 包冲突。
-
配置方式
-
<dependency> <groupId>com.atguigu.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>
-
2.5继承
①作用
- 在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
- 背景:
- 对一个比较大型的项目进行了模块拆分。
- 一个 project 下面,创建了很多个 module。
- 每一个 module 都需要配置自己的依赖信息。
- 需求:
- 在每一个 module 中各自维护各自的依赖信息很容易发生出入,不易统一管理。
- 使用同一个框架内的不同 jar 包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
- 使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索。
- 通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力。
②使用
-
创建父工程
-
需要修改打包方式
-
<!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 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.atguigu.maven</groupId> <artifactId>pro03-maven-parent</artifactId> <version>1.0-SNAPSHOT</version> </parent> <!-- 子工程的坐标 --> <!-- 如果子工程坐标中的groupId和version与父工程一致,那么可以省略 --> <!-- <groupId>com.atguigu.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>
-
-
自定义属性
-
<!-- 通过自定义属性,统一指定Spring的版本 --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- 自定义标签,维护Spring版本数据 --> <atguigu.spring.version>4.3.6.RELEASE</atguigu.spring.version> </properties>
-
在需要的地方使用${}的形式来引用自定义的属性名
-
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${atguigu.spring.version}</version> </dependency>
-
2.6聚合
①含义
部分组成整体
②好处
- 一键执行 Maven 命令:很多构建命令都可以在“总工程”中一键执行。
- 以 mvn install 命令为例:Maven 要求有父工程时先安装父工程;
- 有依赖的工程时,先安装被依赖的工程。我们自己考虑这些规则会很麻烦。
- 但是工程聚合之后,在总工程执行 mvn install 可以一键完成安装,而且会自动按照正确的顺序执行。
- 配置聚合之后,各个模块工程会在总工程中展示一个列表,让项目中的各个模块一目了然。
③配置
-
在总工程中配置 modules 即可:
-
<modules> <module>pro04-maven-module</module> <module>pro05-maven-module</module> <module>pro06-maven-module</module> </modules>
-
④循环问题
-
如果 A 工程依赖 B 工程,B 工程依赖 C 工程,C 工程又反过来依赖 A 工程,那么在执行构建操作时会报下面的错误:(循环引用)
-
DANGER [ERROR] [ERROR] The projects in the reactor contain a cyclic reference:
-
3.使用(idea)
3.1创建
-
创建父工程:
新建
→项目
→Maven
- 不打钩
-
创建子工程(java):
新建
→模块
→Maven
- 选择父项
-
创建子工程(web):
新建
→模块
→Maven
- 右击
模块
→添加框架
→选择第一个
- 将生成的
web
目录放到main
目录下面
- 右击
3.2其他操作
①在idea执行maven命令
- 直接执行
- 手动输入
②导入
- 工程导入
- 直接打开项目
- 修改
settings
中的maven
- 子工程导入(java)
- 将模块复制到工程下面
- 选择刚才导入的目录
- 在模块的
pom.xml
文件修改父工程的坐标 - java的图标变为蓝色的即为导入成功
- 子工程导入(Web)
- 其它操作和上面演示的都一样
- 只是多一步:删除多余的、不正确的 web.xml 设置