将自己的开源 jar 包上传至 Maven 中央仓库,其中还是有不少坑的,所一开一篇文章做下记录。

# 注册 sonatype 账号

  • 进入 issues.sonatype.org 注册账号,基于这个平台才可以上传至 Maven 仓库。
    pPBJoeU.png
  • 注册完成后需要记住 账号 密码 ,后面上传需要进行授权验证。

# 新建 Maven 项目工单

  1. 项目选择: Community Support - Open Source Project Repository Hosting (OSSRH)
  2. 问题选择: New Project
    pPBYSeO.png
  3. Group Id : 推荐使用自己的域名,并遵循以下格式
    • 例如: rainrem.top
    • 则填: top.rainrem
  4. Project URL : 项目地址
  5. SCM url : 项目克隆地址
  6. Username(s) : 注册时的用户名
    pPBtOr6.png
  7. 新建工单后等待管理员审核
  8. 问题 → 我的报告中查看 issue 进度
    pPBNseK.png
  9. 等待几分钟后,就会收到 OSSRH 的回复,如下图
    pPBN4yt.png
  10. 翻译为中文的报告显示
    pPBUbB6.png
  11. 自己的域名,则需要在域名解析中增加 TXT 的解析
    pPBU81A.png
  12. 如果是 io.github.xxx 这种 git 域名,则需要新建完整公开的 git 仓库,如下两个图 (网上找的)
    pPBUDpj.png
    pPBUr1s.png
  13. 然后点击 Respond 按钮开启工单,让管理员去验证
  14. 等待回复,回复结果如下,就表示可以推送你的 jar 包到仓库中了
    pPBUXND.png
  15. 翻译为中文的报告显示
    pPBUx9H.png

# GPG 密匙处理

  • 我们需要使用 gpg 生成秘钥,在后续发布 jar 包时会根据生成的秘钥进行校验。
  • 因为 sonatype 也需要对上传这一行为进行权限的校验,避免恶意上传文件的行为。

# 安装 gpg

  • 官网下载地址:www.gnupg.org
  • Window 版下载地址:gpg4win-4.0.4.exe
  • 下载完成后一路点击下一步即可完成安装。

# 创建秘钥

  • 安装完成后,打开命令行执行下面命令来生成秘钥。
命令行提示符
gpg --gen-key
  • 在生成秘钥的过程中,会要求输入姓名和邮箱地址。
  • 在命令行窗口下填完这两个信息后,还会弹窗要求输入一个生成秘钥的密码,切记需要记住此密码下面会用到。
    pPBdbFO.png
  • 填完后继续,秘钥就会成功生成并保存在本地目录下。
    pPBw9Tf.png

# 上传秘钥

  • 我们需要把公钥上传至服务器供 sonatype 验证,通过下面命令上传公钥。
命令行提示符
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys 你自己的秘钥
  • 验证公钥是否成功上传至服务器
命令行提示符
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --recv-keys 你自己的秘钥

pPB0WrR.png

  • 如果上传失败请更换服务器地址将 keyserver.ubuntu.com 替换以下其中之一,全部都是 11371 的端口
    • pool.sks-keyservers.ne
    • keys.openpgp.org
    • pgp.mit.edu
  • 这些公钥服务器间会同步它们的数据给其他服务器,所以只要上传成功到其中一台可以。

# settings.xml 配置

  • 如果不知道 Mavensettings.xml
    的位置,打开 IDEA文件设置构建、执行、部署构建工具Maven
  • 查看 Maven 主路径,如果是 Bundled (Maven 3)settings.xml 的位置则在你安装 IDEA
    路径下的→ pluginsmavenlibmaven3conf 文件夹下
  • 例如: C:\LightRainData\IDEA\IntelliJ IDEA 2023.1.2\plugins\maven\lib\maven3\conf
<!-- 在 settings.xml 中的 servers 节点下添加 -->
<server>
    <!-- 此处 id 需要和 pom.xml 中配置的 serverId 保持一致 -->
    <id>ossrh</id>
    <!-- 配置你注册 issues.sonatype.org 的账号密码 -->
    <username>LightRain</username>
    <password>xxx</password>
</server>
<!-- 在 settings.xml 中的 profiles 节点下添加 -->
<profile>
    <!-- 此处 id 需要和 pom.xml 中配置的 serverId 保持一致 -->
    <id>ossrh</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
        <gpg.executable>gpg</gpg.executable>
        <!-- 生成秘钥时填写的密码 -->
        <gpg.passphrase>2qmT84jWycBh</gpg.passphrase>
    </properties>
</profile>
  • 以下为 settings.xml 的全部配置
