将JAR包发布到Maven Sonatype OSSRH中央仓库

将jar包发布到Maven中央仓库(https://search.maven.org/) 供广大开发者使用,流程比较繁琐,遂成此文记录。

Maven中央仓库并不支持直接上传Jar包。因此需要将jar包发布到一些指定的第三方Maven仓库,然后该仓库再将Jar包同步到Maven中央仓库。

本文使用最简单的方式,通过发布到Sonatype OSSRH (https://central.sonatype.org/pages/ossrh-guide.html) 仓库的方式来实现。

注册JIRA账号

JIRA是一个项目管理服务,类似于国内的Teambition。Sonatype通过JIRA来管理OSSRH仓库。

注册地址:https://issues.sonatype.org/secure/Signup!default.jspa

需要填写Email, Full Name, Username以及password,其中Username与Password后面的步骤需要用到(重要)

创建issue

在发布Jar包之前,需先创建issue,Sonatype的工作人员会进行审核。

申请地址:https://issues.sonatype.org/secure/CreateIssue.jspa?issuetype=21&pid=10134

创建issue的时候需要填写下面这些信息:

  • Summary:摘要
  • Description:详细描述
  • Group Id:对应Maven的GroupId
  • Project URL:项目首页地址
  • SCM url:项目Github地址



在填写相关信息时,可以参照我之前创建的issue:https://issues.sonatype.org/browse/OSSRH-38344

由于时差问题,前一天创建issue,一般来说第二天早上才会有回应,工作人员会在回复中询问,是否拥有GroupId对应的域名所有权,

如果有的话就回复有,如果没有,建议使用github域名,如:com.github.wuwz:



当issue的status变为RESOLVED,我们就可以进行下一步操作了。

GPG配置与安装

为防止上传的Jar包被纂改,发布到Maven仓库中的所有文件都需要使用GPG签名。

安装GPG

生成GPG密钥对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
gpg --gen-key

gpg (GnuPG) 2.2.11-unknown; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: directory '/c/Users/info016/.gnupg' created
gpg: keybox '/c/Users/info016/.gnupg/pubring.kbx' created
Note: Use "gpg --full-generate-key" for a full featured key generation dialog.

GnuPG needs to construct a user ID to identify your key.

Real name: wuwenze
Email address: wenzewoo@gmail.com
You selected this USER-ID:
"wuwenze <wenzewoo@gmail.com>"

Change (N)ame, (E)mail, or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /c/Users/info016/.gnupg/trustdb.gpg: trustdb created
gpg: key D271764618CA9BBC marked as ultimately trusted
gpg: directory '/c/Users/info016/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/c/Users/info016/.gnupg/openpgp-revocs.d/AD320C934CC0DCA8C27C4407D271764618CA9BBC.rev'
public and secret key created and signed.

pub rsa2048 2019-01-24 [SC] [expires: 2021-01-23]
AD320C934CC0DCA8C27C4407D271764618CA9BBC
uid wuwenze <wenzewoo@gmail.com>
sub rsa2048 2019-01-24 [E] [expires: 2021-01-23]

生成密钥时将需要输入name、email以及password。password在之后的步骤需要用到,请记下来。

上传GPG公钥

将公钥上传到公共的密钥服务器,这样其他人才可以通过公钥来验证jar包的完整性。

1
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys AD320C934CC0DCA8C27C4407D271764618CA9BBC

其中,AD320C934CC0DCA8C27C4407D271764618CA9BBC为秘钥的ID,可以通过gpg --list-keys命令来查看:

1
2
3
4
5
6
7
8
9
10
11
gpg --list-keys
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2021-01-23
/c/Users/info016/.gnupg/pubring.kbx
-----------------------------------
pub rsa2048 2019-01-24 [SC] [expires: 2021-01-23]
AD320C934CC0DCA8C27C4407D271764618CA9BBC
uid [ultimate] wuwenze <wenzewoo@gmail.com>
sub rsa2048 2019-01-24 [E] [expires: 2021-01-23]

Maven全局setting.xml配置

注意,此处是全局的setting.xml,例如我的路径是:D:\Maven\conf\settings.xml,添加以下内容:

1
2
3
4
5
6
7
<servers>
<server>
<id>sonatype</id>
<username>注册的JIRA账号</username>
<password>注册的JIRA密码</password>
</server>
</servers>

Maven项目的pom.xml配置

根据Sonatype OSSRH的要求,以下信息都必须配置:

  • Supply Javadoc and Sources
  • Sign Files with GPG/PGP
  • Sufficient Metadata
    • Correct Coordinates
    • Project Name, Description and URL
    • License Information
    • Developer Information
    • SCM Information

配置挺多的,配置时参考我的项目,然后进行修改即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
<?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>com.wuwenze</groupId>
<artifactId>ExcelKit</artifactId>
<version>2.0.7</version>
<packaging>jar</packaging>
<name>ExcelKit</name>
<url>http://gitee.com/wuwenze/ExcelKit</url>
<description>Excel导入导出工具(简单、好用且轻量级的海量Excel文件导入导出解决方案.)</description>
<developers>
<developer>
<name>wuwenze</name>
<url>https://wuwenze.com</url>
<email>wenzewoo@gmail.com</email>
</developer>
</developers>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<scm>
<connection>scm:git:git@gitee.com:wuwenze/ExcelKit.git</connection>
<developerConnection>scm:git:git@gitee.com:wuwenze/ExcelKit.git</developerConnection>
<url>git@gitee.com:wuwenze/ExcelKit.git</url>
</scm>

<properties>
<encoding>UTF-8</encoding>
<jdk-version>1.6</jdk-version>
<poi-version>3.17</poi-version>
<dom4j-version>1.6.1</dom4j-version>
<jaxen-version>1.1.6</jaxen-version>
<xerces-version>2.11.0</xerces-version>
<guava-version>18.0</guava-version>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi-version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>${poi-version}</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j-version}</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>${jaxen-version}</version>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>${xerces-version}</version>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<target>${jdk-version}</target>
<source>${jdk-version}</source>
<encoding>${encoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>jdk-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>${jdk-version}</jdk>
</activation>
<properties>
<maven.compiler.source>${jdk-version}</maven.compiler.source>
<maven.compiler.target>${jdk-version}</maven.compiler.target>
<maven.compiler.compilerVersion>${jdk-version}</maven.compiler.compilerVersion>
</properties>
</profile>
<profile>
<id>release</id>
<build>
<plugins>
<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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
</profile>
</profiles>

</project>

Deploy Jar

前面的准备工作一切妥当后,即可执行deploy操作了,执行以下Maven命令:

1
mvn clean package deploy -Prelease



第一次执行该命令时,需要输入GPG的密码,之前配置的时候已经记录过了,然后静静的等待上传成功(这其中有很多坑,自己根据Maven报错依次解决,直到最终SUCCESS就行了,这里不表。)

Release Jar

使用JIRA账号登陆:https://oss.sonatype.org/#stagingRepositories,简短的说一下操作步骤吧:

  • 将Staging Rpositories拉到最下即可看到你刚刚发布的jar包。

  • 选择上方的Close,第一次会有工作人员回复你之前创建的那个Issue(前面有截图)。
  • 然后再点击Release即可,等2个小时左右即可在http://search.maven.org/看到你发布的jar包。

  • 注意:在流程中可能失败,这时可以点击Activity查看具体的错误原因:

Update Jar

第一次相对来说比较麻烦,以后更新jar包就比较简单了,更改pom.xml中的version,重新deploy、close、release流程即可。