Maven入门
目录
一、Maven是什么?
Maven是一个跨平台的项目管理工具。其主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。
Maven基本功能:
- 构建
- 编译
- 打包
- 测试
- 依赖管理(各种jar包)
Maven的特点:
项目设置遵循统一的规则。
任意工程中共享。
依赖管理包括自动更新。
一个庞大且不断增长的库。
可扩展,能够轻松编写 Java 或脚本语言的插件。
只需很少或不需要额外配置即可即时访问新功能。
二、Maven安装和配置
确定已安装jdk
下载安装
- 访问官网下载页面,
下载系统对应版本的maven安装包,并解压。
(PS:因为笔者是Windows系统,所以下载的是apache-maven-3.6.3-bin.zip。)
- 访问官网下载页面,
下载系统对应版本的maven安装包,并解压。
配置环境变量
- 在环境变量中添加变量
MAVEN_HOME,变量值为C:\Java\apache-maven-3.6.3, - 并在已有变量
Path中追加值%MAVEN_HOME%\bin。
(PS:变量值请大家自行更改为自己之前解压的目录路径。)
- 在环境变量中添加变量
检查是否安装成功
- 运行
CMD打开命令行,输入mvn --version,若输出版本信息则为安装成功。
- 运行
配置本地仓库(可选)
- 在D盘,新建文件夹
maven-repository - 然后在
C:\Java\apache-maven-3.6.3\conf\settings.xml文件中,将<localRepository>节点取消注释。 - 并更改为
<localRepository>D:\maven-repository</localRepository>。
(PS: 配置了本地仓库后,当我们从maven中获取jar包的时候,maven首先会在本地仓库中查找,如果本地仓库有则返回;如果没有则从远程仓库中获取包,并在本地库中保存。 本地仓库其实起到了一个缓存的作用,它的默认地址是 C:\Users\用户名.m2。)
- 在D盘,新建文件夹
配置阿里云镜像(可选)
- 在
C:\Java\apache-maven-3.6.3\conf\settings.xml文件中,的mirrors节点下添加下方代码。
(PS:将MAVEN镜像路径添加阿里镜像,是为了提高jar包下载速度,默认的远程仓库maven中心仓库在国外,下载速度较慢)<mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror>
- 在
IDEA中配置maven(可选)
步骤如下:- File => Settings => 输入框里输入Maven => 定位Maven选项
- 在右侧,Maven home directory选择为解压目录
- User settings file 选择解压目录下,conf文件夹下的settings.xml文件
- Local repository,应该会按照settings.xml自动填写
三、Maven构建项目(命令行交互方式)
(一)命令行交互方式
打开
CMD命令行,输入mvn archetype:generate命令行将输出一个模板列表,需要我们选择一个模板(Choose archetype)为基础来构建工程
我们可以键入列表前面的序号或关键字,来缩小模板选择范围或者直接选中模板,这里输入
webapp,筛选出web应用的模板键入需要的
模板序号,来选择构建web项目的模板org.apache.maven.archetypes:maven-archetype-webapp选择模板的版本,输入序号回车。若模板只有一个版本,则会跳过这一步
接着输入项目的坐标:
groupId(项目组织ID) 、artifactId(项目ID)、version(版本)、package(包)- groupId:项目组织唯一的标识符,默认会对应JAVA的包的结构,是main目录里java的目录结构。
- artifactId:项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称。
- version:项目的版本,“1.0-SNAPSHOT”表示快照1.0版本,“1.0-release”表示发行版1.0
接着是确认属性配置(Confirm properties configuration),若信息无误,直接回车即可
可以看到,当前目录下多了一个以输入的
artifactId来命名的文件夹到此基本项目构建完成
(二)命令行非交互方式
- 直接在命令行中键入一下命令
注意:1. 下面命令后面的^,表示换行接着输入,不能漏。 2.换行输入,提示符会变成More?。mvn archetype:generate -DgroupId=com.zcz.webdemo2^ -DartifactId=webdemo2^ -DarchetypeArtifactId=maven-archetype-webapp^ -DinteractiveMode=false mvn archetype:generate \ -DarchetypeGroupId=org.apache.flink \ //原型组ID -DarchetypeArtifactId=flink-quickstart-java \ //原型ID -DarchetypeVersion=1.6.1 \ //原型版本 -DgroupId=my-flink-project \ -DartifactId=my-flink-project \ -Dversion=0.1 \ -Dpackage=myflink \ -DinteractiveMode=false
- 参数解释:
- -DgroupId:输入的groupId
- -DartifactId:输入的artifactId
- -DarchetypeArtifactId:模板名称
- -DinteractiveMode=false:不以交互式命令行的形式构建项目
四、Maven编译项目、测试项目、打包项目
在项目约定位置写好java代码之后,就要进行项目的编译 (PS:约定位置见后面的“默认约定”一节。)
编译先进入Maven项目根目录下,然后执行
mvn compile若之前以写过测试代码,这里可执行命令来测试 (PS:测试类及代码约定见后面的“默认约定”一节。)
mvn test打包项目,就是把编译完成的class文件,打到一个jar或者war包内
mvn versions:set -DnewVersion=1.0.0 #修改版本号,自动设置所有本项目有关的pom.xml version mvn versions:commit #确认版本号,删除修改前pom版本备份 mvn versions:revert #回退版本号,使用备份恢复原版本号 mvn packagemvn package 、 mvn install 、 mvn deploy区别
package install deploy 打包到项目target目录 打包拷贝到本地仓库,供其他项目引用 打包上传到远程仓库,需配置pom文件
五、关于pom.xml文件
刚刚构建的项目文件夹下有一个pom.xml文件。
它是项目的描述文件,描述了项目的maven坐标,依赖关系,开发者需要遵循的规则,缺陷管理系统,组织和licenses,以及其他所有的项目相关因素,是项目级别的配置文件。
(PS:最基础的pom文件,可以看这里 http://maven.apache.org/pom.html#The_Basics )web项目的pom.xml结构
- 特别说明一下依赖节点(
<dependency>)下的<scope>
配置provided相当于compile,但是在打包阶段做了exclude的动作,也就是当我们打包的时候就不会把这个依赖加进去。最常见的是j2ee规范相关的servlet-api和jsp-api等jar包,一般Tomcat会提供,无需在打包到war包中,如果不配置为provided,把这些包打包到工程war包中,在tomcat6以上版本会出现冲突无法正常运行程序(版本不符的情况)。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- 模型版本。maven2.0必须是这样写,现在是maven2唯一支持的版本 --> <modelVersion>4.0.0</modelVersion> <!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.winner.trade,maven会将该项目打成的jar包放本地路径:/com/winner/trade --> <groupId>com.winner.trade</groupId> <!-- 本项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 --> <artifactId>trade-core</artifactId> <!-- 本项目目前所处的版本号 --> <version>1.0.0-SNAPSHOT</version> <!-- 打包的机制,如pom,jar, maven-plugin, ejb, war, ear, rar, par,默认为jar --> <packaging>jar</packaging> <!-- 帮助定义构件输出的一些附属构件,附属构件与主构件对应,有时候需要加上classifier才能唯一的确定该构件 不能直接定义项目的classifer,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成的 --> <classifier>...</classifier> <!-- 定义本项目的依赖关系 --> <dependencies> <!-- 每个dependency都对应这一个jar包 --> <dependency> <!--一般情况下,maven是通过groupId、artifactId、version这三个元素值(俗称坐标)来检索该构件, 然后引入你的工程。如果别人想引用你现在开发的这个项目(前提是已开发完毕并发布到了远程仓库),--> <!--就需要在他的pom文件中新建一个dependency节点,将本项目的groupId、artifactId、version写入, maven就会把你上传的jar包下载到他的本地 --> <groupId>com.winner.trade</groupId> <artifactId>trade-test</artifactId> <version>1.0.0-SNAPSHOT</version> <!-- maven认为,程序对外部的依赖会随着程序的所处阶段和应用场景而变化,所以maven中的依赖关系有作用域(scope)的限制。 --> <!--scope包含如下的取值:compile(编译范围)、provided(已提供范围)、runtime(运行时范围)、test(测试范围)、system(系统范围) --> <scope>test</scope> <!-- 设置指依赖是否可选,默认为false,即子项目默认都继承:为true,则子项目必需显示的引入,与dependencyManagement里定义的依赖类似 --> <optional>false</optional> <classifier>jdk15</classifier> <!-- 屏蔽依赖关系。 比如项目中使用的libA依赖某个库的1.0版,libB依赖某个库的2.0版,现在想统一使用2.0版,就应该屏蔽掉对1.0版的依赖 --> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <!-- 为pom定义一些常量,在pom中的其它地方可以直接引用 使用方式 如下 :${file.encoding} --> <properties> <file.encoding>UTF-8</file.encoding> <java.source.version>1.5</java.source.version> <java.target.version>1.5</java.target.version> </properties> ... </project>- 特别说明一下依赖节点(
其他项目信息配置、构建配置、分发配置、仓库配置、profile配置、环境配置等,参见官方文档描述
六、默认约定
- Maven 提倡使用一个共同的标准目录结构,Maven 使用约定优于配置的原则,大家尽可能的遵守这样的目录结构。
- 约定优于配置的设定一个是为了简化了配置文件的配置,另外也是为了规范maven工程的目录结构
目录|目的
:-:|:-:
${basedir}|存放pom.xml和所有的子目录
${basedir}/src/main/java|项目的java源代码
${basedir}/src/main/resources|项目的资源,比如说property文件,springmvc.xml
${basedir}/src/test/java|项目的测试类,比如说Junit代码
${basedir}/src/test/resources|测试用的资源
${basedir}/src/main/webapp/WEB-INF|web应用文件目录,web项目的信息,比如存放web.xml、本地图片、jsp视图页面
${basedir}/target|打包输出目录
${basedir}/target/classes|编译输出目录
${basedir}/target/test-classes|测试编译输出目录
TestXXX.java|Maven只会自动运行符合该命名规则的测试类
testFunction()|Maven只会自动运行测试类中的符合该命名规则测试方法
~/.m2/repository|Maven默认的本地仓库目录位置
- 企业 Maven 依赖管理层次结构设计:https://zhuanlan.zhihu.com/p/109323847
七、常用命令和配置
- 安装jar到本地仓库;下载jar包
mvn spring-javaformat:apply # 格式化代码 “Spring” style
#安裝jar到本地仓库
mvn install:install-file -Dfile=D:\git\Spring-boot-MSMQ-Demo-master\libs\MsmqJava.jar -DgroupId=ionic.Msmq -DartifactId=MsmqJava -Dversion=1.0 -Dpackaging=jar
mvn deploy:deploy-file -Durl=http://172.20.52.101:8081/repository/maven-releases/ -DrepositoryId=maven-release -Dfile=D:\git\Spring-boot-MSMQ-Demo-master\libs\MsmqJava.jar -DgroupId=ktest.ionic.Msmq -DartifactId=MsmqJava -Dversion=1.0 -Dpackaging=jar
mvn dependency:copy-dependencies #复制所有依赖到target
mvn dependency:tree #查看依赖树
mvn dependency:tree -Dverbose #查看依赖树详细
mvn dependency:tree -Dverbose -Dincludes=groupId:artifactId:version
E:\tool\apache-maven-3.9.4\bin\mvn dependency:tree -Dverbose -Dincludes=org.bouncycastle #查看依赖树详细
E:\tool\apache-maven-3.9.4\bin\mvn dependency:tree -Dverbose -s C:\\users\root\.m2\settings.xml -Dincludes=com.ibm.mq:com.ibm.mq.allclient:9.3.1.0 -DsocksProxyHost=127.0.0.1 -DsocksProxyPort=7890
#下载指定jar到本地仓库 可指定远程仓库-DremoteRepositories=https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2
mvn dependency:get -DgroupId=org.jline -DartifactId=jline -Dversion=3.20.0 -Dpackaging=jar
mvn dependency:get -Dartifact=org.apache.maven:maven-core:2.2.1:jar:sources -DremoteRepositories=http://repo1.maven.apache.org/maven2 -Ddest=./something.jar
#按pom.xml获取指定依赖
mvn dependency:copy-dependencies -f pom.xml #pom.xml内容如下
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>temp.download</groupId>
<artifactId>temp-download</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- 需要下载什么jar包 添加相应依赖 其余部分无需在意-->
</dependencies>
</project>
- 打包构建配置
- 可执行jar,并且依赖及配置等都打入一个jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<build>
<finalName>${project.name}-unexecutable</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<finalName>${project.name}</finalName>
<archive>
<manifest>
<mainClass>com.example.Main</mainClass>
</manifest>
<!-- <manifestEntries> 配置jar包中的MANIFEST.MF文件内容,用于javaagent打包
<Premain-Class>org.example.Main</Premain-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
<Can-Set-Native-Method-Prefix>true</Can-Set-Native-Method-Prefix>
</manifestEntries> -->
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<!-- 此配置效果 打包执行mvn package即可不必加上assembly:single -->
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
- 可执行jar,但依赖及配置不打入jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>${revision}.${buildTime}-SNAPSHOT</version>
<properties>
<!--程序版本-->
<revision>1.0.10</revision>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>xxx</groupId>
<artifactId>xxx</artifactId>
<version>xxx</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.17.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<finalName>${project.name}</finalName>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<outputDirectory>target</outputDirectory>
<plugins>
<plugin>
<!-- 指定jdk编译级别为jdk1.8,默认包含此插件可省略 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- <source>8</source> 由properties中maven.compiler.source指定,此处省略-->
<!-- <target>8</target> 由properties中maven.compiler.target指定,此处省略-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<outputDirectory>${project.build.directory}/${project.name}</outputDirectory>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
<manifest>
<mainClass>com.example.Main</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<useUniqueVersions>false</useUniqueVersions>
</manifest>
<!-- 把配置文件目录加入到MANIFEST.MF的Class-Path中 -->
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
<!-- 指定需要把哪些文件打入到jar包中, -->
<!-- ** 代表jar包根目录 -->
<!-- **/com/ 代表jar包根目录下仅包含com目录(我所有的程序都在com包下), 当然打好之后还会包含生成的manifest目录 -->
<!-- 注意com后面的/一定不要省去,不然maven会认为这是一个文件名 -->
<!-- includes或者excludes一定要指定,不然会把target下所有的文件都打进去 -->
<includes>
<include>**/com/</include>
</includes>
<excludes>
<exclude>**/mappings/</exclude>
</excludes>
</configuration>
</plugin>
<!-- 拷贝依赖的jar包到lib目录 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!-- 拷贝依赖的jar包到lib目录 -->
<outputDirectory>
${project.build.directory}/${project.name}/lib
</outputDirectory>
<!-- 功能未知待学习<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer> -->
</configuration>
</execution>
</executions>
</plugin>
<!-- 解决资源文件的编码问题 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<encoding>UTF-8</encoding>
<outputDirectory>${project.build.directory}/${project.name}</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>*</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- 打包source文件为jar文件 -->
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- maven-surefire-plugin 用于配置执行JUnit单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M1</version>
<configuration>
<!-- 跳过单元测试-->
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>generate-timestamp</id>
<phase>validate</phase>
<goals>
<goal>create-timestamp</goal>
</goals>
<configuration>
<timestampFormat>yyyyMMddHHmmss</timestampFormat>
<timestampPropertyName>buildTime</timestampPropertyName>
</configuration>
</execution>
</executions>
</plugin>
<!-- https://www.mojohaus.org/flatten-maven-plugin/plugin-info.html-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.5.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
- 基础Maven项目工程文件夹构建
mkdir -p src/main/java/com/example
mkdir -p src/main/resources
echo > src/main/java/com/example/Main.java
nano pom.xml //写入构建的pom.xml
七、推荐书籍
- 《Maven实战》
- Maven插件
- maven常用插件详解 https://blog.csdn.net/lixiangchibang/article/details/126817408
- Maven3种打包方式 https://www.cnblogs.com/sfnz/p/14207890.html
- java maven-assembly-plugin、maven-jar-plugin和maven-shade-plugin之间的区别? https://stackoverflow.com/questions/38548271/difference-between-the-maven-assembly-plugin-maven-jar-plugin-and-maven-shade-p https://www.saoniuhuo.com/question/detail-2597867.html
- 如何使用 Maven 创建构建 Java 项目(包括所有依赖项)https://gist.github.com/simonwoo/04b133cb0745e1a0f1d6
- 版本不兼容Jar包冲突该如何是好? maven-shade-plugin https://blog.csdn.net/vivo_tech/article/details/122185807