原创java开源项目发布maven全球中央仓库详细过程示范和遇到的问题解决办法

java项目上传到maven全球中央仓库(原创个人开源项目发布maven中央仓库详细过程示范)

需求背景

最近工作里写的一个缓存框架挺好用的,准备把这个缓存写成开源项目,于是将缓存相关代码脱敏提取创建新项目并开源在github LocalCache开源项目

打包好的依赖项

<dependency>
  <groupId>cn.humorchen</groupId>
  <artifactId>LocalCache</artifactId>
  <version>1.0.0-RELEASE</version>
</dependency>

第一步 注册sonatype账号

注册的账户名、项目名这些用英文,密码不要有转义符,后面别的地方会用到的,中文要出编码问题幺蛾子的。

地址:https://issues.sonatype.org/secure/Signup!default.jspa
看不懂英文的兄弟请用chrome网页翻译

账号注册之后似乎还有个邮箱认证把,有的话去邮箱里打开认证通过链接。
账号密码一定要记住了,保存好,并且最好是复杂的密码,后面还需要用到的。

第二步 登录sonatype账号并申请新建项目

地址:https://issues.sonatype.org/secure/Dashboard.jspa
在这里插入图片描述
去创建问题,地址:创建问题

如果你没看到这个新建按钮,是因为暂停了创建,要等开放,目前2024年2月20日看是没法创建的
Sonatype has begun the retirement process for issues.sonatype.org.If you have been instructed to sign up for a new account here in an e-mail from central-support@sonatype.com, you can ignore this notice.

在这里插入图片描述
项目选择:Community Support - Open Source Project Repository Hosting (OSSRH)

问题类型选择:New Project

描述:
For registering a new Group ID on OSSRH for publishing to Central
Project Summary: LocalCache(你的项目名)
Group Id:cn.humorchen(改为你的域名)
open source code git url:https://github.com/HumorChen/LocalCache(改为你的开源项目地址)

在这里插入图片描述
group id填你的域名,例如cn.humorchen,由于sonatype暂时关闭了新建,我从别的地方薅来了上面这个图,概要那个你就写你要发布个啥项目,我的是这样写的,如果你没有域名的话可以用github共用地址,io.github.xxx,这个xxx是你github的唯一名。建议还是自己有域名~
在这里插入图片描述

提交了问题之后等管理员处理,会评论你的,大概等半小时到半天不等。
在这里插入图片描述

然后管理员回复了,让我添加dns记录来认证这个域名是我的。
这个时候到你注册域名的那边去添加一个域名的text记录
比如我的是humorchen.cn这个域名,那就把humorchen.cn添加一条text记录,记录头是@,不要用www,记录值为管理员评论里说的那个值。
弄好了之后在评论区回复管理员已经弄好了,然后你在右上角流转状态,等管理员处理,管理员确认你这个域名是你的,看到那个解析记录了,就回回复你恭喜你加入中央仓库,你能发布快照和发行版构建到某个地址,我的是s01.oss.sonatype.org,地址一般不会变,我看到过的有s01,s02

在这里插入图片描述

第三步 准备个人GPG数字签名并发布到ubuntu

安装gnupg-w32-2.3.3_20211012.exe
下载地址:https://gnupg.org/ftp/gcrypt/binary/gnupg-w32-2.3.3_20211012.exe
在这里插入图片描述
安装完成后来生成个人签名,到命令行执行

gpg --gen-key

在这里插入图片描述

依次填入生成密钥需要的个人名字,我填的humorchen(输入的sonatype账号名),回车,再输入邮箱(输入你sonatype账号绑定的邮箱),回车,再让你确认,输入O,然后输入一个密码短语,这个密码短语建议额外随机生成一个(百度在线生成随机密码,生成8位以上)
在这里插入图片描述

生成好了,下面图第一个红框告诉你的是你这个密钥文件存在哪里了,第二个是个人签名的ID,要上传到ubuntu的。
在这里插入图片描述

