从 Gitee 开源项目发布到 Maven Central 中央仓库完整指南

本文将详细介绍如何将一个托管在 Gitee 上的开源 Java 项目发布到 Maven Central 中央仓库,涵盖账号注册、GPG 密钥配置、POM 文件配置以及部署脚本等完整流程。

目录

  1. 前置准备
  2. [注册 Sonatype 账号](#注册 Sonatype 账号)
  3. 验证命名空间
  4. [GPG 密钥安装与配置(Mac版)](#GPG 密钥安装与配置(Mac版))
  5. [Maven settings.xml 配置](#Maven settings.xml 配置)
  6. [POM 文件配置](#POM 文件配置)
  7. 执行部署
  8. 常见问题与解决方案

1. 前置准备

在开始之前,请确保你已具备以下条件:

  • Java 开发环境 :JDK 8+ 已安装并配置好 JAVA_HOME
  • Maven 环境 :Maven 3.6+ 已安装并配置好 M2_HOME
  • Gitee 账号:已有开源项目托管在 Gitee 上
  • 有效的邮箱:用于注册 Sonatype 账号和 GPG 密钥

2. 注册 Sonatype 账号

2.1 访问 Sonatype Central Portal

访问 https://central.sonatype.com/ 并注册账号。

注意:2024年起,Sonatype 启用了新的 Central Portal,取代了原有的 OSSRH (oss.sonatype.org)。

2.2 登录方式

支持以下登录方式:

  • GitHub 账号登录
  • Google 账号登录
  • 邮箱注册登录

推荐使用 GitHub 登录,便于后续验证命名空间。


3. 验证命名空间

3.1 什么是命名空间?

命名空间即你的 groupId,例如 io.gitee.ziqistudio。Maven Central 要求你必须证明拥有该命名空间的所有权。

3.2 Gitee 命名空间验证

对于 Gitee 项目,命名空间格式为:io.gitee.{用户名或组织名}

验证步骤:

  1. 登录 Sonatype Central Portal
  2. 进入 Namespaces 页面
  3. 点击 Add Namespace
  4. 输入命名空间,如 io.gitee.ziqistudio
  5. 系统会生成一个验证码(Verification Key)
  6. 在 Gitee 上创建一个与验证码同名的公开仓库
  7. 回到 Sonatype 点击 Verify

示例:

复制代码
验证码:abc123xyz
创建仓库:https://gitee.com/ziqistudio/abc123xyz

验证成功后,状态会变为 Verified


4. GPG 密钥安装与配置(Mac版)

4.1 安装 GPG

使用 Homebrew 安装 GPG:

bash 复制代码
# 安装 GPG
brew install gnupg

# 安装 pinentry-mac(用于密码输入)
brew install pinentry-mac

# 验证安装
gpg --version

4.2 生成 GPG 密钥对

bash 复制代码
# 生成密钥(推荐使用 RSA 4096)
gpg --full-generate-key

按照提示操作:

复制代码
请选择您要使用的密钥类型:
   (1) RSA 和 RSA
   (2) DSA 和 Elgamal
   (3) DSA(仅用于签名)
   (4) RSA(仅用于签名)
   (9) ECC(签名和加密)
  (10) ECC(仅用于签名)
您的选择是? 1

RSA 密钥的长度应在 1024 位与 4096 位之间。
您想要使用的密钥长度?(3072) 4096

请设定这个密钥的有效期限。
         0 = 密钥永不过期
密钥的有效期限是?(0) 0

真实姓名: Your Name
电子邮件地址: your-email@example.com
注释: Maven Central Deploy Key

# 设置一个强密码(passphrase),后续部署时需要使用

4.3 查看密钥信息

bash 复制代码
# 列出所有密钥
gpg --list-keys

# 列出私钥及 keygrip(用于免密配置)
gpg --list-secret-keys --keyid-format LONG

输出示例:

复制代码
/Users/username/.gnupg/pubring.kbx
----------------------------------
pub   rsa4096/14C5CF1B443259C5 2024-01-01 [SC]
      14C5CF1B443259C5E6028F87492BAC9CB7397FFA
uid                 [ultimate] Your Name <your-email@example.com>
sub   rsa4096/XXXXXXXXXXXXXXXX 2024-01-01 [E]

其中 14C5CF1B443259C5E6028F87492BAC9CB7397FFA 是完整的密钥 ID。

4.4 上传公钥到密钥服务器

Maven Central 要求公钥必须上传到公开的密钥服务器:

bash 复制代码
# 上传到多个密钥服务器(确保可用性)
gpg --keyserver keyserver.ubuntu.com --send-keys 14C5CF1B443259C5E6028F87492BAC9CB7397FFA
gpg --keyserver keys.openpgp.org --send-keys 14C5CF1B443259C5E6028F87492BAC9CB7397FFA
gpg --keyserver pgp.mit.edu --send-keys 14C5CF1B443259C5E6028F87492BAC9CB7397FFA

4.5 配置 GPG Agent(解决 /dev/tty 问题)

在 macOS 上,非交互式环境(如 IDE 或 CI)中运行 Maven 时,可能遇到以下错误:

复制代码
gpg: cannot open '/dev/tty': Device not configured

解决方案:

  1. 配置 gpg.conf
bash 复制代码
# 创建或编辑 ~/.gnupg/gpg.conf
echo "use-agent" >> ~/.gnupg/gpg.conf
echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf
  1. 配置 gpg-agent.conf
bash 复制代码
# 创建或编辑 ~/.gnupg/gpg-agent.conf
cat >> ~/.gnupg/gpg-agent.conf << 'EOF'
allow-loopback-pinentry
default-cache-ttl 600
max-cache-ttl 7200
EOF
  1. 重启 GPG Agent
bash 复制代码
gpg-connect-agent reloadagent /bye
  1. 预缓存密码(可选)
bash 复制代码
# 使用此命令预缓存密码,避免每次都输入
echo "test" | gpg --batch --yes --pinentry-mode loopback --passphrase "YOUR_PASSPHRASE" --sign > /dev/null 2>&1

4.6 导出密钥(备份)

bash 复制代码
# 导出公钥
gpg --armor --export your-email@example.com > public-key.asc

# 导出私钥(妥善保管!)
gpg --armor --export-secret-keys your-email@example.com > private-key.asc

5. Maven settings.xml 配置

5.1 生成 Sonatype Token

  1. 登录 Sonatype Central Portal
  2. 点击右上角用户头像 → View Account
  3. 进入 Generate User Token
  4. 记录生成的 usernamepassword(Token)

5.2 配置 settings.xml

编辑 ~/.m2/settings.xml

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
                              https://maven.apache.org/xsd/settings-1.2.0.xsd">

    <servers>
        <!-- Sonatype Central Portal 认证 -->
        <server>
            <id>sonatype</id>
            <!-- 使用 Token 认证(推荐) -->
            <username>生成的Token用户名</username>
            <password>生成的Token密码</password>
        </server>
    </servers>

    <profiles>
        <profile>
            <id>gpg</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <!-- GPG 可执行文件路径(Mac 通常为 gpg) -->
                <gpg.executable>gpg</gpg.executable>
                <!-- GPG 密钥 ID -->
                <gpg.keyname>14C5CF1B443259C5E6028F87492BAC9CB7397FFA</gpg.keyname>
                <!-- 可选:配置密码(不推荐明文存储) -->
                <!-- <gpg.passphrase>YOUR_PASSPHRASE</gpg.passphrase> -->
            </properties>
        </profile>
    </profiles>

    <activeProfiles>
        <activeProfile>gpg</activeProfile>
    </activeProfiles>

</settings>

5.3 密码加密(推荐)

使用 Maven 密码加密功能保护密码:

bash 复制代码
# 创建主密码
mvn --encrypt-master-password

# 将输出保存到 ~/.m2/settings-security.xml
cat > ~/.m2/settings-security.xml << 'EOF'
<settingsSecurity>
  <master>{加密后的主密码}</master>
</settingsSecurity>
EOF

# 加密服务器密码
mvn --encrypt-password

6. POM 文件配置

6.1 必需的元数据

Maven Central 对 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>

    <!-- 必需:GAV 坐标 -->
    <groupId>io.gitee.ziqistudio</groupId>
    <artifactId>spring-boot-starter-exception-i18n</artifactId>
    <version>3.0.1</version>
    <packaging>jar</packaging>

    <!-- 必需:项目名称和描述 -->
    <name>Spring Boot Starter - Exception I18N</name>
    <description>Spring Boot Starter for exception internationalization</description>

    <!-- 必需:项目 URL -->
    <url>https://gitee.com/ziqistudio/spring-exception-i18n</url>

    <!-- 必需:许可证信息 -->
    <licenses>
        <license>
            <name>Apache License, Version 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0</url>
        </license>
    </licenses>

    <!-- 必需:开发者信息 -->
    <developers>
        <developer>
            <name>ziqi studio</name>
            <email>304246984@qq.com</email>
            <organization>ziqi studio</organization>
            <organizationUrl>https://gitee.com/ziqistudio</organizationUrl>
        </developer>
    </developers>

    <!-- 必需:SCM 信息 -->
    <scm>
        <url>https://gitee.com/ziqistudio/spring-exception-i18n</url>
        <connection>scm:git:https://gitee.com/ziqistudio/spring-exception-i18n.git</connection>
        <developerConnection>scm:git:https://gitee.com/ziqistudio/spring-exception-i18n.git</developerConnection>
        <tag>v${project.version}</tag>
    </scm>

    <!-- ... 其他配置 ... -->
</project>

6.2 构建插件配置

xml 复制代码
<build>
    <plugins>
        <!-- Maven Source Plugin - 生成源码包 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-source-plugin</artifactId>
            <version>3.3.0</version>
            <executions>
                <execution>
                    <id>attach-sources</id>
                    <goals>
                        <goal>jar-no-fork</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

        <!-- Maven Javadoc Plugin - 生成文档包 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-javadoc-plugin</artifactId>
            <version>3.6.0</version>
            <configuration>
                <source>17</source>
                <encoding>UTF-8</encoding>
                <charset>UTF-8</charset>
                <docencoding>UTF-8</docencoding>
                <detectJavaApiLink>false</detectJavaApiLink>
            </configuration>
            <executions>
                <execution>
                    <id>attach-javadocs</id>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <configuration>
                        <additionalOptions>-Xdoclint:none</additionalOptions>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <!-- Maven GPG Plugin - GPG 签名 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-gpg-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
                <execution>
                    <id>sign-artifacts</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>sign</goal>
                    </goals>
                    <configuration>
                        <gpgArguments>
                            <arg>--pinentry-mode</arg>
                            <arg>loopback</arg>
                        </gpgArguments>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <!-- Central Publishing Maven Plugin - 发布到 Maven Central -->
        <plugin>
            <groupId>org.sonatype.central</groupId>
            <artifactId>central-publishing-maven-plugin</artifactId>
            <version>0.9.0</version>
            <extensions>true</extensions>
            <configuration>
                <!-- 与 settings.xml 中的 server id 保持一致 -->
                <publishingServerId>sonatype</publishingServerId>
                <checksums>required</checksums>
            </configuration>
        </plugin>
    </plugins>
</build>

6.3 发布仓库配置

xml 复制代码
<!-- 发布配置 -->
<distributionManagement>
    <!-- SNAPSHOT 仓库 -->
    <snapshotRepository>
        <id>sonatype</id>
        <url>https://central.sonatype.com/api/v1/publisher/snapshots</url>
    </snapshotRepository>
    <!-- 正式版仓库 -->
    <repository>
        <id>sonatype</id>
        <url>https://central.sonatype.com/api/v1/publisher/releases</url>
    </repository>
</distributionManagement>

7. 执行部署

7.1 部署命令

bash 复制代码
# 清理并部署(推荐)
mvn clean deploy -pl spring-boot-starter-exception-i18n

# 如果配置了 release profile
mvn clean deploy -Prelease -pl spring-boot-starter-exception-i18n

# 传入 GPG 密码(非交互式)
mvn clean deploy -Dgpg.passphrase=YOUR_PASSPHRASE -pl spring-boot-starter-exception-i18n

7.2 部署脚本示例

创建 deploy.sh

bash 复制代码
#!/bin/bash

# Maven Central 部署脚本
# 用法: ./deploy.sh [module-name]

set -e

MODULE=${1:-spring-boot-starter-exception-i18n}

echo "=========================================="
echo "  Maven Central 部署脚本"
echo "=========================================="

# 检查 GPG 是否可用
echo "检查 GPG 配置..."
gpg --list-secret-keys --keyid-format LONG

# 重新加载 GPG Agent
echo "重新加载 GPG Agent..."
gpg-connect-agent reloadagent /bye

# 执行部署
echo "开始部署模块: $MODULE"
mvn clean deploy -pl $MODULE -Dmaven.test.skip=true

echo "=========================================="
echo "  部署完成!请前往 Sonatype 确认发布"
echo "  https://central.sonatype.com/publishing"
echo "=========================================="

7.3 手动发布

部署成功后,需要在 Sonatype Central Portal 手动发布:

  1. 访问 https://central.sonatype.com/publishing
  2. 找到刚刚上传的 Deployment
  3. 等待验证通过(状态变为 Validated)
  4. 点击 Publish 发布到 Maven Central

注意 :发布后约 10-30 分钟可在 Maven Central 搜索到。


8. 常见问题与解决方案

8.1 GPG 签名失败:cannot open '/dev/tty'

问题

复制代码
gpg: cannot open '/dev/tty': Device not configured

解决方案

  1. 配置 ~/.gnupg/gpg.conf

    复制代码
    use-agent
    pinentry-mode loopback
  2. 配置 ~/.gnupg/gpg-agent.conf

    复制代码
    allow-loopback-pinentry
  3. 在 Maven GPG 插件中添加:

    xml 复制代码
    <gpgArguments>
        <arg>--pinentry-mode</arg>
        <arg>loopback</arg>
    </gpgArguments>

8.2 部署验证失败:Failed to get coordinates from pom file

问题

复制代码
Failed to get coordinates from pom file xxx.pom

解决方案

确保 POM 文件中明确包含 groupIdartifactIdversion

xml 复制代码
<groupId>io.gitee.ziqistudio</groupId>
<artifactId>spring-boot-starter-exception-i18n</artifactId>
<version>3.0.1</version>

即使子模块继承父 POM,也建议显式声明这些坐标。

8.3 缺少必需的元数据

问题

复制代码
Missing: name, description, url, scm, licenses, developers

解决方案

确保 POM 文件包含所有必需元素(见第 6.1 节)。

8.4 Javadoc 生成失败

问题

复制代码
Javadoc generation failed due to lint errors

解决方案

添加 -Xdoclint:none 参数忽略 Javadoc 警告:

xml 复制代码
<configuration>
    <additionalOptions>-Xdoclint:none</additionalOptions>
</configuration>

8.5 401 Unauthorized

问题

复制代码
Return code is: 401, ReasonPhrase: Unauthorized

解决方案

  1. 检查 settings.xml 中的 <server> 配置
  2. 确保 <id> 与 POM 中的 publishingServerId 一致
  3. 重新生成 Sonatype Token

8.6 密钥未上传到服务器

问题

复制代码
Key not found on key server

解决方案

bash 复制代码
# 上传到多个密钥服务器
gpg --keyserver keyserver.ubuntu.com --send-keys YOUR_KEY_ID
gpg --keyserver keys.openpgp.org --send-keys YOUR_KEY_ID

附录:完整项目结构示例

复制代码
spring-exception-i18n/
├── pom.xml                          # 父 POM(packaging=pom)
├── spring-boot-starter-exception-i18n/
│   ├── pom.xml                      # 子模块 POM(可发布)
│   └── src/
├── spring-exception-i18n-demo/
│   ├── pom.xml                      # 示例模块(不发布)
│   └── src/
├── deploy.sh                        # 部署脚本
└── README.md

参考链接


作者 :ziqi studio
项目地址https://gitee.com/ziqistudio/spring-exception-i18n
许可证:Apache License 2.0

相关推荐
大厂技术总监下海1 天前
在快速变化的AI世界,LangChain 如何为开发者的技术选择提供“确定性”?
开源·llm
努力犯错1 天前
Qwen-Image-2512 vs. Z-Image Turbo:5 组提示词基准测试 - 哪个模型更好?
人工智能·开源
yyt3630458411 天前
K 线图高性能窗口化渲染
前端·javascript·css·vue.js·gitee·vue
wenzhangli71 天前
ooder-right 权限插件 0.5 版本开源发布
开源
猫头虎1 天前
TextIn大模型加速器+火山引擎: 文档结构化数据处理工具扣子智能体工作流创建指南
人工智能·开源·aigc·ai编程·火山引擎·合合信息·textin
少云清1 天前
【接口测试】2_持续集成 _Git与Gitee
git·ci/cd·gitee
说私域1 天前
基于开源AI智能名片链动2+1模式商城系统的创始人个人品牌资产构建研究
人工智能·小程序·开源
是毛毛吧1 天前
AI开发工具----碾压 Bolt.new?Lovable:全栈开发的下一个“卷王”级神器深度评测
人工智能·开源·github
最贪吃的虎1 天前
深入理解Git Commit的工作原理:从对象引用到空间优化
java·前端·git·后端·spring·开源