⭐⭐⭐⭐⭐⭐
Github主页https://github.com/A-BigTree
笔记链接https://github.com/A-BigTree/Code_Learning
⭐⭐⭐⭐⭐⭐
如果可以,麻烦各位看官顺手点个star~
如果文章对你有所帮助,可以点赞收藏⭐支持一下博主~
向量说明:
使用三个『向量』在『Maven的仓库』中==唯一的定位==到一个『jar』包。
groupId
:公司或组织的id;artifactId
:一个项目或者是项目中的一个模块的id;version
:版本号;向量取值:
groupId
:公司或组织域名的倒序,通常也会加上项目名称
com.atguigu.maven
artifactId
:模块的名称,将来作为 Maven 工程的工程名version
:模块的版本号,根据自己的需要设定
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
坐标对应的jar包在Maven本地仓库中的位置:
Maven本地仓库根目录\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar
> mvn archetype:generate
根据提示操作:
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 2032:【回车,使用默认值】
Choose org.apache.maven.archetypes:maven-archetype-quickstart version:
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
7: 1.3
8: 1.4
Choose a number: 8:【回车,使用默认值】
Define value for property 'groupId': cn.seucs.maven
Define value for property 'artifactId': pro1_maven_test
Define value for property 'version' 1.0-SNAPSHOT: :【回车使用默认值】
Define value for property 'package' cn.seucs.maven: :【回车使用默认值】
Confirm properties configuration:
groupId: cn.seucs.maven
artifactId: pro1_maven_test
version: 1.0-SNAPSHOT
package: cn.seucs.maven
Y: :【回车确定】
Maven默认生成的工程,对junit
依赖的是较低的3.8.1版本,我们可以改成较适合的4.12版本。
自动生成的App.java
和AppTest.java
可以删除。
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
dependencies>
pom.xml
解读;
<groupId>com.atguigu.mavengroupId>
<artifactId>pro01-maven-javaartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>jarpackaging>
<name>pro01-maven-javaname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
dependencies>
POM:Project Object Model
,项目对象模型。和POM类似的是:DOM(Document Object Model)
,文档对象模型。它们都是模型化思想的具体体现。
POM
表示将工程抽象为一个模型,再用程序中的对象来描述这个模型。这样我们就可以用程序来管理项目了。我们在开发过程中,最基本的做法就是将现实生活中的事物抽象为模型,然后封装模型相关的数据作为一个对象,这样就可以在程序中计算与现实事物相关的数据。
POM
理念集中体现在Maven工程根目录下pom.xml
这个配置文件中。所以这个pom.xml
配置文件就是Maven工程的核心配置文件。其实学习Maven就是学这个文件怎么配置,各个配置有什么用。
另外还有一个target
目录专门存放构建操作输出的结果。
Maven
为了让构建过程能够尽可能==自动化==完成,所以必须约定目录结构的作用。例如:Maven
执行编译操作,必须先去Java源程序目录读取Java源代码,然后执行编译,最后把编译结果存放在target目录。
Maven 对于目录结构这个问题,没有采用配置的方式,而是基于约定。这样会让我们在开发过程中非常方便。如果每次创建Maven工程后,还需要针对各个目录的位置进行详细的配置,那肯定非常麻烦。
目前开发领域的技术发展趋势就是:约定大于配置,配置大于编码。
放在main/java
的package部分:
package com.atguigu.maven;
public class Calculator {
public int sum(int i, int j){
return i + j;
}
}
放在test/java
的package部分:
package com.atguigu.maven;
import org.junit.Test;
import com.atguigu.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);
}
}
运行Maven中和构建操作相关的命令时,必须进入 到pom.xml
所在的目录。
> mvn clean
target
目录主程序编译:
> mvn compile
target/classes
;测试程序编译:
> mvn test-compile
target/test-classes
;> mvn test
target/surefire-reports
;> mvn package
target
;> mvn install
[INFO] Installing D:\JavaWeb\code_test\maven_space\pro1_maven_test\target\pro1_maven_test-1.0-SNAPSHOT.jar to D:\maven_repository\cn\seucs\maven\pro1_maven_test\1.0-SNAPSHOT\pro1_maven_test-1.0-SNAPSHOT.jar
[INFO] Installing D:\JavaWeb\code_test\maven_space\pro1_maven_test\pom.xml to D:\maven_repository\cn\seucs\maven\pro1_maven_test\1.0-SNAPSHOT\pro1_maven_test-1.0-SNAPSHOT.pom
安装的效果是将本地构建过程中生成的 jar 包存入 Maven 本地仓库。这个 jar 包在 Maven 仓库中的路径是根据它的坐标生成的。
另外,安装操作还会将pom.xml
文件转换为XXX.pom
文件一起存入本地仓库。所以我们在Maven的本地仓库中想看一个jar包原始的pom.xml
文件时,查看对应XXX.pom
文件即可,它们是名字发生了改变,本质上是同一个文件。
mvn archetype:generate "-DarchetypeGroupId=org.apache.maven.archetypes" "-DarchetypeArtifactId=maven-archetype-webapp"
下面按照提示执行:
Define value for property 'groupId': cn.seucs.webapp 【组织名称】
Define value for property 'artifactId': pro2_maven_web 【项目名称】
Define value for property 'version' 1.0-SNAPSHOT: : 【默认回车】
Define value for property 'package' cn.seucs.webapp: : 【默认回车】
Confirm properties configuration:
groupId: cn.seucs.webapp 【默认回车】
artifactId: pro2_maven_web
version: 1.0-SNAPSHOT
package: cn.seucs.webapp
Y: : 【默认回车】
确认打包的方式是war包形式
<packaging>warpackaging>
pro2_maven_web
|-- pom.xml
`-- src
`-- main
`-- webapp
|-- WEB-INF
| `-- web.xml
`-- index.jsp
cn.seucs.webapp
JSP全称是 Java Server Page
,和Thymeleaf
一样,是服务器端页面渲染技术。这里我们不必关心JSP
语法细节,编写一个超链接标签即可。
servlet-api.jar
包的依赖对于不知道详细信息的依赖可以到https://mvnrepository.com/网站查询。使用关键词搜索,然后在搜索结果列表中选择适合的使用。
把相关的信息加入pom.xml
,执行mvn compile
命令。
明确一个意识:从来只有Web工程依赖Java工程,没有反过来Java工程依赖Web工程。本质上来说,Web工程依赖的Java工程其实就是Web工程里导入的jar包。最终Java工程会变成jar包,放在Web工程的WEB-INF/lib
目录下。
> mvn dependency:list
显示格式:groupId
:artifactId
:打包方式
:version
:依赖的范围
;
这样的格式虽然和我们XML配置文件中坐标的格式不同,但是本质上还是坐标信息,需要能够认识这样的格式,将来从Maven 命令的日志或错误信息中看到这样格式的信息,就能够识别出来这是坐标。进而根据坐标到Maven仓库找到对应的jar包,用这样的方式解决我们遇到的报错的情况。
以树形结构查看当前Web工程的依赖信息:
> mvn dependency:tree
标签位置: dependencies/dependency/scope
;
标签可选值: compile,test,provided,system,runtime,import
;
为默认的依赖有效范围。如果在定义依赖关系的时候,没有明确指定依赖有效范围的话,则默认采用该依赖有效范围。此种依赖,在 编译、运行、测试时均有效;
只在测试时有效,测试过程中使用的 jar 包,以 test 范围依赖进来。比如junit
;
在编译、测试时有效,但是在运行时无效。例如:servlet-api
,运行项目时,容器已经提供,就不需要Maven重复地引入一遍了
在运行、测试时有效,但是在编译代码时无效。例如:JDBC
驱动实现,项目代码编译只需要JDK
提供的JDBC
接口,只有在测试或运行项目时才需要实现上述接口的具体JDBC
驱动。
在编译、测试时有效,但是在运行时无效。和provided的区别是,使用system范围的依赖时必须通过systemPath
元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。systemPath
元素可以引用环境变量。
scope取值 | 有效范围(compile, runtime, test) | 依赖传递 | 例子 |
---|---|---|---|
compile | all | 是 | spring-core |
provided | compile, test | 否 | servlet-api |
runtime | runtime, test | 是 | JDBC驱动 |
test | test | 否 | JUnit |
system | compile, test | 是 |
当A依赖B,B依赖X;同时A依赖C,C依赖另一版本的X,这时需要在A里将B依赖的X排除掉,为了避免jar包之间的冲突。
所以配置依赖的排除其实就是阻止某些jar包的传递。因为这样的jar包传递过来会和其他jar包冲突。
<dependency>
<groupId>com.atguigu.mavengroupId>
<artifactId>pro01-maven-javaartifactId>
<version>1.0-SNAPSHOTversion>
<scope>compilescope>
<exclusions>
<exclusion>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
exclusion>
exclusions>
dependency>
Maven工程之间,A工程继承B工程
本质上是A工程的pom.xml
中的配置继承了B工程中pom.xml
的配置。
在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
背景:
project
下面,创建了很多个module
;module
都需要配置自己的依赖信息;需求:
module
中各自维护各自的依赖信息很容易发生出入,不易统一管理;jar
包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一;jar
包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索;通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的jar
包;又能够将以往的经验沉淀下来,节约时间和精力。
在一个工程中依赖多个Spring的jar包:
[INFO] +- org.springframework:spring-core:jar:4.0.0.RELEASE:compile
[INFO] | \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] +- org.springframework:spring-beans:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-expression:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-aop:jar:4.0.0.RELEASE:compile
[INFO] | \- aopalliance:aopalliance:jar:1.0:compile
使用Spring时要求所有Spring自己的jar包版本必须一致。为了能够对这些jar包的版本进行统一管理,我们使用继承这个机制,将所有版本信息统一在父工程中进行管理。
工程创建好之后,要修改它的打包方式:
<groupId>com.atguigu.mavengroupId>
<artifactId>pro03-maven-parentartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>pompackaging>
只有打包方式为pom
的Maven工程能够管理其他Maven工程。打包方式为pom
的Maven工程中不写业务代码,它是专门管理其他Maven工程的工程。
模块工程类似于IDEA中的module,所以需要进入父工程的根目录,然后运行mvn archetype:generate
命令来创建模块工程。
pom.xml
下面modules
和module
是**聚合功能**的配置
<modules>
<module>pro04-maven-modulemodule>
<module>pro05-maven-modulemodule>
<module>pro06-maven-modulemodule>
modules>
pom.xml
<parent>
<groupId>com.atguigu.mavengroupId>
<artifactId>pro03-maven-parentartifactId>
<version>1.0-SNAPSHOTversion>
parent>
<artifactId>pro04-maven-moduleartifactId>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>4.0.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>4.0.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>4.0.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-expressionartifactId>
<version>4.0.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>4.0.0.RELEASEversion>
dependency>
dependencies>
dependencyManagement>
关键点:省略版本号
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-expressionartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
dependency>
dependencies>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<atguigu.spring.version>4.3.6.RELEASEatguigu.spring.version>
properties>
在需要的地方使用${}的形式来引用自定义的属性名:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>${atguigu.spring.version}version>
dependency>
真正实现“一处修改,处处生效”。
使用一个“总工程”将各个“模块工程”汇集起来,作为一个整体对应完整的项目。
概念的对应关系:
从继承关系角度来看:
从聚合关系角度来看:
以
mvn install
命令为例:Maven 要求有父工程时先安装父工程;有依赖的工程时,先安装被依赖的工程。我们自己考虑这些规则会很麻烦。但是工程聚合之后,在总工程执行mvn install
可以一键完成安装,而且会自动按照正确的顺序执行。
如果 A 工程依赖 B 工程,B 工程依赖 C 工程,C 工程又反过来依赖 A 工程,那么在执行构建操作时会报下面的错误:
[ERROR] [ERROR] The projects in the reactor contain a cyclic reference:
这个错误的含义是:循环引用。