Maven史上最全总结

maven基础概念

参考文章:https://blog.csdn.net/wwwwwww31311/article/details/114323704

一 maven的安装配置

安装配置参考:https://daniel.blog.csdn.net/article/details/100545928
补充:这篇文章对maven的安装配置做了详细说明,唯一需要注意点的是,在配置maven的settings.xml文件,设置localRepository个人本地maven仓库路径时要和idea保持一致,避免后续出现麻烦

二 maven整合IDEA

整合idea参考:https://blog.csdn.net/qq_45821420/article/details/106446791

个人补充:
1 maven版本要合适至少不要太老,这点注意下即可
2 配置要小心,不要出错,其中注意
在这里插入图片描述

  • User settings file选项:maven安装包中的核心设置(配置)文件
  • Local repository选项:指定一个文件夹作为你本地存放jar包,这里要注意即maven的配置文件中也会需要指定Local repository即本地maven仓库,如下 那么最好的方式就是两者保持一致咯,同时IDEA还会默认在C盘用户文件夹下生成一个.m2文件夹,如下,这个目录下会生成临时的settings配置文件和repository数据仓库,这常见于打开别人的项目,比如你刚从Git上拉取了你公司的项目或者拉取了别人的项目,这时默认会在.m2文件夹下生成临时的配置和数据仓库,虽然这样也没问题,但还是推荐大家使用自己配置的路径
C:\${User}\.m2

3、idea的设置

File -> New Projects settings -> Settings for new fiie,这里面的设置项和Settings是完全一样的
区别是Settings是为当前项目设置,只对当前项目生效,New Projects settings则是对后续打开的项目进行设置
即后面打开的新项目默认配置就是按这,New Projects settings默认是和Settings一致的

三 Maven基础知识

参考文章:超级详细的Maven使用教程

1、maven的生命周期

验证(validate) - 验证项目是否正确,所有必要的信息可用
编译(compile) - 编译项目的源代码
测试(test) - 使用合适的单元测试框架测试编译的源代码。这些测试不应该要求代码被打包或部署
打包(package) - 采用编译的代码,并以其可分配格式(如JAR)进行打包。
验证(verify) - 对集成测试的结果执行任何检查,以确保满足质量标准
安装(install) - 将软件包安装到本地存储库中,用作本地其他项目的依赖项
部署(deploy) - 在构建环境中完成,将最终的包复制到远程存储库以与其他开发人员和项目共享。

注意:执行相关步骤时,一定是先执行完前面的流程这执行当前步骤的,比如执行打包命令,一定是先执行完测试命令及其前面两个命令的

2、maven依赖范围

编译依赖范围(compile),该范围就是默认依赖范围,此依赖范围对 于编译、测试、运行三种classpath都有效,举个简单的例子,假如项目中有spring-core的依赖,那么spring-core不管是在编译,测试,还是运行都会被用到,因此spring-core必须是编译范围(构件默认的是编译范围,所以依赖范围是编译范围的无须显示指定)

 <dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-core</artifactId>
	  <version>2.5</version>
	  <scope>compile</scope> <!--默认为该依赖范围,无须显示指定-->
</dependency>

测试依赖范围(test),顾名思义就是针对于测试的,使用此依赖范围的依赖,只对测试classpath有效,在编译主代码和项目运行时,都将无法使用该依赖,最典型的例子就是 Junit, 构件在测试时才需要,所以它的依赖范围是测试,因此它的依赖范围需要显示指定为test ,当然不显示指定依赖范围也不会报错,但是该依赖会被加入到编译和运行的classpath中,造成不必要的浪费

 <dependency>
  	  <groupId>junit</groupId>
  	  <artifactId>junit</artifactId>
  	  <version>4.7</version>
  	 <scope>test</scope>
 </dependency>

已提供依赖范围(provided),使用该依赖范围的maven依赖,只对编译和测试的classpath有效,对运行的classpath无效,典型的例子就是servlet-api, 编译和测试该项目的时候需要该依赖,但是在运行时,web容器已经提供的该依赖,所以运行时就不再需要此依赖,如果不显示指定该依赖范围,并且容器依赖的版本和maven依赖的版本不一致的话,可能会引起版本冲突,造成不良影响

 <dependency>
  	  <groupId>javax-servlet</groupId>
  	  <artifactId>servlet-api</artifactId>
  	  <version>2.0</version>
  	 <scope>provided</scope>
    </dependency>

运行时依赖范围(runtime),使用该依赖范围的maven依赖,只对测试和运行的classpath有效,对编译的classpath无效,典型例子就是JDBC的驱动实现,项目主代码编译的时候只需要JDK提供的JDBC接口,只有在测试和运行的时候才需要实现上述接口的具体JDBC驱动。

