导入别人项目或者自己搭建项目时,每次必不可少都会遇到maven报错问题 (当然有可能是别人的项目pom写的不规范 自信点可能不是你的问题 但我们需要学会解决)。 这些问题 百度都不知道怎么查,最近着手自己搭建了一个springcloud聚合工程的demo 应该算是比较有代表性了,当然 springboot也可差不多 主要是理解maven的使用, 终于把这些给理解了个大概。文章有点长 原创不易
项目结构介绍: MySpringCloud为父模块,本文以红框内的模块举例, file为业务模块 调用了user-api工具模块,user-api引入了framework工具模块,两个工具模块被common模块管理
本文从多个层面分析maven综合报错问题:
- 首先一个比较低级的错误 一般有了开发经验不会犯 但是入门者可能会踩坑 要确保maven配置里面的maven仓库地址是可用的,典型错误:早期maven中央仓库是http传输的,后来改成了https, 网上可能还存在很多错误的mirrors配置 换句话说 仓库地址都是错误的 所以会导致所有依赖下载失败,此外 不同的仓库地址 某些依赖的groupId有可能会不同
-
确保了地址是可用的 groupId 和 artifactId都是无误:
maven遇到的主要错误 应该属以下几个
.A Cannot resolve xxxx 错误 .B Could not find artifact 错误 .C must be "pom" but is "jar"错误 .D 程序包XXX 不存在 .E Unable to find main class
解决方式:
- 低级错误1:找到本地maven仓库路径 查找 .lastUpdated 结尾的文件 全部删除 ,出现这种文件的情况可能由于网络不好,下载错误 并且它会阻止下次下载;
- 低级错误2:如果网络正常 且每次下载都是这个文件,那么很可能就是依赖版本号不正确,远程仓库根本没有这个包,所以一直都是 lastUpdated 。
- 正文开始 用一个父子多模块maven项目 pom.xml文件实际举例 重点都在注释上面,顺便写了个英文版注释,因为xml比较容易乱码,项目几经周转很可能注释就乱了,这些注释就不复制出来了 研究这玩意 我累了。
父pom
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 子项目继承父项目pom文件时 父项目需要packing指定为pom
daclare the packing:pom when child extends this moudule-->
<packaging>pom</packaging>
<groupId>com.demo</groupId>
<artifactId>MySpringCloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>MySpringCloud</name>
<description>Demo project for Spring Boot</description>
<!-- 配置版本 version config 用于依赖管理版本号el表达式取值
act on dependencyManagement-dependencies-dependency-version by ${xxx.version}-->
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
<nacos.version>1.3.0</nacos.version>
<sentinel.version>1.8.2</sentinel.version>
<openfeign.version>2.2.5.RELEASE</openfeign.version>
<netflix-hystrix.version>2.2.5.RELEASE</netflix-hystrix.version>
<fastjson.version>1.2.76</fastjson.version>
<servlet.version>4.0.1</servlet.version>
</properties>
<!-- author by qkj-->
<!-- 声明依赖及其版本 但不引入, 子模块进行引入 (但子模块无需声明版本 否则会使用声明的版本号)-->
<!-- note: dependencyManagement only declare the dependency Id and version but not import,
child moudule should import again without declare the version when need dependency -->
<!-- 注意:dependencyManagement与dependencies区别 如果在父模块使用dependencies,子模块都继承,不管用不用得上-->
<!-- note: difference with dependencies:child moudule extends dependencies unconditional -->
<dependencyManagement>
<dependencies>
<!-- diff:cloud-dependencies and cloud-starter?
dependencies only declare the version and download jar with starter -->
<!-- cloud-dependencies and cloud-starter 的区别 一般带 dependencies 的 artifactId 都是声明版本
点进去看就能发现 里面是声明的dependencyManagement, 而starter则是我们要下载具体的xxx-starter.jar包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<!-- 需要加上type 否则在阿里云可能下载不了
declare type:pom or maybe download fall in alibaba maven
type pom: 已打包为pom工程-->
<!-- 同理 如果我们写了一个聚合工程 且把聚合工程当成基础包供其它项目使用
其它项目把parent指定为基础包,并在依赖引入 声明type为pom即可 -->
<type>pom</type>
</dependency>
<!-- alibaba与cloud整合 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<!-- scope:import can only declare in dependencyManagement; resolve the problem of single extends -->
<!--<scope>import</scope> 只会在dependencyManagement中出现-->
<!-- 解决单继承问题 换句话说 加上import 可以使用spring-cloud-alibaba-dependencies面的dependencyManagement -->
<!-- such as spring-cloud-alibaba-dependencies already include spring-cloud-starter-alibaba-nacos-discovery
child module can declare spring-cloud-starter-alibaba-nacos-discovery without version-->
<scope>import</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>${lombok.version}</version>
</dependency>
<!--fastjson 过低版本会有漏洞(建议关注新版) low version such as 1.2.71 before with remote bug-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- nacos注册中心客户端 内置ribbon-->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
</dependency>
<!-- sentinel-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>${sentinel.version}</version>
</dependency>
<!-- sentinel控制台-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>${sentinel.version}</version>
</dependency>
<!--feign 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${openfeign.version}</version>
</dependency>
<!-- feign集成hystrix豪猪降级-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>${netflix-hystrix.version}</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
</dependency>
<!-- skywalking工具类:自定义链路追踪等-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<!-- 与sw版本对应 -->
<version>${skywalking.version}</version>
</dependency>
<!-- skywalking和logback整合-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>${skywalking.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 可以理解为声明子类(子模块) -->
<modules>
<module>common</module>
<module>user</module>
<module>file</module>
</modules>
<!--注意 子模块有工具类(没有main方法的模块)
不能在父模块这里声明maven插件 子模块继承 会导致打包报错:找不到main方法(unalbe to find main class) -->
<!-- <build>-->
<!-- <plugins>-->
<!-- <plugin>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-maven-plugin</artifactId>-->
<!-- <configuration>-->
<!-- <excludes>-->
<!-- <exclude>-->
<!-- <groupId>org.projectlombok</groupId>-->
<!-- <artifactId>lombok</artifactId>-->
<!-- </exclude>-->
<!-- </excludes>-->
<!-- </configuration>-->
<!-- <version>2.3.4.RELEASE</version>-->
<!-- </plugin>-->
<!-- </plugins>-->
<!-- </build>-->
</project>
子pom
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.demo</groupId>
<artifactId>MySpringCloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<!-- 因为file是我们的业务模块 通俗点说是一个小项目 到时候要打包java -jar运行的 所以打包方式为jar(可以不写 默认为jar) 而不是pom-->
<packaging>jar</packaging>
<groupId>com.qkj</groupId>
<artifactId>file</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>file</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- 父模块该依赖为pom 子模块该依赖也尽量定义为pom
父模块该依赖未使用<scope>import</scope>:当前模块如果还有子模块必须声明为pom 没有则随意 -->
<!-- 但是父模块该依赖使用了import 可以理解为继承了该依赖内置的dependencyManagement 必须使用pom 且声明版本号-->
<!-- must declare type:pom when child module exist or parent module dependency declare scope:import;
version should be declared if parent module dependency declare scope:import,else type could be default or other-->
<!-- so shoule better declare the type: pom -->
<version>${spring-cloud.version}</version>
<type>pom</type>
</dependency>
<!-- alibaba与cloud整合 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--fastjson 注意过低版本会有漏洞 low version such as 1.2.71 before with remote bug-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- nacos注册中心客户端 内置ribbon-->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<!-- sentinel-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
<!-- sentinel控制台-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>
<!--feign 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 豪猪熔断-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--Nacos Discovery-->
<!-- 在spring-cloud-alibaba-dependencies里面声明了版本 又因为设置了scope:import 所以在我们自己写的父模块pom文件中 不能显式看到-->
<!-- declare in spring-cloud-alibaba-dependencies-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--实现配置的动态变更-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- skywalking工具类:自定义链路追踪等-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
</dependency>
<!-- skywalking和logback整合 print traceId in our logs-->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
</dependency>
<dependency>
<groupId>com.qkj</groupId>
<artifactId>user-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- scope :默认provided 没有传递性 ,compile具有传递性 换句话说就是会把jar包打进来,而runtime表示不作用在编译时 如JDBC驱动-->
<!-- compile can pass on but provided(default) can't , runtime means not compile-->
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<version>2.3.4.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
工具类父pom :common.pom
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.demo</groupId>
<artifactId>MySpringCloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<packaging>pom</packaging>
<groupId>com.qkj</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>common</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<modules>
<module>file-api</module>
<module>user-api</module>
<module>framework</module>
</modules>
<!-- 注意工具类pom中 不能有maven打包插件 同理 不能写在最外层的父级模块中 否则子模块会继承-->
</project>
工具类子pom : user-api.pom
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.qkj</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<artifactId>user-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user-api</name>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--feign 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.qkj</groupId>
<artifactId>framework</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- scope :默认provided 没有传递性 ,compile具有传递性 换句话说就是会把jar包打进来,而runtime表示不作用在编译时 如JDBC驱动-->
<!-- compile can pass on but provided(default) can't , runtime means not compile-->
<scope>compile</scope>
</dependency>
<!-- 注意工具类pom中 不能有maven打包插件 同理 不能写在最外层的父级模块中 否则子模块会继承-->
</dependencies>
</project>
工具类子pom: framework.pom
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.qkj</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<artifactId>framework</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>framework</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--feign 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
</project>
什么时候可以不写version?
父pom dependencyManagement 里面声明了version, 而子pom继承了 父pom(parent 节点声明继承关系) ,子pom依赖不声明版本,则使用父pom依赖版本,这在多子模块项目中方便管理。 而整个pom不存在parent时,version是一定要写的,如果不写则会报错
type: 默认为jar 因为我们的是聚合工程,所以父模块要声明为pom,否则会报must be “pom” but is "jar"错误
总结:
- maven仓库地址有误或下载缓慢 网络不好 (推荐使用阿里仓库)
- 版本号错误 或缺少版本号
- 多模块项目中未正确声明父模块groupId artifactId
- pom工程中 未正确声明type
- 父模块中声明了maven打包插件 而子模块含有工具类模块