Maven 依赖上传到 Nexus 私服后本地仍报 “was not found”

一、问题现象

把一个第三方 jar 上传到公司 Nexus 私服后,本地编译一直报错:

[ERROR] The following artifacts could not be resolved:
com.yonyou.iuap:iuap-ip-openapi-sdk:jar:8.2.100-RELEASE (present, but unavailable):
Could not find artifact com.yonyou.iuap:iuap-ip-openapi-sdk:jar:8.2.100-RELEASE
in nexus-public (http://maven.puyiyun.com/repository/maven-public/)

诡异的地方在于:浏览器里能正常下载这个 jar,链接是通的,信息也完全一致。

http://maven.puyiyun.com/repository/maven-releases/com/yonyou/iuap/iuap-ip-openapi-sdk/8.2.100-RELEASE/iuap-ip-openapi-sdk-8.2.100-RELEASE-RELEASE.jar
图 1:仓库中真实文件名末尾多出了一段 -RELEASE

二、先排除掉的那些”常见嫌疑”

按常规思路排查了一圈,全部排除:

排查项结论
Nexus 上文件是否存在存在,curl -I 返回 200
settings.xml 的 mirror / profile / server 认证正确,同仓库其他依赖都能正常拉取
本地缓存 .lastUpdated / _remote.repositories已删除对应目录并 -U 强制更新,无效
release / snapshot 类型不匹配是 RELEASE,无问题

到这里基本可以确定:不是权限、不是网络、不是缓存、不是配置,而是”坐标”和”文件名”对不上。

三、根因:jar 文件名多了一个 classifier

把 Maven 要找的文件和仓库里实际存在的文件并排看,一目了然:

文件名
Maven 按坐标 8.2.100-RELEASE 要找的iuap-ip-openapi-sdk-8.2.100-RELEASE.jar
Nexus 上真实存在的iuap-ip-openapi-sdk-8.2.100-RELEASE-RELEASE.jar

按 Maven 的命名规范:

{artifactId}-{version}[-{classifier}].{extension}

version 是 8.2.100-RELEASE,那么末尾多出来的那段 RELEASE 就被解析成了一个 classifier。也就是说,仓库里只有”带 classifier 的 jar”,没有主 jar。

这也解释了报错里那句很特别的措辞 —— present, but unavailable:Maven 在仓库里找到了该 artifact 的目录和 pom(所以是 present),但按无 classifier 的坐标请求主 jar 时找不到文件(所以 unavailable)。

小结:Could not find artifact + present, but unavailable 这个组合,八成是坐标与文件名不匹配,而不是仓库真没有。

四、解决方案

方案 A(应急):在 pom 里补上 classifier

如果只是想先把编译跑通、暂时不方便动仓库:

<dependency>
    <groupId>com.yonyou.iuap</groupId>
    <artifactId>iuap-ip-openapi-sdk</artifactId>
    <version>8.2.100-RELEASE</version>
    <classifier>RELEASE</classifier>
</dependency>

缺点很明显:这是”迁就错误命名”,团队里其他人拉取时也得跟着加 classifier,而且传递依赖可能仍解析不到。只适合救火。

方案 B(治本,我最终采用的):重命名后重新上传

关键动作只有一个——把本地文件名改成和坐标完全一致:

iuap-ip-openapi-sdk-8.2.100-RELEASE.jar
iuap-ip-openapi-sdk-8.2.100-RELEASE.pom

即去掉末尾多出来的那个 -RELEASE,然后重新上传:

  • Repository 选 maven-releases
  • Group / Artifact / Version 填 com.yonyou.iuap / iuap-ip-openapi-sdk / 8.2.100-RELEASE
  • Classifier 留空,Extension 分别是 jar 和 pom
  • 不要勾选 “Generate a POM file with these coordinates”(已有真实 pom,勾了会被空 pom 覆盖,传递依赖全丢)
图 2:Upload component 表单,Classifier 留空、Extension 填 jar / pom

上传后清掉本地该版本目录,强制拉取:

rm -rf ~/.m2/repository/com/yonyou/iuap/iuap-ip-openapi-sdk/8.2.100-RELEASE
mvn clean compile -U

编译通过,问题解决。

五、一个意外发现:pom 用 .xml 还是 .pom,效果不一样

重新上传过程中发现一个很有意思的现象:内容完全相同的 pom 文件,仅后缀不同,结果就不同。

pom 文件名Extension 填 pom、Classifier 留空时的结果
xxx.xmljar 落盘为 ...-8.2.100-RELEASE-RELEASE.jar(双 RELEASE)
xxx.pomjar 落盘为 ...-8.2.100-RELEASE.jar(正确)

原因推测在于 Nexus 上传 maven2 组件时的坐标来源优先级:

pom 里解析出的 GAV > 表单手填的 GAV

Components REST API 文档里,maven2.groupId / artifactId / version 都标注为 “Yes, unless a POM asset is included in the upload” —— 只要上传里带了可识别的 pom,Nexus 就以 pom 内容为准,并按规范重命名整个组件的资产。

  • 命名为 .pom 时:被识别为 pom 资产 → 解析出权威坐标 → 按 {artifactId}-{version}.jar 规范化重命名 → 正确
  • 命名为 .xml 时:很可能未被识别为 pom 资产(判定依据偏向文件名后缀,而非 Extension 输入框里手填的字符串)→ 缺少权威坐标 → 只能照抄本地文件名 → 双 RELEASE 被原样带进仓库

顺带解释了之前另一个怪现象:上传时 Classifier 会被自动填成 RELEASE。同样是这套逻辑——Nexus 拿第一个文件的文件名去猜 artifactId-version-classifier.ext,看到 ...-8.2.100-RELEASE-RELEASE.jar 就把末尾那段当成 classifier 填进去了。手动清空只是掩盖症状,根子仍是源文件名不合规。

⚠️ 这个”靠文件名后缀识别 pom”的细节在不同 3.x 小版本实现上有差异,不要当成稳定契约依赖,只作为”为什么会出现不一致”的解释。

六、经验沉淀(Checklist)

以后往 Nexus 传第三方 jar,按这个顺序走基本不会翻车:

  1. 先规范文件名:{artifactId}-{version}.jar / {artifactId}-{version}.pom,pom 一律用 .pom 后缀,不要用 .xml
  2. 核对 pom 内部坐标与表单填写一致,否则 metadata 会不匹配
  3. 不要勾 Generate POM(除非你确实没有 pom)
  4. 上传后立刻用 curl 校验,两个都 200 才算可用:
curl -I ".../8.2.100-RELEASE/iuap-ip-openapi-sdk-8.2.100-RELEASE.jar"
curl -I ".../8.2.100-RELEASE/iuap-ip-openapi-sdk-8.2.100-RELEASE.pom"
  1. 删掉仓库里遗留的错误命名 asset,避免后人踩同一个坑
  2. 本地清缓存 + -U 验证

七、更推荐的做法:用命令行上传

网页上传的坑在于文件名会影响结果。mvn deploy:deploy-file 则完全不看你本地文件叫什么,一律按 GAV 生成路径和文件名,还能批量处理:

mvn deploy:deploy-file \
  -DgroupId=com.yonyou.iuap \
  -DartifactId=iuap-ip-openapi-sdk \
  -Dversion=8.2.100-RELEASE \
  -Dpackaging=jar \
  -Dfile=iuap-ip-openapi-sdk-8.2.100-RELEASE.jar \
  -DpomFile=iuap-ip-openapi-sdk-8.2.100-RELEASE.pom \
  -DrepositoryId=nexus-releases \
  -Durl=http://maven.puyiyun.com/repository/maven-releases/

若确实没有 pom,可用 -DgeneratePom=true 让 Maven 生成,但生成的 pom 不含依赖声明,传递依赖会丢失,能拿到原始 pom 就尽量用 -DpomFile。

八、一句话总结

不是仓库没有、也不是配置问题,而是上传时文件名多带了一段 RELEASE,被 Maven 解析成了 classifier,导致主 jar 缺失。 把本地 jar/pom 重命名为与坐标完全一致后重新上传即可;pom 文件后缀用 .pom 而不是 .xml,或直接改用 mvn deploy:deploy-file,能从根本上避免这类”文件名决定命运”的坑。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部