本文参考B站UP主:DT课堂原名颜群 的maven视频写出。
1.maven作用
a.管理jar包
i.增加第三方包
ii.自动处理jar包之间的依赖关系(自动关联下载,版本自动适配)
b.将项目拆分成多个模块
2.maven概念:
基于Java平台的自动化构建工具
(其他还有gradle)
可以
清理:删除编译的结果,为重新编译做准备
编译:java->class
测试:单元测试, 开发人员与测试人员交互
报告:将测试的结果进行显示
打包:用于安装部署(java项目->jar , web项目->war)
安装:将打成的包放到本地仓库,供其他项目使用
部署:将打成的包放到服务器上准备运行
--将java、js、jsp等各个文件进行筛选、组装变成一个可运行的项目
自动化构建工具maven:将原材料(java、js、css、html、图片)->产品(可发布项目)
本地仓库(先在本地仓库下载,一般是个人的仓库)
私服(nexus,一般是公司所有人共享的仓库,本地仓库没有时去私服仓库找)
中央仓库(私人仓库没有时再联网去中央仓库下载)
中央仓库镜像(对中央仓库分流,减轻其压力)
eclipse中部署的web项目可以运行
将eclipse中的项目直接复制到tomcat/webapps中则无法运行
原因:eclipse中的项目,在部署时会生成一个对应的部署项目(在wtowebapps中),区别在于:部署项目的项目其实是没有源码src的(.java文件)只有编译后的class文件和jsp文件。而直接复制粘贴的项目其目录结构和tomcat中的部署项目结构是不一样的,所以tomcat无法直接运行eclipse中直接复制过来的项目。
要想用eclipse部署则需要打包项目为war,复制到tomcat的webapps中。或者通过eclipse中的Add and remove按钮进行部署
3.配置maven
:
https://www.bilibili.com/video/BV1TW411A7X2?p=2
4.使用maven
约定优于配置(指文件路径格式)
硬编码方式:job.setPath("d:\\abc");
配置方式:job
conf.xml-><path>d:\\abc</path>
约定方式:job使用默认值d:\\abc
maven约定的目录结构:
项目
pom.xml:项目对象模型(与src同级的)
--target:项目编译后生成的文件
--src
--main:程序功能代码
--java:Java代码
--resources:资源代码、配置代码
--test:测试代码
--java
--resources
(1)、pom配置:
i.如何在仓库中确定唯一模块
<project xmlns="html://xxxxx">
<!-- 下面是自己将要开发的项目配置,发布时将按照这个配置发布到相应位置 -->
<groupId>org.lanqiao(域名翻转).maven(大的项目名)</groupId>
<groupId>域名翻转.模块名(大的项目名)</groupId>
<artifactId>子模块</artifactId>
<artifactId>HelloWorld</artifactId>
<version>版本号</version>
<version>0.0.1-SNAPSHOT</version>
<name>起名字(一般就用子模块名)</name>
<name>HelloWorld</name>
<!-- 下面是依赖 -->
<dependencies>
<!-- dependency可以有多个 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
<!-- 可以去百度搜索maven和jar包,点开里面可以直接复制 -->
<dependency>
<groupId>域名翻转.模块名</groupId>
<artifactId>子模块</artifactId>
<version>版本号</version>
<scope>依赖的范围默认(compile)</scope>
</dependency>
</dependencies>
<!--
A中的某些类需要使用B中的某些类,则称为A依赖于B
在Maven某些项目中,如果要使用 一个当时存在的Jar或模块,则可通过依赖实现(去本地仓库、中央仓库去寻找)
-->
</project>
(2)、编译运行
cmd进入src文件夹,然后运行命令mvn compile
(3)、mvn常见命令
mvn compile 编译 --只编译main目录中的java文件
mvn test 测试
mvn package 打包为jar/war/pom(通过测试才能打包)
mvn install 将开发的模块放入本地仓库,供其他模块使用
mvn clean 清理编译后的产物(清除target文件夹,不会影响本地仓库)
install上传到本地仓库的文件需要手动删除
运行mvn命令必须在pom.xml文件所在的目录(指src)
(4)、maven在编译(编译main,指mvn compile)、测试(指执行测试mvn test)、运行(指部署)项目时各自使用一个classPath
(5)、依赖的范围、有效性:
指依赖中<scope>标签的取值
如果为compile,那么编译(指编译主程序main时),测试(指执行测试mvn test),运行(部署时)时都可以找到依赖的jar包
为test时,那么编译和运行的时候都拿不到所依赖的jar包,只有测试拿得到所依赖的jar包(比如测试工具JUnit)
为provided时,那么编译和测试时都可以拿到,只有运行时拿不到。(比如开发与测试Servlet)(因为只有在编译和测试时用得到servlet-api.jar,运行时是在tomcat中,tomcat中自带servlet-api.jar,不需要maven提供jar包)
(6).依赖排除
前提:项目需要A.jar,A.jar依赖B.jar,maven会自动引入B.jar
但我们只想要A.jar时使用依赖排除
比如:spring-context.jar依赖spring-aop.jar和spring-beans.jar等,但我只想要spring-context.jar,所以就用如下配置
<
dependency
>
<
groupId
>
org.springframework
</
groupId
>
<
artifactId
>
spring-context
</
artifactId
>
<
version
>
5.2.4.RELEASE
</
version
>
<!--
排除依赖
beans
和
aop-->
<
exclusions
>
<
exclusion
>
<!--
如果不知道怎么写就上
maven
官网搜索相关
jar
包并复制粘贴
-->
<
groupId
>
org.springframework
</
groupId
>
<
artifactId
>
spring-beans
</
artifactId
>
</
exclusion
>
<!--
可以排除多个
-->
<
exclusion
>
<
groupId
>
org.springframework
</
groupId
>
<
artifactId
>
spring-aop
</
artifactId
>
</
exclusion
>
</
exclusions
>
</
dependency
>
(7)依赖的传递性
A.jar依赖B.jar,B.jar依赖C.jar
但要使A.jar依赖C.jar,必须使B.jar依赖于C.jar的范围是complie
(8)多个maven模块(项目)之间如何依赖:
比如:要使新的A模块依赖已开发好的B模块,需要以下几个步骤:
i.把B模块 install 到本地仓库
ii.把B模块添加到A模块:
<!--在本项目(A模块)中编写如下依赖(编写依赖B模块)-->
<dependency>
<!--以下内容可直接复制粘贴B模块的pom.xml配置-->
<groupId>B模块所属的域名翻转.模块名</groupId>
<artifactId>B模块名</artifactId>
<version>B模块的版本号</version>
</dependency>
(9)依赖原则(为了防止冲突)
a.最短路径优先原则:
以下图HelloWorldTime模块为例:
HelloWorldTime依赖最近的Junit3.8
b.路径长度相同:
i.在同一个pom.xml文件中有2个相同的依赖:
(严格禁止这种写法)
在pom.xml中越靠后则优先级越高,后面的依赖会覆盖前面的
比如:下面的配置,优先选择junit4.0
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
ii.如果是不同的pom.xml中有相同的依赖,则先声明的依赖会覆盖后声明的依赖。
例如下图所示:以HelloWorldTime模块为例
下图是HelloWorldTime的pom.xml文件的依赖配置:
(前提:HelloWorld中没有配置依赖commons-io)
优先选择在前面声明的依赖模块的pom.xml文件中的jar包
最终HelloWorldTime模块选择的是HelloWorld2x模块中依赖的commons-io2.4.jar
(10).通过Maven统一jdk版本
i.在模块的pom.xml中配置(只在eclipse中的模块pom.xml中有效)
<!--以下的数字可以改为12、1.8、11等,可直接复制<profiles>标签内容到<project>标签中-->
<project>
<profiles>
<profile>
<id>起一个名字</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.7</jdk>
</activation>
<properties>
<
maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</
maven.compiler.target>
<maven.compiler.compilerVersion>1.7</
maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
</project>
ii.在模块的pom.xml中配置(修改当前项目使用的jdk版本,IDEA与eclipse通用)
<!--以下的数字可以改为12、1.8、11等,可直接复制<build>标签内容到<project>标签中-->
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- <version>3.7.0</version> -->
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
iii.在本地maven仓库配置的settings.xml文件中添加配置
在settings.xml文件中找到有<profile>标签的地方,加上如下配置。配置jdk版本为1.8
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
</properties>
</profile>
(11)依赖的继承
与依赖的传递区别:A模块继承B模块是指:A可以使用B的所有依赖,不需要看B中的依赖是否有compile范围
想要实现依赖继承有三个步骤
1、确保被继承的父工程打包方式为pom,并且要在父工程的pom.xml文件中配置依赖
在父工程<project>标签中添加:
<
packaging
>
pom
</
packaging
>
<!--下面<
modules
>是聚合配置(idea会自动添加,可以省略),具体讲解在第13点-->
<
modules
>
<
module
>
子工程1
名字
</
module
>
<
module
>
子工程2
名字
</
module
>
<
module
>
子工程3名字
</
module
>
</
modules
>
配置依赖(父工程的依赖需要写在<dependencyManagement>标签下):
在之前的<dependencies>标签外套一个<dependencyManagement>标签,具体如下:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
2、在子工程pom.xml里面配置父工程的坐标,建立继承关系
在子工程的<project>标签中添加
<artifactId>子工程名</artifactId>
<!--当域名翻转.模块名与版本和父工程一样时,可以不填写groupId与version-->
<!--定位父工程坐标-->
<parent>
<artifactId>父工程名</artifactId>
<groupId>父工程域名翻转.模块名</groupId>
<version>父工程版本</version>
<!--需要在<parent>中写<relativePath>定位父工程的pom.xml相对路径-->
<relativePath>../父工程名/pom.xml</relativePath>
</parent>
3、在子工程的pom.xml里面声明要使用到父工程里面的哪些依赖
(不用再声明继承的版本号<version>和范围<scope>)
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
优点和区别:
统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,才能保证测试的和发布的是相同的成果,因此,在顶层pom中定义共同的依赖关系。同时可以避免在每个使用的子项目中都声明一个版本号,这样想升级或者切换到另一个版本时,只需要在父类容器里更新,不需要任何一个子项目的修改;如果某个子项目需要另外一个版本号时,只需要在dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号。
dependencies即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继承)
dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。
(12)快捷更改依赖的版本号,统一编码
i.统一编码:(注意,不是放在pom.xml的<project>标签中,而是放在最外面)
<properties>
<!-- 文件拷贝时的编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 编译时的编码 -->
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
不过有时候需要更改依赖的版本号,这需要在pom文件里面找很久,还有就是一个一个的改很麻烦,有种便利的方法:
还可以结合
依赖继承统一版本/编码,更加实用
(13)Maven聚合
Maven项目能识别的:自身包含的、本地仓库的。
假设Module2依赖Module1,则在执行Module2前必须先将Module1加入到本地仓库(用install命令),之后才能执行Module2。
以上前置工程的install操作,可以交由“聚合”一次性搞定。
通过聚合可以把多个工程合起来
聚合的使用:
在一个总工程中配置(总工程只能为pom打包方式)
假设总工程与子工程的目录结构如下(自己建立的路径,不是仓库的路径):
--Module(总工程)
--Module1(子工程1)
--Module2(子工程2)
--Module3(子工程3)
则在Module工程的pom.xml的<project>中添加的配置如下:
<packaging>pom</packaging>
<modules>
<!--module中填写子工程相对于总工程的位置(在自己建立的路径上找,不要去仓库中找,没有的),相对路径与子工程名-->
<module>Module1</module>
<module>../Module2</module>
<module>../Module3</module>
</modules>
然后在Module工程执行test,package,install等命令时会自动对Module1等所有子工程执行相同操作
所以配置好聚合后,就不用管先为哪一个工程执行install命令了,因为系统会自动根据依赖的关系去自动执行所有子工程。
注意:聚合的依赖关系遵守依赖的传递规则
5.maven生命周期
假设生命周期中的命令顺序为:a->b->c->d->e
生命周期和构建的关系:即执行一个命令时会把之前的命令全部按顺序先执行完毕,再执行该命令。
比如:
当执行c命令,则实际执行的命令及其顺序是:a->b->c
执行package命令会按顺序执行compile,test命令后再执行package打包命令。
生命周期包含的阶段:一共三个阶段
(1)clean lifecycle:清理
pre-clean、clean、post-clearn
(2)
default lifecycle:默认(最重要最常见的命令)
很多包括compile、test-compile、test、package、install、deploy等
(3)site lifecycle:站点
pre-site、site、post-site、site-deploy