查看当前创建好的个人签名

gpg --list-keys

把这个秘钥上传至公钥服务器,使用如下命令:

gpg --keyserver keyserver.ubuntu.com --send-keys 秘钥ID

上传命令执行没报错误完成了就是成功了,报错了啥的就再次执行,搞几次一定能成功的。

验证是否上传成功

gpg --keyserver keyserver.ubuntu.com --recv-keys 秘钥ID

(如果要把签名导入导出可以看这个博客https://blog.csdn.net/qq_39870538/article/details/127036100

第四步 准备maven配置

建议新开一个setting.xml给开源项目使用,我是单独下了一份maven,改了配置放一个文件夹去
在这里插入图片描述

我的配置如下,账号密码部分自己修改为自己的!

<?xml version="1.0" encoding="UTF-8"?>

<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
-->

<!--
 | This is the configuration file for Maven. It can be specified at two levels:
 |
 |  1. User Level. This settings.xml file provides configuration for a single user,
 |                 and is normally provided in ${user.home}/.m2/settings.xml.
 |
 |                 NOTE: This location can be overridden with the CLI option:
 |
 |                 -s /path/to/user/settings.xml
 |
 |  2. Global Level. This settings.xml file provides configuration for all Maven
 |                 users on a machine (assuming they're all using the same Maven
 |                 installation). It's normally provided in
 |                 ${maven.conf}/settings.xml.
 |
 |                 NOTE: This location can be overridden with the CLI option:
 |
 |                 -gs /path/to/global/settings.xml
 |
 | The sections in this sample file are intended to give you a running start at
 | getting the most out of your Maven installation. Where appropriate, the default
 | values (values used when the setting is not specified) are provided.
 |
 |-->
<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">
  <!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   |
   | Default: ${user.home}/.m2/repository
  <localRepository>/path/to/local/repo</localRepository>
  -->

  <!-- interactiveMode
   | This will determine whether maven prompts you when it needs input. If set to false,
   | maven will use a sensible default value, perhaps based on some other setting, for
   | the parameter in question.
   |
   | Default: true
  <interactiveMode>true</interactiveMode>
  -->

  <!-- offline
   | Determines whether maven should attempt to connect to the network when executing a build.
   | This will have an effect on artifact downloads, artifact deployment, and others.
   |
   | Default: false
  <offline>false</offline>
  -->

  <!-- pluginGroups
   | This is a list of additional group identifiers that will be searched when resolving plugins by their prefix, i.e.
   | when invoking a command line like "mvn prefix:goal". Maven will automatically add the group identifiers
   | "org.apache.maven.plugins" and "org.codehaus.mojo" if these are not already contained in the list.
   |-->
  <pluginGroups>
    <!-- pluginGroup
     | Specifies a further group identifier to use for plugin lookup.
    <pluginGroup>com.your.plugins</pluginGroup>
    -->
  </pluginGroups>

  <!-- TODO Since when can proxies be selected as depicted? -->
  <!-- proxies
   | This is a list of proxies which can be used on this machine to connect to the network.
   | Unless otherwise specified (by system property or command-line switch), the first proxy
   | specification in this list marked as active will be used.
   |-->
  <proxies>
    <!-- proxy
     | Specification for one proxy, to be used in connecting to the network.
     |
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>proxyuser</username>
      <password>proxypass</password>
      <host>proxy.host.net</host>
      <port>80</port>
      <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
    </proxy>
    -->
  </proxies>

  <!-- servers
   | This is a list of authentication profiles, keyed by the server-id used within the system.
   | Authentication profiles can be used whenever maven must make a connection to a remote server.
   |-->
  <servers>
    <!-- server
     | Specifies the authentication information to use when connecting to a particular server, identified by
     | a unique name within the system (referred to by the 'id' attribute below).
     |
     | NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are
     |       used together.
     |
    <server>
      <id>deploymentRepo</id>
      <username>repouser</username>
      <password>repopwd</password>
    </server>
    -->

    <!-- Another sample, using keys to authenticate.
    <server>
      <id>siteServer</id>
      <privateKey>/path/to/private/key</privateKey>
      <passphrase>optional; leave empty if not used.</passphrase>
    </server>
    -->

    <server>
      <id>ossrh</id>
      <username>你的sonatype账号</username>
      <password>你的sonatype密码</password>
    </server>
  </servers>

  <!-- mirrors
   | This is a list of mirrors to be used in downloading artifacts from remote repositories.
   |
   | It works like this: a POM may declare a repository to use in resolving certain artifacts.
   | However, this repository may have problems with heavy traffic at times, so people have mirrored
   | it to several places.
   |
   | That repository definition will have a unique id, so we can create a mirror reference for that
   | repository, to be used as an alternate download site. The mirror site will be the preferred
   | server for that repository.
   |-->
  <mirrors>
    <!-- mirror
     | Specifies a repository mirror site to use instead of a given repository. The repository that
     | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
     | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
     |
    <mirror>
      <id>mirrorId</id>
      <mirrorOf>repositoryId</mirrorOf>
      <name>Human Readable Name for this Mirror.</name>
      <url>http://my.repository.com/repo/path</url>
    </mirror>
     -->
    <!-- 阿里仓库 -->
    <mirror>
      <id>aliyunmaven</id>
      <mirrorOf>*</mirrorOf>
      <name>阿里云公共仓库</name>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
    <!-- 中央仓库1 -->
    <mirror>
      <id>repo1</id>
      <mirrorOf>central</mirrorOf>
      <name>Human Readable Name for this Mirror.</name>
      <url>https://repo1.maven.org/maven2/</url>
    </mirror>

    <!-- 中央仓库2 -->
    <mirror>
      <id>repo2</id>
      <mirrorOf>central</mirrorOf>
      <name>Human Readable Name for this Mirror.</name>
      <url>https://repo2.maven.org/maven2/</url>
    </mirror>


  </mirrors>

  <!-- profiles
   | This is a list of profiles which can be activated in a variety of ways, and which can modify
   | the build process. Profiles provided in the settings.xml are intended to provide local machine-
   | specific paths and repository locations which allow the build to work in the local environment.
   |
   | For example, if you have an integration testing plugin - like cactus - that needs to know where
   | your Tomcat instance is installed, you can provide a variable here such that the variable is
   | dereferenced during the build process to configure the cactus plugin.
   |
   | As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles
   | section of this document (settings.xml) - will be discussed later. Another way essentially
   | relies on the detection of a property, either matching a particular value for the property,
   | or merely testing its existence. Profiles can also be activated by JDK version prefix, where a
   | value of '1.4' might activate a profile when the build is executed on a JDK version of '1.4.2_07'.
   | Finally, the list of active profiles can be specified directly from the command line.
   |
   | NOTE: For profiles defined in the settings.xml, you are restricted to specifying only artifact
   |       repositories, plugin repositories, and free-form properties to be used as configuration
   |       variables for plugins in the POM.
   |
   |-->
  <profiles>
    <!-- profile
     | Specifies a set of introductions to the build process, to be activated using one or more of the
     | mechanisms described above. For inheritance purposes, and to activate profiles via <activatedProfiles/>
     | or the command line, profiles have to have an ID that is unique.
     |
     | An encouraged best practice for profile identification is to use a consistent naming convention
     | for profiles, such as 'env-dev', 'env-test', 'env-production', 'user-jdcasey', 'user-brett', etc.
     | This will make it more intuitive to understand what the set of introduced profiles is attempting
     | to accomplish, particularly when you only have a list of profile id's for debug.
     |
     | This profile example uses the JDK version to trigger activation, and provides a JDK-specific repo.
    <profile>
      <id>jdk-1.4</id>

      <activation>
        <jdk>1.4</jdk>
      </activation>

      <repositories>
        <repository>
          <id>jdk14</id>
          <name>Repository for JDK 1.4 builds</name>
          <url>http://www.myhost.com/maven/jdk14</url>
          <layout>default</layout>
          <snapshotPolicy>always</snapshotPolicy>
        </repository>
      </repositories>
    </profile>
    -->

    <!--
     | Here is another profile, activated by the property 'target-env' with a value of 'dev', which
     | provides a specific path to the Tomcat instance. To use this, your plugin configuration might
     | hypothetically look like:
     |
     | ...
     | <plugin>
     |   <groupId>org.myco.myplugins</groupId>
     |   <artifactId>myplugin</artifactId>
     |
     |   <configuration>
     |     <tomcatLocation>${tomcatPath}</tomcatLocation>
     |   </configuration>
     | </plugin>
     | ...
     |
     | NOTE: If you just wanted to inject this configuration whenever someone set 'target-env' to
     |       anything, you could just leave off the <value/> inside the activation-property.
     |
    <profile>
      <id>env-dev</id>

      <activation>
        <property>
          <name>target-env</name>
          <value>dev</value>
        </property>
      </activation>

      <properties>
        <tomcatPath>/path/to/tomcat/instance</tomcatPath>
      </properties>
    </profile>
    -->
  </profiles>

  <!-- activeProfiles
   | List of profiles that are active for all builds.
   |
  <activeProfiles>
    <activeProfile>alwaysActiveProfile</activeProfile>
    <activeProfile>anotherAlwaysActiveProfile</activeProfile>
  </activeProfiles>
  -->
</settings>

然后到IDEA这个开源项目配置里修改项目使用的maven配置文件为指定文件,指定使用这个文件。

第五步 修改项目配置

项目需要支持javadoc、maven打包、source源码包、gpg对打包的文件签名

我的配置如下,看配置中文标注或带xxx部分,主要是配置gpg信息、licenses开源协议、scm开源项目仓库、distributionManagement 中央仓库(打包的构建发布到这)、build plugins(构建插件)

<?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>
    <groupId>cn.humorchen</groupId>
    <artifactId>LocalCache</artifactId>
    <name>LocalCache</name>
    <version>1.0.0-RELEASE</version>
    <description>
        一个安全好用的springboot项目本地方法缓存,基于最高效的caffeine框架。
    </description>
    <url>https://github.com/HumorChen/LocalCache(改为你的开源项目地址)</url>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.7.6</spring-boot.version>
        <lombok.version>1.18.6</lombok.version>
        <slf4j-api.version>1.7.7</slf4j-api.version>
        <fastjson.version>1.2.75</fastjson.version>
        <aspectjweaver.version>1.9.5</aspectjweaver.version>
        <hutool.version>5.7.13</hutool.version>
        <gpg.passphrase>你创建签名时输的密码passphrase</gpg.passphrase>
        <gpg.keyname>你创建签名时的ID 4D368E64007Fxxxxxxxxxxxxxxxx6337CEFB1B5</gpg.keyname>
        <gpg.homedir>你创建签名时的日志里有路径 D:\user\xxxxxxx\Application Data\gnupg</gpg.homedir>
    </properties>
    <licenses>
        <license>
            <name>MIT License</name>
            <url>https://github.com/HumorChen/LocalCache/blob/master/LICENSE(你的开源协议声明地址,或者你也可以直接在这指定开源协议名)</url>
            <distribution>repo</distribution>
        </license>
    </licenses>
    <scm>
        <tag>master</tag>
        <url>https://github.com/HumorChen/LocalCache</url>
        <connection>scm:git:git@github.com:HumorChen/LocalCache.git</connection>
        <developerConnection>scm:git:git@github.com:HumorChen/LocalCache.git</developerConnection>
    </scm>

    <!-- 中央仓库地址配置,不需要修改 -->
    <distributionManagement>
        <snapshotRepository>
            <id>ossrh</id>
            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
        </snapshotRepository>

        <repository>
            <id>ossrh</id>
            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
        </repository>
    </distributionManagement>
    <developers>
        <developer>
            <name>humorchen</name>
            <email>humorchen99@gmail.com</email>
            <organization>cn.humorchen</organization>
        </developer>
    </developers>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>15.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--        hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        <!--        caffeine-->
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>2.8.0</version>
        </dependency>
        <!--        lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
        <!--        slf4j-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j-api.version}</version>
        </dependency>
        <!--        fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
        <!--        aspectj-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectjweaver.version}</version>
        </dependency>
        <!--        junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.example.demo.DemoApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- 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.10.4</version>
                <configuration>
                    <additionalJOptions>
                        <additionalJOption>-Xdoclint:none</additionalJOption>
                    </additionalJOptions>
                </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>3.1.0</version>
                <configuration>
                    <gpgArguments>
                        <arg>--pinentry-mode</arg>
                        <arg>loopback</arg>
                    </gpgArguments>
                </configuration>
                <executions>
                    <execution>
                        <id>sign-artifacts</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>sign</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