settings.xml
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 http://maven.apache.org/xsd/settings-1.2.0.xsd">
    <pluginGroups></pluginGroups>
    <proxies></proxies>
    <servers>
        <server>
            <!-- 此处 id 需要和 pom.xml 中配置的 serverId 保持一致 -->
            <id>ossrh</id>
            <!-- 配置你注册 issues.sonatype.org 的账号密码 -->
            <username>LightRain</username>
            <password>xxx</password>
        </server>
    </servers>
    <mirrors>
        <mirror>
            <id>maven-default-http-blocker</id>
            <mirrorOf>external:http:*</mirrorOf>
            <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
            <url>http://0.0.0.0/</url>
            <blocked>true</blocked>
        </mirror>
    </mirrors>
    <profiles>
        <profile>
            <!-- 此处 id 需要和 pom.xml 中配置的 serverId 保持一致 -->
            <id>ossrh</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <gpg.executable>gpg</gpg.executable>
                <!-- 生成秘钥时填写的密码 -->
                <gpg.passphrase>2qmT84jWycBh</gpg.passphrase>
            </properties>
        </profile>
    </profiles>
</settings>
  • 将修改完成后的 settings.xml 保存。
    1. 修该 IDEAMaven 下的 settings.xml 路径指向
    2. 或将 settings.xml 复制一份到 User 用户下的 .m2 文件夹下
    3. 例如: C:\User\LightRain\.m2\settings.xml
      pPBsNF0.png

# pom.xml 配置

pom.xml
<?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 一定要和你申请工单的 groupId 保持一致 -->
    <groupId>top.rainrem</groupId>
    <!-- 项目名称 -->
    <artifactId>toolbox</artifactId>
    <!-- 版本号 -->
    <version>1.0.0-RELEASE</version>
    <!-- 名称 -->
    <name>toolbox</name>
    <!-- 描述 -->
    <description>工具</description>
    <properties>
        <!-- 项目使用的 java 版本 -->
        <java.version>17</java.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- 项目仓库地址,根据实际情况修改 -->
        <projectUrl>https://gitee.com/RainSauce/toolbox.git</projectUrl>
        <!-- serverId 配置,需要和 settings.xml 中 servers.server.id 保持一致 -->
        <serverId>ossrh</serverId>
    </properties>
    <!-- 开发者信息 -->
    <developers>
        <developer>
            <name>LightRain</name>
            <email>3164395730@qq.com</email>
            <url>${projectUrl}</url>
        </developer>
    </developers>
    <url>${projectUrl}</url>
    <!-- 许可证信息,这里是 Apache 2.0 的许可证,大家根据实际情况修改 -->
    <licenses>
        <license>
            <name>The Apache Software License, Version2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
            <distribution>repo,manual</distribution>
        </license>
    </licenses>
    <scm>
        <!-- 采用 projectUrl 变量代替这个值,方便给重复利用这个配置,也就是上面的标签替换一下值就行 -->
        <connection>${projectUrl}</connection>
        <developerConnection>${projectUrl}</developerConnection>
        <url>${projectUrl}</url>
    </scm>
    <distributionManagement>
        <snapshotRepository>
            <!-- 这个 id 和 settings.xml 中 servers.server.id 要相同,因为上传 jar 需要登录才有权限 -->
            <id>${serverId}</id>
            <name>OSS Snapshots Repository</name>
            <!-- 官方仓库地址不需要修改 -->
            <url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
        </snapshotRepository>
        <repository>
            <!-- 这个 id 和 settings.xml 中 servers.server.id 要相同,因为上传 jar 需要登录才有权限 -->
            <id>${serverId}</id>
            <name>OSS Staging Repository</name>
            <!-- 官方仓库地址不需要修改 -->
            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
        </repository>
    </distributionManagement>
    <dependencies>
        <!-- 此处坐标依赖自己决定添加 -->
    </dependencies>
    <!-- 打包及插件信息 -->
    <!-- 这些配置基本不用修改,原样粘贴进去即可 -->
    <!-- 如果 plugins 中的坐标爆红,将其添加到 dependencies 中完成拉去即可解决 -->
    <!-- 其中 maven-gpg-plugin 插件会调用上文中安装的 GnuPG 软件,对文件进行签名 -->
    <profiles>
        <profile>
            <id>release</id>
            <build>
                <plugins>
                    <!-- Source -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-source-plugin</artifactId>
                        <version>2.2.1</version>
                        <executions>
                            <execution>
                                <phase>package</phase>
                                <goals>
                                    <goal>jar-no-fork</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <!-- Javadoc -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-javadoc-plugin</artifactId>
                        <version>2.9.1</version>
                        <configuration>
                            <show>private</show>
                            <nohelp>true</nohelp>
                            <charset>UTF-8</charset>
                            <encoding>UTF-8</encoding>
                            <docencoding>UTF-8</docencoding>
                            <additionalparam>-Xdoclint:none</additionalparam>
                            <!-- TODO 临时解决不规范的 javadoc 生成报错,后面要规范化后把这行去掉 -->
                        </configuration>
                        <executions>
                            <execution>
                                <phase>package</phase>
                                <goals>
                                    <goal>jar</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <!-- GPG -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-gpg-plugin</artifactId>
                        <version>1.6</version>
                        <executions>
                            <execution>
                                <phase>verify</phase>
                                <goals>
                                    <goal>sign</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <!--Compiler -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>3.0</version>
                        <configuration>
                            <source>1.8</source>
                            <target>1.8</target>
                            <fork>true</fork>
                            <verbose>true</verbose>
                            <encoding>UTF-8</encoding>
                        </configuration>
                    </plugin>
                    <!--Release -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-release-plugin</artifactId>
                        <version>2.5.1</version>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>
  • 需要注意的地方:
    • snapshotRepository 是项目快照版本 snapshot 上传地址,如果项目的版本号,如: 1.0.0-SNAPSHOT ,会上传到这个仓库。
    • 通常情况下 repository 是我们真正需要发布项目的远程仓库上传地址。需要注意的是我们这里写的是 staging
      暂存地址,而不是 release 版本的地址。(为什么这么做?后文详述)
    • 我们上传的远程仓库的地址是带 s01 前缀的,而比较旧的文章中不带 s01 前缀。
    • 因为旧的 sonatype maven 仓库已经资源满了,官方新建了一个 s01 maven 仓库。
    • 现阶段在 sonatype JIRA 管理平台上注册的用户,只能上传这个新的 s01 仓库。

