#盛大云存储服务Java SDK
盛大云存储服务Java SDK由盛大官方提供,开发者可以利用该工具包实现:
- 管理Bucket信息
- 上传与下载Object数据
- 生成与设置Bucket Policy
- 生成预签名(Presigned)的可公开访问的URL
- DSL(Fluent Interface)风格的API,简洁易用
- 支持Access Policy Language,通过DSL风格的API生成Bucket Policy
- 支持大文件上传(最大5TB),自动通过Multipart Upload机制上传大文件,对开发者透明
- 提供了独立的签名与认证模块供开发者使用
- 支持HTTPS安全网络访问
- 无需配置Endpoint,自动支持多盛大云存储服务的多IDC
- 支持限速传输
目前最新的版本是2012年09月24日发布的2.0.0:
- snda-cloud-storage-java-sdk-2.0.0.jar 二进制发布包
- snda-cloud-storage-java-sdk-2.0.0.zip 包含源代码,第三方依赖,Javadoc等内容的发布包
<dependency>
<groupId>com.snda</groupId>
<artifactId>snda-cloud-storage-java-sdk</artifactId>
<version>2.0.0</version>
</dependency>
配置Sonatype仓库
<repository>
<id>sonatype-service</id>
<url>https://oss.sonatype.org/service/local/repositories/releases/content</url>
</repository>
盛大云存储服务Java SDK提供了DSL风格的Java API,易于上手,简单高效。其核心为SNDAStorage对象,开发者通过该对象提供的多种方法来访问盛大云存储服务。
SNDAStorage storage = new SNDAStorageBuilder().credential(yourAccessKeyId, yourSecretAccessKey).build();
更多的设置:
SNDAStorage storage = new SNDAStorageBuilder().
credential(yourAccessKeyId, yourSecretAccessKey).
https(). //启用HTTPS
bytesPerSecond(64 * 1024). //限制每秒传输速率为64KB
connectionTimeout(10 * 1000). //设置ConnectionTimeout为10秒
soTimeout(30 * 1000). //设置SoTimeout为30秒
build();
SNDAStorage对象内部维护了一组HTTP连接池,在不使用该对象时,应该调用其destory方法销毁该对象,
storage.destory();
for (BucketSummary each : storage.listBuckets()) {
String name = each.getName();
}
在默认的Location节点中创建名为mybucket的Bucket
storage.bucket("mybucket").create();
在华东一节点创建Bucket
storage.bucket("mybucket").location(Location.HUADONG_1).create();
查看Location
storage.bucket("mybucket").location().get();
删除Bucket
storage.bucket("mybucket").delete();
设置Bucket Policy
storage.bucket("mybucket").policy(myPolicy).set();
获取Bucket Policy
storage.bucket("mybucket").policy().get();
删除Bucket Policy
storage.bucket("mybucket").policy().delete();
根据条件列出Objects
ListBucketResult result = storage.
bucket("mybucket").
prefix("upload/").
delimiter("/").
maxKeys(25).
listObjects();
根据条件列出Multipart Uploads
ListMultipartUploadsResult result = storage.
bucket("mybucket").
prefix("data/").
maxUploads(50).
listMultipartUploads();
上传数据
storage.bucket("mybucket").object("data/upload/pic.jpg").entity(new File("d:\\user\\my_picture.jpg")).upload();
自定义Metadata
storage.bucket("mybucket").object("data/upload/mydata").
contentType("application/octet-stream").
contentMD5("ABCDEFGUVWXYZ").
contentLanguage("en").
metadata("x-snda-meta-foo", "bar").
metadata("x-snda-meta-creation", new DateTime()).
metadata("x-snda-meta-author", "wangzijian@snda.com").
entity(2048L, inputStream).
upload();
下载数据
SNDAObject object = null;
try {
object = storage.bucket("mybucket").object("data/upload/pic.jpg").download();
read(object.getContent());
} finally {
Closeables.closeQuietly(object);
}
SNDAObject实现了java.io.Closeable接口,其内部持有了代表Object内容的InputStream,需要在使用完毕时关闭。
下载至本地硬盘
storage.bucket("mybucket").object("data/pic.jpg").download().to(new File("~/download/my_pic.jpg"));
条件下载(Conditional GET)
storage.bucket("mybucket").object("norther.mp3").ifModifedSince(new DateTime(2012, 10, 7, 20, 0, 0)).download();
分段下载(Range GET)
storage.bucket("mybucket").object("norther.mp3").range(1000, 5000).download();
获取Object信息与Metadata(HEAD Object)
SNDAObjectMetadata metadata = storage.bucket("mybucket").object("music/norther.mp3").head();
更新Object信息与Metadata
storage.bucket("mybucket").object("music/norther.mp3").
contentType("audio/mpeg").
metadata("x-snda-meta-nation", "Finland").
update();
复制Object
storage.bucket("mybucket").object("book/english.txt").
copySource("otherbucket", "data/edu/main.txt");
replaceMetadata().
contentType("text/plain").
metadata("x-snda-meta-author", "Jack Jackson").
copy();
盛大云存储SDK提供了强大的Bucket Policy构建器,开发者可以轻易生成和设置所需要的Bucket Policy。
加入静态引入
import static com.snda.storage.policy.fluent.impl.Conditions.*
允许匿名用户下载该Bucket中key以public作为前缀的所有Object,同时限定User-Agent为Android或IOS,防盗链Referer设置为*.mycompany.com/*
Statement statement = Statement.allow().anyone().perform("storage:GetObject").to("srn:snda:storage:::mybucket/public/*").
where(userAgent().equals("Android", "IOS")).
and(referer().equals("*.mycompany.com/*")).
identifed("public-get-object");
storage.bucket("mybucket").policy(new Policy().
withRandomId().
withStatement(statement)).
set();
允许匿名用户通过HTTPS下载该Bucket中的所有Object,且请求时间必须在2012年10月1日0点至2012年10月8日0点之间:
Statement.allow().anyone().perform("storage:GetObject").to("srn:snda:storage:::mybucket/*").
where(secureTransport().bool(true)).
and(currentTime().greaterThan(new DateTime(2012, 10, 1, 0, 0, 0))).
and(currentTime().lessThan(new DateTime(2012, 10, 8, 0, 0, 0))).
identifed("public-get-object-with-time-restriction");
设置请求的IP必须在指定的"192.168.176.0/24"范围内:
Statement.allow().anyone().perform("storage:GetObject").to("srn:snda:storage:::mybucket/*").
where(sourceIp().ipAddress("192.168.176.0/24")).
identifed("public-get-object-with-connection-restriction");
盛大云存储提供了一种基于查询字串(Query String)的认证方式,即通过预签名(Presigned)的方式,为要发布的Object生成一个带有认证信息的URI,并将它分发给第三方用户来实现公开访问。
SDK中提供了PresigendURIBuilder来构造预签名URI。
URI uri = storage.presignedURIBuilder().
bucket("mybucket").
key("hello_world.mp4").
expires(new DateTime().plusMinutes(5))
build();
生成的URI如下:
http://storage-huadong-1.sdcloud.cn/mybucket/hello_world.mp4?Expires=1348044780&SNDAAccessKeyId=norther&Signature=SJawXv5QdQHcFrTqnx3RpmTN9WI%3D
Entity代表要上传的Object的内容,由内容与长度组成,接口定义如下:
public interface Entity extends InputSupplier<InputStream> {
long getContentLength();
InputStream getInput() throws IOException;
}
getContentLength方法返回该Entity的长度,盛大云存储服务要求上传的数据必须事先指定其长度,最大不得超过5TB。
getInput方法继承自Google Guava的InputSupplier。 InputSupplier代表Entity的内容,是一个打开InputStream的回调(Callback)。 在云存储SDK的不同模块之间,我们只传递InputSupplier的引用,而不是直接传递InputStream。 这是一种高效并且灵活的使用流的方式,因为只有在必要的时候,应用才会调用InputSupplier的getInput方法来打开一个新的InputStream,并保证该InputStream在使用完毕时能被正确的关闭。
下面的样例中,盛大云存储SDK只在必须要的情况下,才会调用getInput来打开流。
object.bucket("mybucket").object("key").
contentType("video/mp4").
entity(65535, new InputSupplier<InputStream>() {
@Override
public InputStream getInput() throws IOException {
return openStream();
}
}).
upload();
云存储SDK提供了3种默认的Entity实现,包括InputSupplierEntity, InputStreamEntity,与 FileEntity
参考FileEntity的实现:
public class FileEntity implements Entity {
private final File file;
public FileEntity(File file) {
this.file = checkNotNull(file);
}
@Override
public long getContentLength() {
return file.length();
}
@Override
public InputStream getInput() throws IOException {
return new FileInputStream(file);
}
}
注意 InputStreamEntity并不关闭其持有的InputStream对象,这样的做法符合IO Stream使用的最佳实现,即:关闭自己打开的流。
样例如下:
InputStream inputStream = null;
try {
inputStream = openInputStream(); //用户应负责关闭自己所打开的流,盛大云存储SDK并不会关闭用户传入的InputStream对象
storage.bucket("mybucket").object("key").entity(256, inputStream).upload();
} finally {
Closeables.closeQuietly(inputStream);
}
开发这使用盛大云存储SDK上传文件时,SDK会透明的使用Multipart Upload实现对大文件上传,一般情况下用户不需要自己来使用Multipart Upload API。
若开发者有自己使用Multipart Upload的需求,可以参看下面的使用样例:
初始化Multipart Upload
InitiateMultipartUploadResult result = storage.bucket("mybucket").object("blob").initiateMultipartUpload();
获得Multipart Upload Id
String uploadId = result.getUploadId();
上传Part
storage.bucket("mybucket").object("blob").multipartUpload(uploadId).
partNumber(1).
entity(new File("/user/data/bin1")).
upload();
复制Part
storage.bucket("mybucket").object("blob").multipartUpload(uploadId).
partNumber(2).
copySource("otherbucket", "bigdata").
copySourceRange(255, 65335);
copy();
完成Multipart Upload
storage.bucket("mybucket").object("blob").multipartUpload(uploadId).
part(1, "ETag1").
part(2, "ETag2").
complete();
放弃Multipart Upload
storage.bucket("mybucket").object("blob").multipartUpload(uploadId).abort();
列出未完成的Parts
storage.bucket("mybucket").object("blob").multipartUpload(uploadId).
partNumberMarker(10).
maxParts(5).
listParts();
盛大云存储SDK会将云存储服务返回的Error转换成统一的异常层次:SNDAServiceException,用户可以基于该类型来实现诸如错误处理与诊断等操作。
public class SNDAServiceException extends RuntimeException {
public int status() //获得错误代表的HTTP状态码(Status)
public String getRequestId() //获得请求的ID,当错误发生时,开发者可以将该ID记录下来并告知盛大云存储服务来快速诊断错误
public DateTime getDate() //获得异常发生的时间
public String getCode() //获得错误码,对应Error结构中的Code元素,HEAD请求时,该值为null
public String getResource() //获得错误对应的资源,对应Error结构中的Resource元素,HEAD请求时,该值为null
public String getErrorMessage() //获得错误消息,对应Error结构中的Message元素,HEAD请求时,该值为null
}
除了标准的错误信息外,用户还可以获得额外的错误信息:
try {
doSomething();
} catch (SNDAServiceException e) {
if ("SignatureDoesNotMatch".equals(e.getCode()) {
String signatureProvided = e.getError().get("SignatureProvided");
}
}
盛大云存储SDK依赖以下的第三方库:
依赖 | 描述 | 网址 |
---|---|---|
Google Guava | Google提供的Java基础类库,提供了函数式编程,并发,集合操作等多种基础功能 | http://code.google.com/p/guava-libraries/ |
Joda Time | 一套关于时间的类库,已被收入至JDK 7中 | http://joda-time.sourceforge.net/ |
SLF4J | 功能强大的日志框架 | http://www.slf4j.org/ |
Apache Commons-Lang | 用来实现一些基础的操作,例如Object hashcode与equals方法的实现 | http://commons.apache.org/lang/ |
Apache Commons-Codec | 用来进行一些诸如Base64之类的编码算法 | http://commons.apache.org/codec/ |
Apache HTTP Client | 用来实现HTTP协议与网络数据的传输 | http://hc.apache.org/httpclient-3.x/ |
Jackson | 著名的JSON格式序列化工具,只有在使用Bucket Policy时需要 | http://jackson.codehaus.org/ |
Copyright (c) 2012 grandcloud.cn. All rights reserved.