第七步 发布项目

发布过程中如果遇到乱码请看我这个博客,我遇到了的。https://humorchen.blog.csdn.net/article/details/136172570

在IDEA里选择Maven的deploy部署
在这里插入图片描述
发布成功
在这里插入图片描述

第八步 进nexus仓库发布出去

地址: https://s01.oss.sonatype.org/?spm=a2c6h.12873639.article-detail.10.60a1309ckig47M#stagingRepositories

点击右上角的Log In登录你的sonatype账号,再一次点开你的项目构件仓库,点击下图里2号这个仓库,然后点上面的close,输入描述,然后确认,于是系统校验你的项目。
等到最后活动进度最后一行显示All rules passed: Central Sync Requirement就说明校验通过,可以发布了。

如果过程正按钮是灰色,或者不能点击,重复刷新等待就行(有可能是网络等其他原因)。然后重复上面步骤。即可

校验通过后再点击上面的release按钮即可发布到中央仓库了。

完成后,大约过个2-4个小时,你就可以在https://search.maven.org/找到你的发布的项目了!
在这里插入图片描述

我这报错了,第一个是丢了url标签,pom.xml里加上了,第二个是签名校验失败,当时设置的密码忘了,导致pom文件里填的那个密码不对,校验失败,重新签名填对之后正常了。

    <url>https://github.com/HumorChen/LocalCache</url>