# 打包上传

  • 在项目根目录下,运行下面的命令进行 maven 打包操作 (同时将项目 jar deploy 到远程 maven 仓库)。
  • 在打包运行过程中,会弹出一个对话框提示你输入密钥 Passphrase ,输入上文 gpg 生成秘钥的密码即可。
  • -Dmaven.test.skip=true 表示跳过测试代码
命令行提示符
mvn clean install deploy -P release -Dmaven.test.skip=true

pPBRGmF.png

  • 需要注意的是:
    • 不要使用 IDEAmaven 打包, IDEAmaven 打包会报错,无法执行 gpg
      命令,至于为什么我也不清楚,使用上文的 CMD 命令行打包即可。
    • 使用 mvn 命令行打包的时候,需要注意你的 JAVA_HOME 环境变量的指向,是不是你期望的版本。
    • 如果 maven depoly 发布命令报 401 authentication 错误,是因为你的 mavensetting.xml
      server 配置的用户名密码错误,或者 setting.xmlserver 配置 idpom
      里面配置的 repository id 不一致导致的。
    • 也有可能你的电脑上 maven 多个版本,项目使用的不是同一个 setting.xml
    • 如果报 400 错误,很有可能是你已经上传过的 jar,同一个版本再次重复上传了。
  • 如果使用 mvn 命令时出现 mvn 不是内部或外部命令←请点击查看
    pPB6e8f.png
  • 上传成功后,可在官网查看到 Nexus Repository Manager
    pPBR0l6.png
  • 并且在 OSSRH 中也能收到反馈。
    pPB27J1.png

# 同步到中央仓库

  • 上面的步骤只是把项目传到了 sonatype 上了,还没有发布出去,中央仓库中还不存在。
  • 进入 Nexus Repository Manager 使用在 sonatype 注册的账号登录即可。
  • 点击旁边的 Staging Repositories 即可看到我们上传的项目。
    pPB2PrF.png
    pPB2kVJ.png
    pPB2Aa9.png
  • 点击 Refresh 按钮刷新查看 Release 按钮是否可以点击
    pPB2WsU.png
  • 只要确认同步到 Maven 中央仓库中你就无法进行修改和删除这是为了保护稳定性,但你可以发布新版本。
  • 然后就是等待就可以了!
    • 账号密码和上面注册的 ossrh 一致
    • https://s01.oss.sonatype.org
    • 一般 30 分钟后能查看
    • https://repo1.maven.org/maven2/
    • 一般 4 小时后能查看
    • https://search.maven.org/
    • 一般 24 小时后能查看
    • https://mvnrepository.com/
  • 一切都 OK 之后,最好回到 sonatype JIRA 管理平台将 “问题” 关闭,这样 sonatype JIRA 管理流程就全部完成了。

# 总结

以后发布项目,如果 groupId 不变的话,我们就不需要再去申请工单了。
上述 settings.xml 已经配置了 servers ,就不用再次配置了,即第二步配置 settings.xml 可以省略了。
秘钥也已经生成过了,也不需要再次生成了, 即第三步的秘钥生成也不需要了。
不过如果更换了电脑,那就要重新配置 settings.xml 并重新生成并上传秘钥了。