概要
这段时间我在负责公司的一个开源项目,需要将该项目的jar包上传到maven中央仓库,以供客户二次开发的依赖引用。由于第一次涉及这块的知识内容,所以耗费了整整两天的时间,因此本文做一次总结,亦或给他人提供点学习资料。
废话不多说,直接上干货。
目录
一、本地环境
Windows10
Gpg3.1.1
IDEA 2018.2.5 x64
Maven 3.6.0
JDK 8
二、环境准备
1、准备SonaType 账户
如果已有账户,请跳过,如果没有,请进入SonaType注册页面注册账户。这个账户很重要,贯穿上传构件到maven中央仓库的整个流程。
在注册时,一定要记住邮箱(Email)、用户名(Username)和密码(Password),后面很多地方都用的到。注册成功后,使用注册的用户名(Username)和密码(Password)登录。
注册成功后,使用注册的用户名(Username)和密码(Password)登录,选择语言 →点击“浏览当前项目”就会跳转到首页,首页左侧显示仪表盘,右侧显示当前所有项目的活动日志。
2、准备开源项目
由于上传构件到maven中央仓库,是需要其源码开源的,因此需要提前处理好开源仓库地址。这个条件必不可少,后面会用到。至于如何将项目开源可自行百度,后期如果有时间我补一篇文章吧。
3、安装PGP
为了防止构件被他人篡改,上传到maven中央仓库的构件需要被GPG/PGP签名。
- 下载
尽量下载最新版本的Gpg4win,容易出现各种问题,我就被坑了,我下载的是gpg4win-vanilla-2.3.4.exe,deploy的时候出现各种问题,折腾的都要疯了。进入Gpg4win下载页面,找到并点击 GNUPG BINARY RELEASES 部分windows版本的Gpg4win。
点击 Gpg4win 后进入选择下载版本页面。
点击当前版本即可,进入下载页,有钱的就捐献,没钱的以后再说。
- 安装
安装这块很简单,按照提示一步步来即可。安装完成后,打开DOS窗口,输入gpg --version命令,验证gpg是否安装成功。
gpg --version
执行上述命令后,如果出现以下信息说明gpg安装成功。
- 生成密钥对
新版本的gpg4win可以使用完整版gps --full-gen-key 命令或者简洁版gps --gen-key 命令生成的密钥对,建议使用完整版命令,因为可以看到更多的密钥信息。
gpg --full-gen-key
执行上述命令后,依据提示依次输入相关信息。
2号表示加密算法,输入默认1即可。
3号表示密钥长度,输入默认2048即可
4号表示密钥有效期,输入默认0即可,表示永不过期
5号是对4号操作的确认,输入y即可
6号表示需要输入真实的名字
7号表示需要输入邮箱
8号表示对以上信息进行确认,输入o表示ok
9号是在8号输入o弹出的一个对话框,需要填写passphrase值,该值是密钥很重要,需要记住,后面deploy鉴权的时候需要用到。
最后的打印输出:
gpg: /c/Users/Administrator/.gnupg/trustdb.gpg: trustdb created
gpg: key XXXXXX1 marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 2048R/XXXXXX2 2020-06-29
Key fingerprint = XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
uid your-real-name<your-email>
sub 2048R/XXXXXX 2020-06-29
上面输出中第二行的XXXXXX1与第六行的XXXXXX2有时显示的值不一样,但是代表的是同一个key,XXXXXX1是XXXXXX2的子字符串(XXXXXX1截取了XXXXXX2末尾部分)。
当填写完后,密钥对就创建成功,在命令行输入 gpg --list-keys 即可查看创建的密钥对。
- 发布公钥
当我们向仓库deploy构件的时候,仓库会用服务器上的公钥验证上传的构件,因此我们要将上面生成的公钥传到服务器上,供验证获取。公钥服务器有以下几个:
http://pgp.mit.edu:11371
http://keyserver.ubuntu.com:11371
http://pool.sks-keyservers.net:11371
上传公钥时,一定要带上公钥服务器的端口号,我就是被这块坑了,切记切记。
执行以下命令:
gpg --keyserver hkp://pool.sks-keyservers.net:11371 --send-keys 公钥
gpg --keyserver hkp://pool.sks-keyservers.net:11371 --recv-keys 公钥
或执行命令
gpg --keyserver hkp://pgp.mit.edu:11371 --send-keys 公钥
gpg --keyserver hkp://pgp.mit.edu:11371 --recv-keys 公钥
或执行命令:
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys 公钥
gpg --keyserver hkp://keyserver.ubuntu.com:11371 --recv-keys 公钥
出现以下信息表示公钥发送成功。
三、创建Issues
1、登录SonaType
如果是第一次登录SonaType,进入页面时有个使用指引,选择“语言”→点击“浏览当前项目”就会跳转到首页。非第一次登录SonaType,会直接进入主页。SonaType首页左侧显示仪表盘,右侧显示当前所有项目的活动日志。
2、创建Issues
点击首页上方新建(对应的英文是Create)按钮,进入“创建问题”(Create Issue)界面。
说明:
项目(Project),选择Community Support - Open Source Project Repository Hosting (OSSRH)。
问题类型(Issue Type),选择 New Project。
概要(Summary),填写开源项目名称,就是要上传构件的那个项目。
描述(Description),填写开源项目描述,就是要上传构件的那个项目的项目描述。
附件(Attachment),默认即可。
Group Id,填写要上传构件的开源项目的pom文件中的项目Group Id(创建maven项目时填写的那个),注意开源项目的Group Id不能随便写,官网有要求。
大体意思:groupId是从所有项目中区分自己项目的唯一标识,与Java包的命名约定类似,它以反向方式重用域名系统。也就是说,如果你是域名的所有者或维护者,你就可以使用反向域名开头+自定义部分命名groupId。
如果该开源项目的构件已经上传过中央仓库,你可以使用之前上传的groupId。确定groupId粒度的一个好方法是使用项目结构。也就是说,如果当前项目是一个多模块项目,它应该在父项目的groupId后面追加一个新的标识符。
域名 | groupId | 备注 |
---|---|---|
www.springframework.org | org.springframework.www | |
org.springframework.xxx | xxx是自定义的名字 |
项目开源地址 | groupId | 备注 |
---|---|---|
github.com/yourusername | io.github.yourusername | yourusername是对应平台上你创建的账户名 |
gitee.com/yourusername | com.gitee.yourusername |
父项目groupId | 子模块groupId | 备注 |
---|---|---|
org.apache.maven | org.apache.maven.plugins | plugins子模块 |
org.apache.maven.reporting | reporting子模块 |
artifactId是项目本身的名称,也可以选择任何想要的名称(由小写字母和其他非特殊符号构成)。对于较长的名称,可以使用破折号分隔,如xxx-xxxxxx-xxxx。
Project URL,填写项目的开源网址地址,https://github.com/账户名/项目名
SCM url,源码的版本控制地址,https://github.com/账户名/项目名.git
Username(s),填写希望上传构件到该groupId的用户列表,用逗号分隔。
Already Synced to Central,存储库是否已经同步到中央仓库?按实际选择,工作人员需要知道是否关闭现有的同步。
当以上信息填写完毕,点击下方的创建(Create)按钮,即完成问题的创建,等待工作人员审核。
3、等待审核
点击首页的问题(Issues)按钮,在下拉菜单中的“最近的问题”选项卡可以找到刚刚新建的问题,点击该问题即可查看详情。
问题创建后,工作人员很快就会审核(几分钟),如果填写的信息没有问题,状态由“开放”变为“已解决”,相应的解决结果由“未解决”变为“已修复”。如果填写的信息有问题,工作人员会在下面留言(评论),告知哪些信息有问题,可以根据提示进行修改。
比如我填写的信息中groupId(cn.iot.xxx.xxx)写错了,因为我没有域名(iot.cn),所以我把groupId改成了com.gitee.我的gitee账户名,改完后在评论区留言告知对方。
当信息都符合要求,审核就会通过,工作人员会继续留言,让你在gitee平台上你的账户下创建一个公共仓库,验证groupId中的gitee账户是你的gitee账户,留言中公共仓库的地址已经给出,你按照要就创建即可,创建完成后留言告知工作人员即可。
工作人员通过上面创建的公共仓库,验证了你的gitee账户后,会留言告知你groupId已经准备好了,你可以进行你的操作了。特别留意最后一句话:当你成功发布第一个release版本时,记得留言告知工作人员。
四 发布构件
1、Maven配置Settings
在maven的settings配置文件中添加一个server,id可以自定义,该id在后面会用到,用户名是Sonatype的用户名,密码是Sonatype的密码。
<servers>
<server>
<id>oss</id>
<username>SonaType的用户名</username>
<password>SonaType的密码</password>
</server>
</servers>
2、开源项目配置pom
上传构件到中央仓库时,除了构件本身,还需要上传一些规定的必要信息。
- 开发者信息
<!--开发者信息 -->
<developers>
<developer>
<name>开发者名</name>
<email>开发者邮箱</email>
</developer>
</developers>
- 开源许可协议
<!-- 开源许可协议 -->
<licenses>
<license>
<name>开源协议名称</name>
<url>开源协议正文页面地址</url>
<distribution>项目发布方式:repo</distribution>
</license>
</licenses>
- 源码控制信息
<!-- 源码控制信息-->
<scm>
<connection>scm:git:git@gitee.com:账户名/开源项目名.git</connection>
<developerConnection>scm:git:git@gitee.com:账户名/开源项目名.git</developerConnection>
<url>git@gitee.com:账户名/开源项目名.git</url>
</scm>
- 构件上传地址
<!--定义snapshots库和releases库的nexus地址-->
<distributionManagement>
<snapshotRepository>
<!--oss需要对应到settings.xml下的server的id-->
<id>oss</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>oss</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
</repository>
</distributionManagement>
- 源码构建插件
<!-- 源码构建插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<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>
<executions>
<execution>
<id>attach-javadocs</id>
<!--<phase>install</phase>-->
<goals>
<goal>jar</goal>
</goals>
<configuration>
<!--<failOnError>false</failOnError>-->
<!--<doclint>none</doclint>-->
<encoding>UTF-8</encoding>
<charset>UTF-8</charset>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</execution>
</executions>
</plugin>
- 加密构建插件
<!--gpg加密插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
完整的pom文件内容详见文章末尾。
3、构建
执行构建命令构建,命令:
mvn clean deploy -P release
在构建过程中,会弹出对话框,要求输入Passphrase值,就是在生成密钥对时要求输入的那个值。
输入passphrase值后,构件构建成功,且上传成功。
4、发布
- 查看构件
登录OSS系统,用户名是注册Sonatype的用户名,密码是注册Sonatype的密码。
登录成功后,点击下图中的①,就可以看到右侧(如②)上传的构件,选中该构件,点击下方的Content(如③),逐层打开,就可以看到目录结构(如④)。此时构件的状态为open,表示只是将构件上传上来,并没有进行校验发布。
执行⑤进行校验。
等待几分钟(有的构件比较大,保证系统处理完成),刷新页面,点击close左侧的①(Refresh)按钮(一定要先刷新页面,再点击Refresh),如果验证成功,②处状态变为closed。如果状态还是open,则可点击③(Activity)事件查看失败的原因,根据原因解决问题,然后重新执行构建命令,再校验。可以看到下图校验成功,可点击④(Release)进行发布,⑤(Drop)是删除上传的构建,在校验前后(Close)、发布前后(Release)都可以执行。
执行④(Release)
等待几分钟(有的构件比较大,保证系统处理完成),刷新页面,点击close左侧的Refresh按钮,点击下方的Activity事件查看执行结果,没有报错说明发布成功!
- 通知工作人员同步构件到仓库
是否还记得创建问题后,工作人员审核通过(上面3部分)的最后,“当你成功发布第一个release版本时,记得留言告知工作人员”,所以返回SonaType,继续评论即可。
留言后,很快工作人员就会回复你:中央仓库已经激活对某某构件的同步,大约10分钟就可以了,但是2个小时左右才能在仓库中真正搜索到,因为仓库更新周期就是2小时。
过了一段时间以后,进入maven中央仓库,输入构件名称,点击查询。
即可查到上传的构件。
五 附录
完整的pom文件示例
<?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>
<artifactId>你的构件名</artifactId>
<version>版本</version>
<packaging>打包方式jar或者war</packaging>
<description>构件描述</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--spring boot依赖-->
<dependency>
...
</dependency>
</dependencies>
<!-- 开发者信息 -->
<developers>
<developer>
<name>开发者名</name>
<email>开发者邮箱</email>
</developer>
</developers>
<!-- 开源许可协议 -->
<licenses>
<license>
<name>GNU Lesser General Public License Version 3</name>
<url>http://www.gnu.org/licenses/lgpl.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<!-- 源码控制信息 -->
<scm>
<connection>scm:git:git@gitee.com:cmcc-iot-api/iot-card-open-core.git</connection>
<developerConnection>scm:git:git@gitee.com:cmcc-iot-api/iot-card-open-core.git</developerConnection>
<url>git@gitee.com:cmcc-iot-api/iot-card-open-core.git</url>
</scm>
<!--定义snapshots库和releases库的nexus地址-->
<distributionManagement>
<snapshotRepository>
<!--oss需要对应到settings.xml下的server的id-->
<id>oss</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>oss</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
</repository>
</distributionManagement>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/webapp</directory>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
<profiles>
<profile>
<!-- 本地开发环境-->
<id>dev</id>
<properties>
<profiles.active>dev</profiles.active>
</properties>
<activation>
<!-- 设置默认激活这个配置-->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<!--打包环境-->
<id>release</id>
<properties>
<profiles.active>release</profiles.active>
</properties>
<build>
<plugins>
<!--生产源码文件插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<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>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<encoding>UTF-8</encoding>
<charset>UTF-8</charset>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</execution>
</executions>
</plugin>
<!--gpg加密插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
六 资料
完成本文,参考了以下博文资料
1、https://www.cnblogs.com/wxisme/p/8728008.html