Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供**构建**和**依赖**管理支持的工具。
构建过程包含的主要的环节: - 清理:删除上一次构建的结果,为下一次构建做好准备 - 编译:Java 源程序编译成 *.class 字节码文件 - 测试:运行提前准备好的测试程序 - 报告:针对刚才测试的结果生成一个全面的信息 - 打包 - Java工程:jar包 - Web工程:war包 - 安装:把一个 Maven 工程经过打包操作生成的 jar 包或 war 包存入Maven的本地仓库 - 部署 - 部署 jar 包:把一个 jar 包部署到 Nexus 私服服务器上 - 部署 war 包:借助相关 Maven 插件(例如 cargo),将 war 包部署到 Tomcat 服务器上
依赖管理中要解决的具体问题: - jar 包的下载:使用 Maven 之后,jar 包会从规范的远程仓库下载到本地 - jar 包之间的依赖:通过依赖的传递性自动完成 - jar 包之间的冲突:通过对依赖的配置进行调整,让某些jar包不会被导入
Maven下载页面:Maven – Download Apache Maven
下载好压缩包后解压(记得钥解压到非中文、没有空格的目录)
进入Maven的核心配置文件conf/setting.xml
打开看到如图部分,如果没有自己指定本地仓库,则会按照图中所示的路径存放后面所需的资源。所以我们可以按照图中格式自己手动配置本地仓库的位置(非中文、没有空格
配置镜像仓库,在配置文件中,原本是如下配置
但Maven下载jar包默认访问境外的中央仓库,速度慢,如下改成国内阿里云提供的镜像仓库,访问国内网站
配置Maven工程的基础JDK(我用的适合1.8
配置环境变量
Maven 是一个用 Java 语言开发的程序,它必须基于 JDK 来运行,需要通过 JAVA_HOME 来找到 JDK 的安装位置。
新建-》按图配置
配置path变量
在命令行查看一下是否可以
配置完成则可以在命令行查看Maven版本
根据坐标创建Maven工程
Maven中的坐标 #[1]向量说明 使用三个『向量』在『Maven的仓库』中唯一的定位到一个『jar』包。 groupId:公司或组织的 id artifactId:一个项目或者是项目中的一个模块的 id version:版本号 #[2]三个向量的取值方式 groupId:公司或组织域名的倒序,通常也会加上项目名称 例如:com.atguigu.maven artifactId:模块的名称,将来作为 Maven 工程的工程名 version:模块的版本号,根据自己的需要设定 例如:SNAPSHOT 表示快照版本,正在迭代过程中,不稳定的版本 例如:RELEASE 表示正式版本 举例: groupId:com.atguigu.maven artifactId:pro01-atguigu-maven version:1.0-SNAPSHOT
坐标和仓库中jar包的存储路径之间的对应关系
用命令行操作Maven
创建目录作为后面操作的工作空间(存储创建的maven工程
例如:D:\software\ja\Maven-workspace\summer-maven-try
如图在命令行中在工作空间目录下使用如下命令创建Maven工程
在下载完后会出现
(7识上图中数字7后代表的选项操作,也可以输别的数)
就是对应上面所说的坐标信息 ,可按下图示例操作(名字不唯一,自定义
上图pro-maven-java(Maven下的java工程)
根据上述操作完,得到如下图构建成功的绿色字体提示
dir /b
可以查看当前路径下的所有文件和文件夹。dir /b /s
可以查看当前路径下的所有文件和文件夹以及子目录下的文件。如下图我们在我们的工作空间发现在执行完上面的工程创建后,在该目录下自动创建出如下文件
我的命名如下 groupId:personal.august.maven artifactId:project01-maven-java version:1.0-SNAPSHOT
(下图是依照我的命名得到的文件路径)
创建完工程后做一些调整
自动生成的 App.java 和 AppTest.java 可以删除。(大概就是下面这样的简单代码,我们可以用也可以自己创建)
Maven 默认生成的工程,对 junit 依赖的是较低的 3.8.1 版本,我们可以改成较适合的 4.12 版本。(junit3不支持注解)
在如图中的pom.xml文件修改
<!-- 依赖信息配置 --> <!-- 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.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>
POM
POM:Project Object Model,项目对象模型。和 POM 类似的是:DOM(Document Object Model),文档对象模型。它们都是模型化思想的具体体现。
POM 理念集中体现在 Maven 工程根目录下 pom.xml 这个配置文件中。所以这个 pom.xml 配置文件就是 Maven 工程的核心配置文件。学习 Maven 就是学这个文件怎么配置,各个配置有什么用。
可以发现Maven约定的目录结构:
(Maven 为了让构建过程能够尽可能自动化完成,所以必须约定目录结构的作用。例如:Maven 执行编译操作,必须先去 Java 源程序目录读取 Java 源代码,然后执行编译,最后把编译结果存放在 target 目录。
目前开发领域的技术发展趋势就是:约定大于配置,配置大于编码。
在Maven工程下编写代码
在上述工程创建完成后,自动生成相应的文件
main目录及其以下的子目录字文件为主体程序,其下的目录命名则是按照我们自定义的坐标名字自动生成
如下直观体现(和我自定义的名字有出入,图中Calculator类则是我们后面使用时创建存放的
主体程序
主体程序指的是被测试的程序,同时也是将来在项目中真正要使用的程序。
(记得包名和目录得要一致)
package personal.august.maven; import org.junit.Test; import personal.august.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的构建命令
相关操作命令
编译操作:
主程序编译:mvn compile 测试程序编译:mvn test-compile 主体程序编译结果存放的目录:target/classes 测试程序编译结果存放的目录:target/test-classes
(未编译前如上图)
执行完mvn compile命令后生成target文件夹(在project01-maven-java目录下执行,pom.xml的所在目录)
mvn compile(对main目录内容进行编译)
执行mvn compile- test后(对test目录进行编译)target目录下内容:
(注意编码字符集不同,电脑可能默认是ANSI,将java文件的编码改为UTF-8就可
清理操作
mvn clean (删除target目录)
测试操作
mvn test
在测试之前会对其编译,所以如果特使代码有所变动,也可以同步更新
测试的报告存放的目录:target/surefire-reports
该目录下的一些文件:
测试报告信息
当前环境的信息
a
打包操作
mvn package
打包的结果——jar 包,存放的目录:target
最后一个即是打包的文件, 打开发现里面只存放主体程序文件
a
安装操作
mvn install
安装的效果是将本地构建过程中生成的 jar 包存入 Maven 本地仓库。这个 jar 包在 Maven 仓库中的路径是根据它的坐标生成的。
以我自定义的坐标为例:
<groupId>personal.august.maven</groupId> <artifactId>project01-maven-java</artifactId> <version>1.0-SNAPSHOT</version>
在 Maven 仓库中生成的路径如下:(已知我的仓库的位置是D:\software\ja\Maven-repository)
D:\software\ja\Maven-repository\personal\august\maven\project01-maven-java\1.0-SNAPSHOT
如下图执行mvn clean install (组合操作,清理并安装,可以确保文件时最新的状态,且clean是将工作空间的target文件删除后再生成
(最后一个就是同名pom文件)
另外,安装操作还会将 pom.xml 文件转换为 XXX.pom 文件一起存入本地仓库。所以我们在 Maven 的本地仓库中想看一个 jar 包原始的 pom.xml 文件时,查看对应 XXX.pom 文件即可,它们是名字发生了改变,本质上是同一个文件。
(图中信息也可以体现)
创建Maven版的Web工程
说明:
操作:
运行生成工程的命令
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4
注意:如果在上一个工程的目录下执行 mvn archetype:generate 命令,那么 Maven 会报错:不能在一个非 pom 的工程下再创建其他工程。所以不要再刚才创建的工程里再创建新的工程,请回到工作空间根目录来操作。
不允许再java工程下创建一个web工程,要返回到上一级目录(与其平级,cd ..返回当前目录的上一级目录)
直接将上面长串的命令复制过去执行
也要按提示去自定义名字
在pom.xml中确认打包方式为war
<packaging>war</packaging>
工程创建完成后生成的目录如下
webapp 目录下有 index.jsp
WEB-INF 目录下有 web.xml
创建一些补充的目录(会比较规范)
创建web工程的使用示例
在包下创建Servlet类(注意包名要和目录相同)
package personal.august.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(WEB-INF目录下)
<servlet> <servlet-name>helloServlet</servlet-name> <servlet-class>personal.august.maven.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>helloServlet</servlet-name> <url-pattern>/helloServlet</url-pattern> </servlet-mapping>
在index.jsp页面编写超链接(webapp目录下)
<html> <body> <h2>Hello World!</h2> <a href="helloServlet">Access Servlet</a> </body> </html>
上述操作完成后,我们要对web工程进行编译
但是在编译之前我们要现导入依赖的jar包,如上HelloServlet类中导入的jar包等
以配对servlet-api.jar包的依赖为例
不知道详细信息的依赖可以到https://mvnrepository.com/网站查询。使用关键词搜索,然后在搜索结果列表中选择适合的使用。
点击版本号进入
复制框中内容到pom.xml即可, (是添加在dependencies的标签内)
执行编译 mvn compile (在该工程目录下执行,可知和java工程一样,执行完将生成target文件夹,里面存放编译后的文件内容
执行mvn package 将web工程打包为war
如下 target目录下生成的war包,和其解压文件(倒数一二
将war部署到Tomcat 上运行(将war包复制到Tomcat/webapps目录下)
因为启动时会自动解压war包,所以也可以选择将其解压文件复制放到webapps目录下
在命令行窗口下的tomcat的bin目录下执行startup.bat,然后打开浏览器访问Document Error: Not Found
点击得到
(如果遇到
可以检查以下8080端口是否被占用,执行命令杀掉该进程后再访问
如果遇到
org.apache.catalina.LifecycleException: 协议处理程序初始化失败(再tomcat启动的页面)
可以将conf/logging.properties文件中的字符编码改为UTF-8,解决org.apache.catalina.LifecycleException: 协议处理程序初始化失败_诗水人间的博客-CSDN博客
让web依赖java工程
明确一个意识:从来只有 Web 工程依赖 Java 工程,没有反过来 Java 工程依赖 Web 工程。本质上来说,Web 工程依赖的 Java 工程其实就是 Web 工程里导入的 jar 包。最终 Java 工程会变成 jar 包,放在 Web 工程的 WEB-INF/lib 目录下。
在project02-maven-web工程的pom.xmlde dependencies标签中添加如下内容
在web工程中,编写测试代码(放在test目录下,新创建和main同级
\project02-maven-web\src\test\java\personal\august\maven
把 Java 工程的 CalculatorTest.java 类复制到 project02-
maven-web\src\test\java\personal\august\maven目录下
执行mvn test ,测试操作中会提前自动执行编译操作,如果测试成功就说明编译也是成功的。
执行打包命令 mvn package,在war包中我们可以看到web工程依赖的java类放在了如下目录中
查看当前web工程所依赖的jar包的列表 mvn dependency:list(以列表的形式查看
在执行最后部分可以看到如下
mvn dependency:tree (以树的形式查看
我们在 pom.xml 中并没有依赖 hamcrest-core,但是它却被加入了我们依赖的列表。原因是:junit 依赖了hamcrest-core,然后基于依赖的传递性,hamcrest-core 被传递到我们的工程了。
依赖范围
标签的位置:dependencies/dependency/scope
标签的可选值:compile/test/provided/system/runtime/import
compile:通常使用的第三方框架的 jar 包这样在项目实际运行时真正要用到的 jar 包都是以 compile 范围进行依赖的。比如 SSM 框架所需jar包。 test:测试过程中使用的 jar 包,以 test 范围依赖进来。比如 junit。 provided:在开发过程中需要用到的“服务器上的 jar 包”通常以 provided 范围依赖进来。比如 servlet-api、jsp-api。而这个范围的 jar 包之所以不参与部署、不放进 war 包,就是避免和服务器上已有的同类 jar 包产生冲突,同时减轻服务器的负担。“服务器上已经有了,就不用再添加
通过compile范围依赖的jar包会放入war包,通过test范围依赖的jar包不会放入war包。
传递的依赖性
A 依赖 B,B 依赖 C,那么在 A 没有配置对 C 的依赖的情况下,A 里面能不能直接使用 C? 在 A 依赖 B,B 依赖 C 的前提下,C 是否能够传递到 A,取决于 B 依赖 C 时使用的依赖范围。 B 依赖 C 时使用 compile 范围:可以传递 B 依赖 C 时使用 test 或 provided 范围:不能传递,所以需要这样的 jar 包时,就必须在需要的地方明确配置依赖才可以。
排除传递依赖
配置方式(exclusions标签)
继承
Maven工程之间,A 工程继承 B 工程
- B 工程:父工程
- A 工程:子工程
本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置
通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力。
(对jar包统一管理,课将所有信息版本统一再父工程中进行管理
父工程的创建(打包方式为pom,一般写不业务代码,专门管理其他Maven工程的工程
如果没有修改打包方式就在里面创建子工程会出现错误
再父工程的目录下创建子工程
再父工程的pom.xml中添加如下内容
(如图只有一个子工程,因为我只建了一个,haha
在子工程的pom.xml中
父工程中配置依赖统一管理
。。。。。。。。
子工程中引用那些被父工程管理的依赖(省略版本号)
。。。。。。。 (如果子工程自己定义了,则按子工程自己的来
在父工程中声明自定义属性
(实现同步修改,相当于typedef的效果吧)
聚合
概念的对应关系: 从继承关系角度来看: 父工程 子工程 从聚合关系角度来看: 总工程 模块工程
聚合的配置(和继承一样,配置modules)
依赖循环问题(如果依赖是一个循环,则会发生错误,这个错误的含义是循环引用)
使用IDEA创建Maven工程下的web工程
2022版 的IDEA创建一个maven项目(超详细)_idea创建maven项目_无尽的沉默的博客-CSDN博客
(记得要把本地仓库路径 、配置文件的路径等改为自己设置的)
上面的那个Archetype可以自己选择,我看网上创建web好像是选这个
(如果没有点如下提示中的配置,则要自己去构建目录
首先在main文件夹下补全java,resorces文件夹,与main同级的test文件夹(后java,resorces也和main一样去创建)
可以发现自己创建时,会由很多提示,直接创建
我们在文件名右击
将对应的目录设置为对应的目录类型,得到如下图标形式就可以了
(后来发现其实只要在创建时,直接点这里的maven就好,
(构建系统的选项中的maven,然后点高级设置创建号一个工程,然后可以自己在添加自己需要的目录,即使没有自动生成对应groupid一样的目录,到那时自己去生成就好,这时可以设置树外观-》压缩空的中间包,创建目录时直接创建于groupid的同名软件包即可)