<dependency>
     <groupId>javax.sql</groupId>
     <artifactId>jdbc-stext</artifactId>
     <version>2.0</version>
     <scope>system</scope>
     <systemPath>${java.home}/lib/rt.jar</systemPath>
 </dependency>

3、Dependencies和DependencyManagement区别

  • dependencies即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继承)

  • dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本

演示
demo2项目只有一个简简单单的lombok依赖,父类用的是dependencies,实际上由于继承了父类的原因,项目内部具有了父类的全部依赖
在这里插入图片描述
但如果父类使用dependencyManagement,而demo2项目没有声明其它依赖,那它内部就只有一个
在这里插入图片描述

注意:dependencyManagement中关联的版本必须声明版本号后子项目才被允许在不声明版本号的前提下引入依赖,否则会报错(Cannot resolve xxxx:unknown),所以我们使用dependencyManagement标签做依赖管理时最好是搭配properties,更规范,且易于修改项目的依赖版本,总之dependencyManagement中所管理的相关依赖必须要声明相关版本号
在这里插入图片描述

注意2:直接父maven项目中dependencyManagement里没有声明相关依赖的版本,那么子项目的可以声明自己的依赖版本号,如果在没有声明版本号的情况下没有报错,那就父项目所基础的更高一级的maven项目中对该依赖的版本号进线了管理,比如,我这里没有声明版本号,父项目dependencyManagement也没有对这个依赖版本号进行管理
在这里插入图片描述
但父项目的父项目就是springboot项目,我这里是2.5.2版本springboot,springboot中dependencyManagement对该依赖做了版本管理
在这里插入图片描述
验证,我们点进去这个spring-boot-starter-web,发现版本号是一致的,都是2.5.2,成功验证结论

四 使用技巧

1、规范性,名称全都要一致,举个反面教材,左侧Profiles是对项目maven配置即pom.xml文件做的配置读取
在这里插入图片描述
2、一个完整的项目肯定有很多不同的模块构成,不同的模块间最好使用同一版本的依赖,比如spring-boot-starter-parent这个依赖,都同一使用2.5版本,不要出现a模块使用2.5,b模块使用2.3这种情况
3、我们编写的工具类maven模块,同一个项目可以直接引入依赖

   <dependency>
            <groupId>com.wzh.utils</groupId>
            <artifactId>common_utils</artifactId>
            <version>1.0.0</version>
   </dependency>

但如果别的同事也需要用这些个工具类呢?可以参考文章:工具类封装成jar包并在maven中添加依赖

4、 刚打开的项目,尤其是从公司拉下来的项目,规模都很庞大,如果发现maven大量引入失败,先刷新maven,引入大量maven需要耐心等待,尤其是你电脑配置不佳或网速不佳的时候;
5、如果你公司在分布式架构基础写了个核心包,而且你通过pom引入依赖也成功了,但是会发现很多类找不到,如下

<dependency>
	 <groupId>com.sobot.core</groupId>
	 <artifactId>core-util</artifactId>
	 <version>1.0.0</version>
</dependency>

很多jar包明明依赖已经导入成功,甚至都可以在项目的External library找到了,如下
在这里插入图片描述
但为何就是不能引入成功呢?我们找到具体项目发现这个项目类路径下的确是没有依赖
在这里插入图片描述
其实这也是正常的,导入一个maven项目后,idea会把maven项目中的依赖对应的jar包导入到Externerl library外部库中,但idea没有将jar包从Externerl library自动导入到classpath,这里咋一看是有点懵的,所以顺着这个思路,我直接在项目structure里面引入相关的依赖,如下
在这里插入图片描述
直接添加依赖
在这里插入图片描述
但idea给了警告,导入的任何依赖都有可能在reimporting后失败;但我直接通过idea,让idea帮我们吧这个依赖jar包由从Externerl library自动导入到classpath,就成功了
在这里插入图片描述
事后我发现,原来是idea偷偷在该项目的pom文件下添加了相关的坐标
在这里插入图片描述
所以,透过现象看本质,这里主要就是这个项目(maven子项目)中没有声明这个pom依赖,而之所以Externerl library有这个相关jar包,原因也很简单,企业级项目是非常复杂的,maven子项目b中声明了这个依赖,所以Externerl library就会有这个相关jar包,这样的话其它maven子项目需要用到这个jar包某几个类时也需要在他们当下的maven项目中声明出来

3、顺这第2条的思路,在确定声明了pom的前提下,如下,已经声明相关依赖
在这里插入图片描述
事实上我们的确发先有些项目中所引用的类sobot-core的jar包中没有
在这里插入图片描述
所幸我直接在git上拉取该项目是拉取下的sobot-core是完整的,但jar包和我拉下来的完整sobot-core版本号也是一样的,这就让人很无语了,这里我直接定位到sobot-core-util在本地所依赖的jar包,如下
在这里插入图片描述
我把从git下拉下来的sobot-core-util手动打成jar包然后取代之前的,这样就解决了老jar包缺斤少两的问题

