1、试验一:根据坐标创建 Maven 工程
1.1.命令行创建项目的过程与概念明确:
a.数学中的坐标:
b.Maven中的坐标
- 1.向量说明:使用三个
『向量』
在『Maven的仓库』
中唯一
的定位到一个『jar』
包。- groupId:
公司或组织的 id
- artifactId:一个
项目或者是项目中的一个模块的 id
- version:版本号
- groupId:
- 2.三个向量的取值方式:
groupId
:公司或组织域名的倒序,通常也会加上项目名称
,例如:com.atguigu.maven01
,在分布式系统的开发过程中,一个项目下面会包含很多模块artifactId
:模块的名称,将来作为 Maven 工程的工程名version
:模块的版本号,根据自己的需要设定- 例如:
SNAPSHOT 表示快照版本,正在迭代过程中,不稳定的版本
- 例如:
RELEASE 表示正式版本
- 例如:
- 4.举例:
groupId:com.atguigu.maven
artifactId:pro01-atguigu-maven
version:1.0-SNAPSHOT
c.坐标和仓库中 jar 包的存储路径之间的对应关系
- 1.如下坐标:
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
- 2.对应的在仓库中位置:
Maven本地仓库根目录\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar
1.2.创建maven工程,进行实验操作:
a.创建目录作为后面操作的工作空间:
- 1.假设空间的位置是:
D:\Program\Back-end\tools\maven\workspaces2022
- 2.
到目前为止,我们已经见到了三个目录
Maven 核心程序
-中军大帐:D:\Program\Back-end\tools\maven\apache-maven-3.8.1
- Maven 本地仓库-兵营:在配置文件中查看设置的存储路径
- 本地工作空间-战场:
D:\Program\Back-end\tools\maven\workspaces2022
b.在工作空间目录下打开命令行窗口:
- 1.在命令行窗口中输入命令运行:
mvn archetype:generate
命令、生成Maven工程:
- 2.maven项目创建成功:
- 3.Maven 默认生成的工程,在
pom.xml
文件中,对 junit 依赖的是较低的 3.8.1 版本,我们可以改成较适合的 4.12 版本。自动生成的 App.java 和 AppTest.java 可以删除
- 4.对新建项目中的pom.xml文件的解读:
<!-- modelVersion标签:从maven2.0就开始固定是4.0.0 代表当前pom.xml所采用的的标签结构 --> <modelVersion>4.0.0</modelVersion> <!-- 当前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标签 在Maven中定义属性--> <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>
1.3.Maven的核心概念:
a.pom.xml文件中标签的含义:
b.Maven核心概念:
b1.POM
- 1.含义: POM:
Project Object Model
,项目对象模型。和 POM 类似的是:DOM(Document Object Model),文档对象模型。它们都是模型化思想的具体体现
- 2.模型化思想
POM
表示将工程抽象为一个模型
,再用程序中的对象来描述这个模型。这样我们就可以用程序来管理项目了。我们在开发过程中,最基本的做法就是将现实生活中的事物抽象为模型,然后封装模型相关的数据作为一个对象,这样就可以在程序中计算与现实事物相关的数据
- 3.对应的配置文件
POM 理念集中体现在 Maven 工程根目录下 pom.xml 这个配置文件中
。所以这个 pom.xml 配置文件就是 Maven 工程的核心配置文件。其实学习 Maven 就是学这个文件怎么配置,各个配置有什么用
b2.约定的目录结构(创建的java工程)
- 1.各个目录的作用:
- 2.约定目录结构的意义:
Maven 为了让构建过程能够尽可能自动化完成
,所以必须约定目录结构的作用。例如:Maven 执行编译操作,必须先去 Java 源程序目录读取 Java 源代码
,然后执行编译,最后把编译结果存放在 target 目录
中。
- 3.约定大于配置
Maven 对于目录结构这个问题,没有采用配置的方式,而是基于约定
。这样会让我们在开发过程中非常方便。如果每次创建 Maven 工程后,还需要针对各个目录的位置进行详细的配置,那肯定非常麻烦。- 目前开发领域的技术发展趋势就是:约定大于配置,配置大于编码
2、试验二:在Maven工程中编写代码:
2.1.写主体程序:
- 主体程序指的是被测试的程序,同时也是将来在项目中真正要使用的程序
package com.atguigu.maven;
public class Calculator {
public int sum(int i, int j){
return i + j;
}
}
2.2.编写测试类:CaculatorTest:
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);
}
}
- 1.使用断言来进行测试:
3、实验三:执行 Maven 的构建命令
3.1.要求
运行
Maven 中和构建操作相关的命令时
,必须进入到 pom.xml 所在的目录
。如果没有在 pom.xml 所在的目录运行 Maven 的构建命令,那么会看到下面的错误信息:
TIP
:mvn -v
命令和构建操作无关,只要正确配置了 PATH,在任何目录下执行都可以。- 而构建相关的命令要在 pom.xml 所在目录下运行——操作哪个工程,就进入这个工程的 pom.xml 目录
b.清理操作:
- 命令:
mvn clean
- 效果:删除 target 目录
c.编译操作
- 1.主程序编译:
mvn compile
,生成class文件
- 2.测试程序编译:
mvn test-compile
- 3.主体程序编译结果存放的目录:
target/classes
- 4.测试程序编译结果存放的目录:
target/test-classes
d.测试操作:
- 命令:
mvn test
- 测试的报告存放的目录:
target/surefire-reports
e.打包操作:
- 命令:
mvn package
- 打包的结果——jar 包,存放的目录:target
f.安装操作:
- 1.命令:
mvn install
- 2.安装的效果是
将本地构建过程中生成的 jar 包存入 Maven 本地仓库
。这个 jar 包在 Maven 仓库中的路径是根据它的坐标生成的
,安装后,坐标信息如下:
<groupId>com.atguigu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
- 3.另外,安装操作
还会将 pom.xml 文件转换为 XXX.pom 文件一起存入本地仓库
。所以我们在Maven 的本地仓库中想看一个 jar 包原始的 pom.xml 文件时,查看对应 XXX.pom 文件即可,它们是名字发生了改变,本质上是同一个文件
4、试验四:创建 Maven 版的 Web 工程
4.1.说明
- 1.在工作空间这个目录下使用:
mvn archetype:generate
命令生成 Web 工程时,需要使用一个专门的 archetype
。 - 2.生成的web工程目录是:
4.2.命令操作:
a.新建web项目:
- 1.命令:
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4
来生成web工程 - 2.参数 archetypeGroupId、archetypeArtifactId、archetypeVersion 用来指定现在使用的 maven-archetype-webapp 的坐标:
b.查看生成的项目:
- 1.生成的pom.xml文件中。默认的打包方式是:war包;
<packaging>war</packaging>
- 2.生成的Web工程的目录结构:
- webapp 目录下有 index.jsp
- WEB-INF 目录下有 web.xml
c.创建servlet:
- 1.在 main 目录下创建 java 目录:
- 2.在 java 目录下创建 Servlet 类所在的包的目录:
- 3.在包下创建 Servlet 类:
package com.atguigu.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");
}
}
- 4.在 web.xml 中注册 Servlet:
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.atguigu.maven.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/helloServlet</url-pattern>
</servlet-mapping>
d.在 index.jsp 页面编写超链接:
- JSP全称是 Java Server Page,
和 Thymeleaf 一样,是服务器端页面渲染技术
。
<html>
<body>
<h2>Hello World!</h2>
<a href="helloServlet">Access Servlet</a>
</body>
</html>
e.执行编译:
- 执行mvn compile命令编译后,报错:
- ANGER
程序包 javax.servlet.http 不存在
程序包 javax.servlet 不存在
找不到符号
符号: 类 HttpServlet
……
- 上面的错误信息说明:我们的 Web 工程用到了 HttpServlet 这个类,而 HttpServlet 这个类属于 servlet-api.jar 这个 jar 包。此时我们说,Web 工程需要依赖 servlet-api.jar 包
f.配置对 servlet-api.jar 包的依赖
- 对于
不知道详细信息的依赖可以到https://mvnrepository.com/网站查询
。使用关键词搜索,然后在搜索结果列表中选择适合的使用
- 添加完依赖之后,就可以再去编译了
g.将 Web 工程打包为 war 包:
- 1.运行
mvn package 命令
,生成 war 包的位置如下图所示:
h.将 war 包部署到 Tomcat 上运行:
- 通过浏览器尝试访问:http://localhost:8080/pro02-maven-web/index.jsp
5、试验五:让 Web 工程依赖 Java 工程:
5.1.观念:
- 1.明确一个意识:从来
只有 Web 工程依赖 Java 工程,没有反过来 Java 工程依赖 Web 工程
。 - 2.本质上来说,
Web 工程依赖的 Java 工程其实就是 Web 工程里导入的 jar 包
。最终 Java 工程会变成 jar 包,放在 Web 工程的WEB-INF/lib
目录下
5.2.操作
1.在
pro02-maven-web
工程的pom.xml
中,找到dependencies 标签,在 dependencies 标签中做如下配置:
<!-- 配置对Java工程pro01-maven-java的依赖 -->
<!-- 具体的配置方式:在dependency标签内使用坐标实现依赖 -->
<dependency>
<groupId>com.atguigu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2.在 Web 工程中,编写测试代码:
- 1.补充创建test目录:
pro02-maven-web\src\test\java\com\atguigu\maven
- 2.确认 Web 工程依赖了 junit
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
- 3.创建测试类:把 Java 工程的
CalculatorTest.java
类复制到pro02-maven-wb\src\test\java\com\atguigu\maven
目录下
5.3.执行Maven命令
- 1.测试命令:
mvn test
;说明:在测试操作中会提前自动执行编译操作,测试成功就说明编译也是成功的;
- 2.打包命令:
mvn package
:
6.实验六:测试依赖的范围:
6.1.依赖范围
- 1.标签的位置:dependencies/dependency/
scope
,scope决定依赖的范围
- 2.标签的可选值:
compile/test/provided/system/runtime/import
,这些都是scope的可选值;
6.2.可选值的对比:
a.对compile 和 test 对比:
b. compile 和 provided 对比:
c.总结结论
- 1.compile:通常使用的第三方框架的 jar 包这样在项目实际运行时真正要用到的 jar 包都是以 compile 范围进行依赖的。比如 SSM 框架所需jar包。
- 2.test:
测试过程中使用的 jar 包
,以 test 范围依赖进来。比如 junit。 - 3.provided:在开发过程中
需要用到的“服务器上的 jar 包”通常以 provided 范围依赖进来
。比如 servlet-api、jsp-api
。而这个范围的 jar 包之所以不参与部署、不放进 war 包,就是避免和服务器上已有的同类 jar 包产生冲突,同时减轻服务器的负担。说白了就是:“服务器上已经有了,你就别带啦!
7.实验七:测试依赖的传递性
7.1.依赖的传递性
- 1.概念:A 依赖 B,B 依赖 C,那么在 A 没有配置对 C 的依赖的情况下,
A 里面能不能直接使用 C?
- 2.传递的原则:在 A 依赖 B,B 依赖 C 的前提下,C 是否能够传递到 A,
取决于 B 依赖 C 时使用的依赖范围
:- B 依赖 C 时
使用 compile 范围:可以传递
- B 依赖 C 时
使用 test 或 provided 范围:不能传递
,所以需要这样的 jar 包时,就必须在需要的地方明确配置依赖才可以;
- B 依赖 C 时
8、实验八:测试依赖的排除
8.1.概念
- 1.当 A 依赖 B,B 依赖 C, 而且 C 可以传递到 A 的时候,A 不想要 C,
需要在 A 里面把 C 排除掉。而往往这种情况都是为了避免 jar 包之间的冲突
;
- 所以配置
依赖的排除
其实就是阻止某些 jar 包的传递
。因为这样的 jar 包传递过来会和其他 jar 包冲突。
8.2.配置排除的方式:
<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>
9、实验九:继承
9.1.概念
- 1.Maven工程之间,A 工程继承 B 工程
- B 工程:父工程
- A 工程:子工程
- 2.
本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置
9.2.作用
- 1.在父工程中统一管理项目中的依赖信息,具体来说是
管理依赖信息的版本
- 2.它的背景是:
- 对一个比较大型的项目进行了模块拆分。
- 一个 project 下面,创建了很多个 module。
- 每一个 module 都需要配置自己的依赖信息。
- 3.它背后的需求是:
- 在
每一个 module 中各自维护各自的依赖信息很容易发生出入,不易统一管理
。 - 使用同一个框架内的不同 jar 包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
- 使用
框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合
。这个耗费很大精力总结出来的方案
不应该在新的项目中重新摸索。 - 通过
在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包
;又能够将以往的经验沉淀下来,节约时间和精力
- 在
9.3.举例
a.常见父项目及设置打包方式:
1.创建的过程和前面创建java工程 pro01-maven-java 一样。工程名称:
pro03-maven-parent
>2.工程创建好之后,要修改它的打包方式:
<groupId>com.atguigu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 pom -->
<packaging>pom</packaging>
3.把各模块整合到父工程中:
- 1.再创建三个模块工程:
- 2.查看被添加新内容的父工程 pom.xml;下面 modules 和 module 标签是聚合功能的配置
- 3.解读子工程的pom.xml:
- 4.在父工程中配置依赖的统一管理:
<!-- 使用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>
- 5.子工程中引用那些被父工程管理的依赖;
关键点:省略版本号
- 6.在父工程中升级依赖信息的版本:
- 7.在父工程中声明自定义属性
9.4.这种继承模式的实际意义:
10、实验十:聚合
10.1.聚合本身的含义:
1.聚合本身的含义:
部分组成整体
10.2.Maven 中的聚合
a.什么是聚合:
- 1.使
用一个“总工程”将各个“模块工程”汇集起来,作为一个整体对应完整的项目
- 项目:整体
- 模块:部分
b.概念的对应关系:
- 1.从继承关系角度来看:
- 父工程
- 子工程
- 2.从聚合关系角度来看:
- 总工程
- 模块工程