作为依赖管理工具
--之后使用框架之后jar包太多了,自己不好管理。
--jar包的来源太多了,有各种各样的来源,不可能去各种官方上找jar包。
--帮助我们解决jar包之间的依赖关系。
作为构建管理工具
--在本地环境的时候,构建的工作是IDEA做的。但是在服务器部署的时候,就需要maven进
行构建。
(1)构建
在开发过程中,指的是使用原材料(java源代码,图片,配置文件,基于HTML的
Thymeleaf)生产产品(一个可以在服务器上运行的项目)的过程。
主要环节
清理:删除上一次构建的结果,为下一次构建做好准备
编译:java源代码编译成class字节码文件
测试:运行提前准备好的测试程序
报告:针对刚才测试的结果生成一个全面的信息
打包:Java工程打包成jar包;web工程打包成war包
部署:
部署jar包:把一个jar包部署到Nexus私服服务器上
部署war包:借助相关Maven插件,将war包部署到Tomcat服务器上
(2)依赖
如果在A工程中使用到了B工程的类,接口,配置文件等等之类的资源,那么我们可以说
A依赖B。在依赖中主要解决的问题是:
--jar包的下载,能从规范的远程仓库下载到本地
--jar包之间的依赖,通过依赖的传递性自动完成
--jar包之间的冲突,通过对依赖的配置进行调整,让某些jar包不会被导入
(3)Maven工作机制
(1)下载地址:Maven – Download Apache Maven
windows下载如下图。下载之后解压在非中文没有空格的目录中。
(2)配置阿里云的镜像仓库。因为maven默认下载jar包会访问境外的中央仓库这样会很慢,所
以要改成阿里云的镜像仓库。配置方式是在maven中的setting.xml文件中添加下面的配置:
nexus-aliyun
central
Nexus aliyun
http://maven.aliyun.com/nexus/content/groups/public
(3)配置maven工程的基础JDK版本 。默认版本是1.5,但是我们开发的时候熟悉和使用的是
jdk1.8版本。将 profile 标签整个复制到 settings.xml 文件的 profiles 标签内。
jdk-1.8
true
1.8
1.8
1.8
1.8
本节中例子使用的工程都是在第五节中创建的。
Maven中的坐标:
groupId:公司或者组织的Id。公司或者组织的倒序,通常也加上项目名。注意一个项目
包含多个工程。例如com.atguigu.maven
artifactId:一个项目或者项目中的一个模块的Id。模块的名称,将来会作为Maven工程的
工程名。例如projectname
veirsion:版本号。SNAPSHOT表示快照版本,正在迭代过程中,不稳定的版本。
RELEASE表示正式版本。例如1.0-RELEASE
上面的jar包在本地仓库的位置:
本地仓库的目录\com\atguigu\maven\1.0\projectname-1.0.jar
创建目录为后面操作的工作空间,目前我们有三个目录:
Maven核心程序:中军大帐
Maven本地仓库:兵营
本地工作空间:战场
标签的位置:dependencies/dependency/scope
标签的可选值:compile/test/provided/system/runtime/import
测试方式:通过import语句将要测试的类引入当前类,引入后,如果编译通过:说明可以使
用,这个范围的依赖对当前类有效。如果编译失败:说明这个范围的依赖对当前类没
用。如果要测试部署到服务器能不能用,那就是看打成war包后,该jar包在不在war包中
的lib目录下
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 包时,就必须在需要的地方明确配置依赖才可以。
验证方式:使用mvn dependency:tree命令查看一下A工程下是否包含C就好。注意这个查询是检查的本地仓库中的jar包,所以要确保本地仓库中的jar包是最新的,最好检查前先对B工程进行mvn install命令的安装
验证实例:在pro01-maven-java工程(A)下引入spring-core工程(B),并且B工程默认引入了commons-logging工程(C)并且范围是compile。
org.springframework
spring-core
4.0.0.RELEASE
当 A 依赖 B,B 依赖 C 而且 C 可以传递到 A 的时候,A 不想要 C,需要在 A 里面把 C 排除掉。而往往这种情况都是为了避免 jar 包之间的冲突。所以配置依赖的排除其实就是阻止某些 jar 包的传递。因为这样的 jar 包传递过来会和其他 jar 包冲突。
排除实例:已知pro02-maven-web -> pro01-maven-java --> spring-core -->commons longgings
我们想要在pro02-maven-web工程中取消 pro01-maven-java对 commons longgings的引用,则需要修改pro02-maven-web工程中的pom文件,如下:
com.atguigu.maven
pro01-maven-java
1.0-SNAPSHOT
commons-logging
commons-logging
检查确认:
引入:Maven工程之间,A 工程继承 B 工程。那么B是父工程,A是子工程。本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置。
作用:在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
它的背景是:
对一个比较大型的项目进行了模块拆分。
一个 project 下面,创建了很多个 module。
每一个 module 都需要配置自己的依赖信息。
它背后的需求是:
在每一个 module 中各自维护各自的依赖信息很容易发生出入,不易统一管理。
使用同一个框架内的不同 jar 包,它们应该是同一个版本,所以整个项目中使用的框架版本需
要统一。
使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终
确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索。
通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力。
父子结构构建:
先创建一个父工程,在工作空间中输入命令:
创建子模块后,父工程pom文件中增加的内容,这就是聚合的配置:
子工程的pom文件中有关父工程的配置:
父工程统一管理依赖信息:
UTF-8
4.0.0.RELEASE
pro04-maven-moudle
pro05-maven-moudle
pro06-maven-moudle
org.springframework
spring-core
${atguigu.spring.version}
org.springframework
spring-beans
${atguigu.spring.version}
org.springframework
spring-context
${atguigu.spring.version}
org.springframework
spring-expression
${atguigu.spring.version}
org.springframework
spring-aop
${atguigu.spring.version}
一键执行 Maven 命令:很多构建命令都可以在“总工程”中一键执行。
以 mvn install 命令为例:Maven 要求有父工程时先安装父工程;有依赖的工程时,先安装被依赖的工程。我们自己考虑这些规则会很麻烦。但是工程聚合之后,在总工程执行 mvn install 可以一键完成安装,而且会自动按照正确的顺序执行。
配置聚合之后,各个模块工程会在总工程中展示一个列表,让项目中的各个模块一目了然
为了让构建过程自动化完成,Maven 设定了三个生命周期,生命周期中的每一个环节对应构建过程中的一个操作。在任何一个生命周期内部,执行任何一个具体环节的操作,都是从本周期最初的位置开始执行,直到指定的地方。前面三个生命周期彼此是独立的。
Maven 的核心程序仅仅负责宏观调度,不做具体工作。具体工作都是由 Maven 插件完成的。例如:编译就是由 maven-compiler-plugin-3.1.jar 插件来执行的。
一个插件可以对应多个目标,而每一个目标都和生命周期中的某一个环节对应。
Default 生命周期中有 compile 和 test-compile 两个和编译相关的环节,这两个环节对应 compile 和 test-compile 两个目标,而这两个目标都是由 maven-compiler-plugin-3.1.jar 插件来执行的。
本地仓库:在当前电脑上,为电脑上所有 Maven 工程服务
远程仓库:需要联网|
局域网:我们自己搭建的 Maven 私服,例如使用 Nexus 技术。
Internet:
中央仓库
镜像仓库:内容和中央仓库保持一致,但是能够分担中央仓库的负载,同时让用户能够
就近访问提高下载速度,例如:Nexus aliyun
建议:不要中央仓库和阿里云镜像混用,否则 jar 包来源不纯,彼此冲突。
专门搜索 Maven 依赖信息的网站:https://mvnrepository.com/
能够构建一个项目,使用前要先进入工作空间D:\workspace\space2022528,使用这个
命令之后会在这里创建一个工程,目录结构如下所示
--修改pom.xml文件中junit依赖的版本为4.12
--pom文件解读:
4.0.0
com.atguigu.maven
pro01-maven-java
1.0-SNAPSHOT
jar
pro01-maven-java
http://maven.apache.org
UTF-8
junit
junit
4.12
test
--pom的思想:
POM 表示将工程抽象为一个模型,再用程序中的对象来描述这个模型。这样我们
就可以用程序来管理项目了。我们在开发过程中,最基本的做法就是将现实生活中的事
物抽象为模型,然后封装模型相关的数据作为一个对象,这样就可以在程序中计算与现
实事物相关的数据。POM 理念集中体现在 Maven 工程根目录下 pom.xml 这个配置文件
中。所以这个 pom.xml 配置文件就是 Maven 工程的核心配置文件。其实学习 Maven 就
是学这个文件怎么配置,各个配置有什么用。
--maven中java工程的基本结构:
我们我注意的是Maven 对于目录结构这个问题,没有采用配置的方式,而是基于约
定。这样会让我们在开发过程中非常方便。如果每次创建 Maven 工程后,还需要针对各
个目录的位置进行详细的配置,那肯定非常麻烦。
目前开发领域的技术发展趋势就是:约定大于配置,配置大于编码。
D:\workspace\space2022528\pro01-maven-java\src\main\java\com\atguigu\maven中添
加Calculator.java文件,代码如下
package com.atguigu.maven;
public class Calculator {
public int sum(int i, int j){
return i + j;
}
}
D:\workspace\space2022528\pro01-maven-java\src\test\java\com\atguigu\maven中添
加CalculatorTest.java文件,代码如下
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);
System.out.println("程序执行完毕");
}
}
运行Maven中构建相关的命令时候,需要进入到pom.xml所在的目录,如果没有在该目录下运行maven的构建命令就会报错。例如:D:\workspace\space2022528\pro01-maven-java,其实就是src所在的目录下。
mvn -v命令和构建没有关系,在任何目录下都能执行。
可以清除target目录
主程序编译:mvn compile
测试程序编译:mvn test-compile
主体程序编译结果存放的目录:target/classes
测试程序编译结果存放的目录:target/test-classes
mvn test
测试的报告存放的目录:target/surefire-reports
mvn package
本工程是java工程,所以打包的结果——jar 包,存放的目录:target
mvn install
安装的效果是将本地构建过程中生成的 jar 包存入 Maven 本地仓库。这个 jar 包在 Maven 仓
库中的路径是根据它的坐标生成的。
生成web工程的时候,需要使用专门的archetype。这个可以去官网看到他的用法。这里给个例子。注意生成工程时候都是要回到工作空间中。构建成功后记得改下pom文件中junit的版本号。
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4
首先针对上面的目录进行补充:
其中HelloServlet文件内容如下:
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");
}
}
在web.xml中注册Servlet
helloServlet
com.atguigu.maven.HelloServlet
helloServlet
/helloServlet
在index.jsp中编写超链接:
Hello World!
Access Servlet
注意在此时编译文件时候会报错,因为我们的工程用到了HttpServlet这个类,而这个类属于servlet-api.jar 这个 jar 包。此时我们说,Web 工程需要依赖 servlet-api.jar 包。所以我们需要导入这个包,这个依赖可以在https://mvnrepository.com网站查询这个网站查询。
把刚才打包好的war包或者解压文件放到tomcat的webapps文件夹中
cmd窗口进入 D:\apache-tomcat-8.5.31\bin目录,调用startup.bat命令,然后就可以在服务器中测试访问
明确一个意识:从来只有 Web 工程依赖 Java 工程,没有反过来 Java 工程依赖 Web 工程。本质上来说,Web 工程依赖的 Java 工程其实就是 Web 工程里导入的 jar 包。最终 Java 工程会变成 jar 包,放在 Web 工程的 WEB-INF/lib 目录下。
首先我们要在web工程的pom.xml文件中,引入之前java工程的坐标
com.atguigu.maven
pro01-maven-java
1.0-SNAPSHOT
在web工程中补充一些测试的代码(要确认依赖了junit)
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);
System.out.println("程序执行完毕");
}
}
调用mvn test命令来进行测试;
调用mvn package命令测试:
通过查看 war 包内的结构,我们看到被 Web 工程依赖的 Java 工程确实是会变成 Web 工程的 WEB-INF/lib 目录下的 jar 包。
我们可以使用mvn dependency:list,查看依赖的jar包
父工程的pom文件
4.0.0
com.atguigu.maven
pro02-maven-idea-parent
pom
1.0-SNAPSHOT
pro03-moudle-java
14
14
子工程的pom文件
pro02-maven-idea-parent
com.atguigu.maven
1.0-SNAPSHOT
4.0.0
pro03-moudle-java
14
14
子工程pom加个junit依赖
junit
junit
4.12
test
在src//main/java/com/atguigu/maven目录下创建java文件
package com.atguigu.maven;
public class Hello {
public void show(){
System.out.println("这是一个测试方法");
}
}
在test/java/com/atguigu/maven目录下创建测试文件
package com.atguigu.maven;
import org.junit.Test;
public class HelloTest {
@Test
public void testHello(){
new Hello().show();
}
}
我们要给他补全目录:
添加java文件
package com.atguigu.maven;
public class Message {
public String getMessage(){
return "hello world";
}
}
在index.jsp界面中添加点东西:
<%@ page import="com.atguigu.maven.Message" %><%--
Created by IntelliJ IDEA.
User: 26849
Date: 2022/5/29
Time: 23:12
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%=new Message().getMessage()%>
比较简单不讲了
首先要把别人的moudle复制到自己的工程目录下,这时候idea是能检测到的,但是此时maven并不认为这是一个moudle,所以要进行一些设置。
如果是web类型的moudle,我们需要额外检查一下: