利用aether api实现从指定maven仓库下载jar包
最近公司做项目遇到一个需求,通过用户提供的groupId和artifactId以及version到指定maven库中下载jar包。平时的maven项目中,依赖的jar包都是通过pom文件设置,然后maven通过<dependency></dependency>去下载jar包,现在要做的就是maven下载的这一功能。
通过上网去查阅,知道了可以在命令行利用mvn dependency:copy -Dartifact=groupId:artifactId:version -DoutputDirectory=? -Dmdep.stripVerison=true的命令下载到本地仓库。但是有一个问题,利用mvn可能涉及到maven环境的问题,这样程序移植的时候会有很多问题。最好是由一个api借口,以jar包的形式引入,完全脱离本地的maven环境。
这个问题在网上搜索了好久,终于利用google找到了答案。它就是Aether。官方网址是http://wiki.eclipse.org/Aether 上面有相关的说明和API 文档。下面就来说一说具体的实现流程。
依据官方文档,首先应引入jar包,创建一个maven项目,在pom文件中添加如下依赖:
<properties> <aetherVersion>1.0.0.v20140518</aetherVersion> <mavenVersion>3.1.0</mavenVersion> <wagonVersion>1.0</wagonVersion> </properties> <dependencies> <dependency> <groupId>org.eclipse.aether</groupId> <artifactId>aether-api</artifactId> <version>${aetherVersion}</version> </dependency> <dependency> <groupId>org.eclipse.aether</groupId> <artifactId>aether-util</artifactId> <version>${aetherVersion}</version> </dependency> <dependency> <groupId>org.eclipse.aether</groupId> <artifactId>aether-impl</artifactId> <version>${aetherVersion}</version> </dependency> <dependency> <groupId>org.eclipse.aether</groupId> <artifactId>aether-connector-basic</artifactId> <version>${aetherVersion}</version> </dependency> <dependency> <groupId>org.eclipse.aether</groupId> <artifactId>aether-transport-file</artifactId> <version>${aetherVersion}</version> </dependency> <dependency> <groupId>org.eclipse.aether</groupId> <artifactId>aether-transport-http</artifactId> <version>${aetherVersion}</version> </dependency> <dependency> <groupId>org.eclipse.aether</groupId> <artifactId>aether-transport-wagon</artifactId> <version>${aetherVersion}</version> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-aether-provider</artifactId> <version>${mavenVersion}</version> </dependency> <dependency> <groupId>org.apache.maven.wagon</groupId> <artifactId>wagon-ssh</artifactId> <version>${wagonVersion}</version> </dependency> </dependencies>
然后建立RepositorySystem,这个是用来操作maven仓库的主要接口:
/** * 建立RepositorySystem * @return RepositorySystem */ private static RepositorySystem newRepositorySystem() { DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); locator.addService( RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class ); locator.addService( TransporterFactory.class, FileTransporterFactory.class ); locator.addService( TransporterFactory.class, HttpTransporterFactory.class ); return locator.getService( RepositorySystem.class ); }
然后建立RepositorySystemSession对象:
/** * create a repository system session * @param system RepositorySystem * @return RepositorySystemSession */ private static RepositorySystemSession newSession( RepositorySystem system,String target ) { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); LocalRepository localRepo = new LocalRepository( /*"target/local-repo" */target); session.setLocalRepositoryManager( system.newLocalRepositoryManager( session, localRepo ) ); return session; }
接下来实现的是从指定maven仓库下载指定的jar包:
/** * 从指定maven地址下载指定jar包 * @param artifact maven-jar包的三围定位(groupId:artifactId:version) * @param repositoryURL maven库的URL地址 * @param username 若需要权限,则需使用此参数添加用户名,否则设为null * @param password 同上 * @throws ArtifactResolutionException */ public static void DownLoad(Params params) throws ArtifactResolutionException { String groupId=params.getGroupId(); String artifactId=params.getArtifactId(); String version=params.getVersion(); String repositoryUrl=params.getRepository(); String target=params.getTarget(); String username=params.getUsername(); String password=params.getPassword(); RepositorySystem repoSystem = newRepositorySystem(); RepositorySystemSession session = newSession( repoSystem ,target); RemoteRepository central=null; if(username==null&&password==null) { central = new RemoteRepository.Builder( "central", "default", repositoryUrl ).build(); }else{ Authentication authentication=new AuthenticationBuilder().addUsername(username).addPassword(password).build(); central = new RemoteRepository.Builder( "central", "default", repositoryUrl ).setAuthentication(authentication).build(); } /** * 下载一个jar包 */ Artifact artifact=new DefaultArtifact(groupId+":"+artifactId+":"+version); ArtifactRequest artifactRequest=new ArtifactRequest(); artifactRequest.addRepository(central); artifactRequest.setArtifact(artifact); repoSystem.resolveArtifact(session, artifactRequest); System.out.println("success"); /** * 下载该jar包及其所有依赖jar包 */ /* * Dependency dependency = new Dependency( new DefaultArtifact( artifact ),null); CollectRequest collectRequest = new CollectRequest(); collectRequest.setRoot( dependency ); collectRequest.addRepository( central ); DependencyNode node = repoSystem.collectDependencies( session, collectRequest ).getRoot(); DependencyRequest dependencyRequest = new DependencyRequest(); dependencyRequest.setRoot( node ); repoSystem.resolveDependencies( session, dependencyRequest ); PreorderNodeListGenerator nlg = new PreorderNodeListGenerator(); node.accept( nlg ); System.out.println( nlg.getClassPath() );*/ } }
其中Params对象是相关的一些参数,包括groupId,artifactId,version,远程maven仓库的URL地址repository,下载后存放的路径target,访问maven仓库的username和password:
public class Params { /** * jar包在maven仓库中的groupId */ private String groupId; /** * jar包在maven仓库中的artifactId */ private String artifactId; /** * jar包在maven仓库中的version */ private String version; /** * 远程maven仓库的URL地址,默认使用bw30的远程maven-public库 */ private String repository="http://ae.mvn.bw30.com/repository/maven-public/"; /** * 下载的jar包存放的目标地址,默认为./target/repo */ private String target="temp"; /** * 登录远程maven仓库的用户名,若远程仓库不需要权限,设为null,默认为null */ private String username=null; /** * 登录远程maven仓库的密码,若远程仓库不需要权限,设为null,默认为null */ private String password=null; public Params() { super(); } public Params(String groupId, String artifactId) { super(); this.groupId = groupId; this.artifactId = artifactId; } public Params(String groupId, String artifactId, String username, String password) { super(); this.groupId = groupId; this.artifactId = artifactId; this.username = username; this.password = password; } public Params(String groupId, String artifactId, String version, String repository, /*String target,*/ String username, String password) { super(); this.groupId = groupId; this.artifactId = artifactId; this.version = version; this.repository = repository; /*this.target = target;*/ this.username = username; this.password = password; } public Params(String groupId, String artifactId, String version, String username, String password) { super(); this.groupId = groupId; this.artifactId = artifactId; this.version = version; this.username = username; this.password = password; } public String getGroupId() { return groupId; } public void setGroupId(String groupId) { this.groupId = groupId; } public String getArtifactId() { return artifactId; } public void setArtifactId(String artifactId) { this.artifactId = artifactId; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getRepository() { return repository; } public void setRepository(String repository) { this.repository = repository; } public String getTarget() { return target; } /*public void setTarget(String target) { this.target = target; }*/ public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
上面是根据三围来下载jar包,但是jar包的版本会有很多,所以有如下需求:给定groupId和artifactId,列出所有的version,用户选择某一version后再利用上面的方法下载,那么怎么列出所有的version呢?Aether API给出了一些借口,稍加组合即可:
/** * 根据groupId和artifactId获取所有版本列表 * @param params Params对象,包括基本信息 * @return version列表 * @throws VersionRangeResolutionException */ public static List<Version> getAllVersions(Params params) throws VersionRangeResolutionException { String groupId=params.getGroupId(); String artifactId=params.getArtifactId(); String repositoryUrl=params.getRepository(); String target=params.getTarget(); String username=params.getUsername(); String password=params.getPassword(); RepositorySystem repoSystem = newRepositorySystem(); RepositorySystemSession session = newSession( repoSystem ,target); RemoteRepository central=null; if(username==null&&password==null) { central = new RemoteRepository.Builder( "central", "default", repositoryUrl ).build(); }else{ Authentication authentication=new AuthenticationBuilder().addUsername(username).addPassword(password).build(); central = new RemoteRepository.Builder( "central", "default", repositoryUrl ).setAuthentication(authentication).build(); } Artifact artifact = new DefaultArtifact( groupId+":"+artifactId+":[0,)" ); VersionRangeRequest rangeRequest = new VersionRangeRequest(); rangeRequest.setArtifact( artifact ); rangeRequest.addRepository( central ); VersionRangeResult rangeResult = repoSystem.resolveVersionRange( session, rangeRequest ); List<Version> versions = rangeResult.getVersions(); System.out.println( "Available versions " + versions ); return versions; }
在这里面最令人恶心的是由于之前是三围坐标,创建Artifact对象的时候传进去groupId:artifactId:verison的字符串就行了,现在没有verison了,找了好久的API都是必带verison的,甚至试了一下通配符也不成。后来找到了官方的example的源码,才发现原来是用[0,)来表示所有的verison,就是数学中的0到正无穷呀,想改成啥区间的version都可以了。
后面的需求就是解压下载下来的jar包,然后将其中的js文件夹再压缩供用户下载引用,压缩、解压的方法网上好多,就不再说明了。
另外,Aether官方提供的示例代码还实现很多其他的功能,有需要的可以下载来参考。
示例代码官方git地址:git://git.eclipse.org/gitroot/aether/aether-demo.git 或
ssh://git.eclipse.org/gitroot/aether/aether-demo.git 或
http://git.eclipse.org/gitroot/aether/aether-demo.git
我的源代码地址:git@git.oschina.net:xiaosiyuan/maven-download-jar.git 或
https://git.oschina.net/xiaosiyuan/maven-download-jar.git