mvn 命令上传文件到 Maven 仓库
针对一个 Maven 的 Java 项目,我们执行 mvn deploy 命令时想要把生成的 jar 包上传到 Maven 仓库(本文将使用私有的 Nexus 仓库)中去。所要用到的插件 Maven Deploy Plugin ,本文实际就是讲述如何用该插件上传 jar 包到 Maven 仓库,更多用法请参考该插件的官方文档。
本文关键性的两个配置文件是 pom.xml 和 settings.xml。前者配置仓库的地址,后者中配置用户名和密码。要确定 Maven 使用了哪个 settings.xml 文件,用 mvn -X
查看,比如下面的输出
[DEBUG] Reading global settings from /usr/local/Cellar/maven/3.8.3/libexec/conf/settings.xml [DEBUG] Reading user settings from /Users/yanbin/.m2/settings.xml
Maven 还允许在执行 mvn 命令时用 -s 或 --settings 参数指定 settings.xml 文件,如 mvn deploy --settings setting.xml
所以对于 settings.xml 文件的修改,可修改全局的,用户的或参数 --settings 指定的。
来一个实际的应用场景,假如我们要上传 jar 包(根据是否为 SNAPSHOT 包) 到下方相应的仓库中
- https://nexus.example.com/repository/maven-releases: release 包,即版本号不是 *-SNAPSHOT
- https://nexus.example.com/repository/maven-snapshots: snapshot 包,即版本号为 *-SNAPSHOT
瞧瞧可采用的几种方式
基本的操作方式
下面是一个完整的 pom.xml 文件
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>blog.yanbin</groupId> <artifactId>kafka-common</artifactId> <version>1.0.0-SNAPSHOT</version> <name>kafka-common</name> <distributionManagement> <repository> <id>private-release</id> <url>http://nexus.example.com/repository/maven-releases</url> </repository> <snapshotRepository> <id>private-snapshot</id> <url>http://nexus.example.com/repository/maven-snapshots</url> </snapshotRepository> </distributionManagement> </project>
< project xmlns : xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns = "http://maven.apache.org/POM/4.0.0" xsi : schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" > < modelVersion > 4.0.0 < / modelVersion > < groupId > blog . yanbin < / groupId > < artifactId > kafka - common < / artifactId > < version > 1.0.0 - SNAPSHOT < / version > < name > kafka - common < / name > < distributionManagement > < repository > < id > private - release < / id > < url > http : //nexus.example.com/repository/maven-releases</url> < / repository > < snapshotRepository > < id > private - snapshot < / id > < url > http : //nexus.example.com/repository/maven-snapshots</url> < / snapshotRepository > < / distributionManagement > < / project > |
由于 version 是 1.0.0-SNAPSHOT,所以将会部署到 distributionManagement/snapshotRepository 指示的仓库中,该仓库的 id 是 private-snapshot。如果我们执行 mvn deploy,Maven 将从 settings.xml 中找到该 id 对应的用户名和密码。因此我们须在 setting.xml 文件中预先配置
假如我们修改用户的 settings.xml 文件 ~/.m2/setting.xml
<?xml version="1.0"?> <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> <server> <id>private-snapshot</id> <username>admin</username> <password>admin123</password> </server> </servers> </settings>
<? xml version = "1.0" ?> < 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 > < server > < id > private - snapshot < / id > < username > admin < / username > < password > admin123 < / password > < / server > < / servers > < / settings > |
现在我们来执行 mvn deploy, 这里跳过 test 和 install 这两步
$ mvn deploy -Dmaven.test.skip -Dmaven.install.skip ...... [INFO] --- maven-deploy-plugin:2.7:deploy (default-deploy) @ kafka-common --- Downloading from private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml Downloaded from private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml (773 B at 4.0 kB/s) Uploading to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.jar Uploaded to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.jar (1.9 kB at 13 kB/s) Uploading to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.pom Uploaded to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.pom (1.2 kB at 1.9 kB/s) Downloading from private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml Downloaded from private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml (283 B at 2.5 kB/s) Uploading to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml Uploaded to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml (773 B at 4.9 kB/s) Uploading to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml Uploaded to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml (283 B at 2.6 kB/s) [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ ......
$ mvn deploy - Dmaven . test . skip - Dmaven . install . skip . . . . . . [ INFO ] -- - maven - deploy - plugin : 2.7 : deploy ( default - deploy ) @ kafka - common -- - Downloading from private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml Downloaded from private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml (773 B at 4.0 kB/s) Uploading to private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.jar Uploaded to private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.jar (1.9 kB at 13 kB/s) Uploading to private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.pom Uploaded to private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.pom (1.2 kB at 1.9 kB/s) Downloading from private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml Downloaded from private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml (283 B at 2.5 kB/s) Uploading to private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml Uploaded to private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml (773 B at 4.9 kB/s) Uploading to private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml Uploaded to private - snapshot : http : //nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml (283 B at 2.6 kB/s) [ INFO ] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- [ INFO ] BUILD SUCCESS [ INFO ] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . |
上传成功了,如果 version 不是 *-SNAPSHOT, 比如为 1.0.0
, 它将会上传到 id 为 private-release
仓库,在 ~/.m2/settings.xml
就要有对应 id 为 private-release
的 <server>
来配置用户和密码。
还可以其他多种传入用户名密码的方式
通过系统属性传入帐号信息
配置 ~/.m2/settings.xml
的 <server>
<servers> <server> <id>private-snapshot</id> <username>${CI_USERNAME}</username> <password>${CI_PASSWORD}</password> </server> </servers>
< servers > < server > < id > private - snapshot < / id > < username > $ { CI_USERNAME } < / username > < password > $ { CI_PASSWORD } < / password > < / server > < / servers > |
mvn 命令为
$ mvn deploy -DCI_USERNAME=admin -DCI_PASSWORD=admin123
通过环境变量传入帐号信息
配置 ~/.m2/settings.xml
的 <server>
<server> <id>private-snapshot</id> <username>${env.CI_USERNAME}</username> <password>${env.CI_PASSWORD}</password> </server>
< server > < id > private - snapshot < / id > < username > $ { env . CI_USERNAME } < / username > < password > $ { env . CI_PASSWORD } < / password > < / server > |
执行 mvn 命令前必须设置相应的环境变量
$ export CI_USERNAME=admin $ export CI_PASSWORD=admin123 $ mvn deploy
配置用户名密码到 url 中
这种方式我们用不着 settings.xml
文件,测试前可把 settings.xml
文件删除。只需修改 pom.xml
文件, 给 distributionManagement 中的 <url> 中配置上用户名和密码
<distributionManagement> <repository> <id>private-release</id> <url>http://admin:admin123@nexus.example.com/repository/maven-releases</url> </repository> <snapshotRepository> <id>private-snapshot</id> <url>http://admin:admin123@nexus.example.com/repository/maven-snapshots</url> </snapshotRepository> </distributionManagement>
< distributionManagement > < repository > < id > private - release < / id > < url > http : //admin:admin123@nexus.example.com/repository/maven-releases</url> < / repository > < snapshotRepository > < id > private - snapshot < / id > < url > http : //admin:admin123@nexus.example.com/repository/maven-snapshots</url> < / snapshotRepository > < / distributionManagement > |
然后执行 mvn deploy
即能成功上传 jar 包。这种配置方式肯定不安全,绝对不应该把密码放到项目文件中去的,所以千万别采用。
直接上传一个 jar 文件
有时候拿到的是一个别人的 jar,没有源文件,想把它直接上传到 Maven 仓库中去供其它 Java 项目享用, 这时候我们要用到的命令是 mvn deploy:deploy-file。当然登陆 nexus Web 控制台手工上传也行,本文主要讲 mvn deploy 的使用。
回顾一下用 twine 把一个 Python 的 whl 包上传到 nexus 上的方式
twine upload --repository-url=https://nexus.example.com/repository/pypi-hosted/ dist/bounded_executor-0.0.3-py3-none-any.whl
直接上传一个 jar 文件与针对 Maven 项目执行 mvn deploy
并无多大区别,唯一不同的是 Maven 项目有一个 pom.xml 文件,在其中有 groupId, artifactId, version 等的描述,而使用 mvn deploy:deploy-file
的话就要在命令中给出相同的信息。 mvn deploy:deploy-file
也能用 -DpomFile
指定一个 pom.xml 文件, 如果该 jar 有传递的依赖也许是有必要用这个参数。
应用 settings.xml 的帐号信息
执行 deploy:deploy-file 依旧可以用 settings.xml 文件,配置方式与前面三种方式是一样的,帐户信息可明文配置,或从系统属性或环境变量中来。假如 jar 包文件名是 redis-common-1.0.0-SNAPSHOT.jar, ~/.m2/settings.xml
中配置的 server
<servers> <server> <id>private-snapshot</id> <username>${CI_USERNAME}</username> <password>${CI_PASSWORD}</password> </server> </servers>
< servers > < server > < id > private - snapshot < / id > < username > $ { CI_USERNAME } < / username > < password > $ { CI_PASSWORD } < / password > < / server > < / servers > |
上传该 jar 包到私有仓库的命令是
mvn deploy:deploy-file -DCI_USERNAME=admin -DCI_PASSWORD=admin123 \ -DgroupId=blog.yanbin.redis -DartifactId=redis-common -Dversion=1.0.0-SNAPSHOT -Dpackaing=jar \ -DrepositoryId=private-snapshot \ -Durl=http://nexus.example.com/repository/maven-snapshots \ -Dfile=redis-common-1.0.0-SNAPSHOT.jar
无需 settings.xml 文件
也可以完全不用 settings.xml 文件,而在 mvn 命令中的 URL 中带上用户名和密码。测试下面的命令前把 ~/.m2/settings.xml
文件先删除
mvn deploy:deploy-file \ -DgroupId=blog.yanbin.redis -DartifactId=redis-common -Dversion=1.0.0-SNAPSHOT -Dpackaing=jar \ -Durl=http://admin:admin123@nexus.example.com/repository/maven-snapshots \ -Dfile=redis-common-1.0.0-SNAPSHOT.jar
这种方式对于临时把一个 jar 包上传到私有仓库更快捷,反正是本机执行,不应有什么安全隐患。此时如果使用 settings.xml 配置了用户名和密码,那么 -Durl 中的用户名和密码将被忽略。
和任何 bash 命令一样,密码中带有特殊符号的要注意转义,比如密码是 aB!ak47%^
,在 mvn deploy:deploy-file 命令的 -Durl 写成
-Durl=http://admin:aB!ak47%^@nexus.example.com/repository/maven-snapshots
在 zsh 中将会看到
zsh: event not found: ak47
在 bash 中看到的是
bash: !ak47%^@nexus.example.com/repository/maven-snapshots: event not found
原因是感叹号 !
在 zsh 和 bash 中是唤起一个历史命令,如 !ak47
是从历史命令中查找一个以 ak47
开头的命令,没有的话就是 event not found
.
所以我们必须对感叹号进行转义,在它前头加上反斜杠,完整的 mvn deploy:deploy-file 命令是
mvn deploy:deploy-file \ -DgroupId=blog.yanbin.redis -DartifactId=redis-common -Dversion=1.0.0-SNAPSHOT -Dpackaing=jar \ -Durl=http://admin:aB\!ak47%^@nexus.example.com/repository/maven-snapshots \ -Dfile=redis-common-1.0.0-SNAPSHOT.jar
实际的密码 aB!ak47%^
被转义为 aB\!ak47%^
。
如果把这个 mvn deploy:deploy-file 命令写到一个 deploy.sh
文件中的话,转义又多余了,其中 -Durl 部分写成 -Durl=http://admin: aB!ak47%^ @nexus.... ,然后用 sh deploy.sh
执行也不会有问题。
Maven effective-settings 插件
该插件能显示出 Maven 用到的 settings 信息,包括其中配置的用户名密码
$ mvn help:effective-settings -DshowPasswords=true