在这里插入图片描述
所有检查通过,点击上门的Release发布出去
在这里插入图片描述
在这里插入图片描述
发布后已经能在这搜到了,在其他项目maven引入也能正常下载到了,过几个小时之后就能在https://search.maven.org/搜索到
在这里插入图片描述

遇到过的问题

  1. 域名解析没有
    要添加@.humorchen.cn 值为评论区的那个值,dns类型选text
  2. maven导入依赖失败
    请检查你项目IDEA的maven配置,用国内阿里云仓库是能获取到这些依赖的,外网的速度慢,还可能失败。
  3. 打包javadoc乱码
    看我乱码解决办法的博客https://humorchen.blog.csdn.net/article/details/136172570
  4. 打包的时候GPG提示没有可用签名
    是因为的创建签名的时候用的git bash,导致创建的签名在那个用户下,目录不对,后面用cmd创建的签名是正常可用的,你在idea里的cmd打开查看已经创建好的签名能看到证明是对的,是可以的。
  5. 打包提示401未授权
    检查项目是否使用了我说的自定义maven setting,xml,你是否修改了密码但是setting.xml未修改,密码是否有转义符,有的话建议改密码。
posted @ 2024-02-20 11:02  HumorChen99  阅读(16)  评论(0编辑  收藏  举报  来源