标准做法

  • 从git/svn上拿到sobot-core项目,然后 将core项目和core-es6项目安装到本地仓库中
命令: mvn install -Dmaven.test.skip=true -P aws-qa
  • 然后修改idea中此项目的VM options, 修改为-Dspring.profiles.active=aws-qa, 然后ChatSetApplication类的main方法启动
java -jar -Dspring.profiles.active=test springboot-demo.jar

五 常见报错

1、多模块项目mvn打包报错 ‘packaging’ with value ‘jar’ is invalid Aggregator projects require ‘pom’ as packaging
补充:如果你父项目没有声明packaging,那么就主动加上这个声明

 <packaging>pom</packaging>

2 maven常见错误:Dependency is duplicated in file(s):

3 常见错误三:Cannot resolve xxxx(依赖名):unknown

4 Could not transfer artifact xxx from/to xxx解决方案

常见错误5、IDEA提示cannot find declaration to go to

<modules>
  	<!-- 引入子模块所在的相对目录 -->
  	<module>子模块module名1</module>
  	<module>.子模块module名2</module>
  	<module>.子模块module名3</module>
 </modules>

比如chat项目中有6个模块,但实际上modules标签下仅管理了3分modules子模块,那么导入maven项目时只会导入那3个子模块modules,其它三个不会被纳入maven管理,如下
在这里插入图片描述
这里问用idea智能查找(点击package)定位到了chat-statistics子项目下,这里也不知道怎么定位的,如果可以看到真实的定位位置应该是chat-report-new,但chat-report-new就是上述我们说的情况,包含再chat项目但没有纳入modules中,所以出现这种报错

常见错误6:NoSuchMethodError 常见原因及解决方法

实际案例
这个错误是指xxx方法被调用的时候,它所属的类中并没有这个xxx方法,如下项目的父类是wzh_git,父类继承了
在这里插入图片描述
父类继承了springboot依赖

 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.2.5.RELEASE</version>

这个依赖中包含一个版本为5.2.4.RELEASE spring-core依赖,而我在wzh_git项目下又声明了一个5.1.6.RELEASE spring-core依赖,这样就出现同一个 Jar 包出现了多个(5.2.4.RELEASE和5.1.6.RELEASE)版本,此时maven也无法明确我们到底要引入那个jar包,而低版本jar包中巧合是还没有定义xxx方法的,所以报错NoSuchMethodError

六 Springboot依赖管理

参考文章:Springboot依赖管理

mybatis-plus-core如何导入的?

七,常见maven命令

maven的install可以将项目本身编译并打包到本地仓库,这样其他项目引用本项目的jar包时不用去私服上下载jar包,直接从本地就可以拿到刚刚编译打包好的项目的jar包,很灵活,避免每次都需要重新往私服发布jar包的痛苦;

例如我们的sobot-chat项目中sobot-core项目是部署到公司私服上的(公司内部工具包),我们首先从git/svn上拉取最新的项目,进入项目目录执行命令

cd sobot-core  #进入项目目录
mvn install -Dmaven.test.skip=true -P aws-qa #在项目目录下执行命令,mvn install是打包maven项目到本地仓库,test.skip=true是跳过maven生命周期的test阶段, -P aws-qa 是指在测试环境下引入这些jar包

在这里插入图片描述
修改idea中具体项目的VM options, 修改为-Dspring.profiles.active=qa,这样就会切换到测试环境下运行,此时项目中已经可以成功引入sobot-core了,原理是你本地maven仓库中已经有相关的jar包了,会在每个模块下额外生成如下
在这里插入图片描述

关于maven打包时, 资源文件没有被打包进来的问题

maven最详细的profile的使用

参考案例sobot-core下core-redis

记录一个bug,调试接口报错:解析 l o g i n . r e d i s . p o r t 失败 , 因为我们本地项目引用的的 s o b o t − c o r e 包完全是参照本地 s o b o t − c o r e 项目进行的打包,所以只要一一核对即可,进入 s o b o t − c o r e 后核对无误重新打包,在 s o b o t − c h a t 找到 {login.redis.port}失败,因为我们本地项目引用的的sobot-core包完全是参照本地sobot-core项目进行的打包,所以只要一一核对即可,进入sobot-core后核对无误重新打包,在sobot-chat找到 login.redis.port失败,因为我们本地项目引用的的sobotcore包完全是参照本地sobotcore项目进行的打包,所以只要一一核对即可,进入sobotcore后核对无误重新打包,在sobotchat找到{login.redis.port}这个位置的变量
在这里插入图片描述
找到时已经核对无误;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值