Java SDK
QingStor 对象存储的 Java SDK 已在 GitHub 开源,本文为简要使用文档。更多详细信息请参见 GitHub 项目 和 Java SDK API 文档。
Java SDK 使用 Snips 工具生成,各接口调用的均与 QingStor 对象存储的 API 相对应。其返回码、请求头、错误码等规定请参照具体的 Qingstor Restful API 文档。
SDK 示例请参见 SDK Example。
使用 SDK 之前请先在 管理控制台 申请 Access key。
安装
- 可以直接访问 GitHub 的 Release 页面 下载压缩包,也可以执行如下命令行下载源码:
> git clone git@github.com:qingstor/qingstor-sdk-java.git
- 在 gradle/maven 中将版本替换为您需要的版本,QingStor 对象存储推荐使用最新的版本。
Gradle:
dependencies {
  implementation 'com.yunify:qingstor.sdk.java:2.5.1'
}
Maven:
<dependency>
  <groupId>com.yunify</groupId>
  <artifactId>qingstor.sdk.java</artifactId>
  <version>2.5.1</version>
</dependency>
初始化服务
发起请求前需要初始化服务。以下代码初始化了一个 QingStor Service。
import com.qingstor.sdk.config.EnvContext;
import com.qingstor.sdk.service.*;
EvnContext env = new EnvContext("ACCESS_KEY_ID", "SECRET_ACCESS_KEY");
QingStor stor = new QingStor(env);
说明:
- 代码行中的 env承载了用户的认证信息及 SDK 配置;
- 代码行中的 stor用于操作 QingStor 对象存储服务,如调用 Service 级别的 API 或创建指定的 Bucket 对象来调用 Bucket 和 Object 级别的 API。
代码示例
获取账户下的 Bucket 列表
ListBucketsOutput listOutput = stor.listBuckets(null);
创建 Bucket
初始化并创建 Bucket,需要指定 Bucket 名称和所在 Zone:
// 您要在哪个 zone 创建/操作 bucket.
String zoneName = "pek3b";
Bucket bucket = stor.getBucket("您的 bucket 名字", zoneName);
Bucket.PutBucketOutput output = bucket.put();
if (output.getStatueCode() == 201) {
    // Created
    System.out.println("Put Bucket: Created.");
}
获取 Bucket 中存储的 Object 列表
Bucket.ListjavaObjectsOutput listObjectsOutput = Bucket.listObjects(null);
List<KeyModel> objectKeys = listObjectsOutput.getKeys();
创建一个 Object
上传一个文件
String objKey = "object_name";
Bucket.PutObjectInput input = new Bucket.PutObjectInput();
// input 可以设置 File, Stream 等作为要上传的内容.
File f = new File("test_file.txt");
input.setBodyInputFile(f);
// 可选设置.
input.setContentType("text/plain");
input.setContentLength(f.length());
Bucket.PutObjectOutput putObjectOutput = bucket.putObject(objKey, input);
上传一个流式文件
流式上传前计算流的 MD5 值,详细内容如下:
    private void put(String key, InputStream body) throws QSException {
        Bucket.PutObjectInput input = new Bucket.PutObjectInput();
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            // 这里只起示例作用, 如果 body size 有可能非常大, 按一定 size 做拆分以分段
            // 上传形式来分 part 计算 md5 上传才是比较经济的方式.
            byte[] data = body.readAllBytes();
            String contentMD5 = Base64.getEncoder().encodeToString(md5.digest(data));
            input.setContentMD5(contentMD5);
            // 此时 stream 已经被 consume 掉, 但对象存储 server side 也需要读取 body 内容,
            //  所以在 setBodyInputStream 之前,  可以通过:
            //  1. 流已经读取为 bytes array, 直接构造 ByteArrayInputStream 即可;
            // body = new ByteArrayInputStream(data);
            //  2. 如果流支持 markSupported(), 可以重设到流的开始.
            //  下面是方式 2 的示例:
            body.reset();
            input.setBodyInputStream(body);
        } catch (NoSuchAlgorithmException | IOException e) {
            throw new QSException("");
        }
        Bucket.PutObjectOutput output = bucket.putObject(key, input);
        System.out.println(output.getStatueCode());
        if (output.getStatueCode() == 201) {
            System.out.println(output.getETag());
        } else {
            System.out.println(output.getCode());
            System.out.println(output.getMessage());
        }
        System.out.println(output.getRequestId());
    }
删除一个 Object
Bucket.DeleteObjectOutput deleteObjectOutput = bucket.deleteObject("test_file");
本地时间和网络时间不同步
如果用户本地时间与网络时间不同步会因签名原因造成请求失败。用户还需要从服务端获取网络时间。
- 获取服务端时间:
Calendar instance = Calendar.getInstance(TimeZone.getTimeZone("Asia/Beijing"));
String gmtTime = QSSignatureUtil.formatGmtDate(instance.getTime());
return gmtTime;
- 将获取到的服务端时间设置到 SDK 中:
reqHandler.getBuilder().setHeader(QSConstant.HEADER_PARAM_KEY_DATE, gmtTime);
reqHandler.sendAsync();
使用服务端签名
以上传文件为例:
public static void javaSdkSendDemo() {
    try {
        //引入jar包后先把相关导入按照IDE提示一一导入
        //创建EvnContext
        EnvContext env = new EnvContext("your_access_key", "your_secret_key");
        //你的bucket所在的zone,比如pek3a
        String zoneName = "pek3a";
        //bucket名称,如果没有创建先从控制台或者api创建bucket
        String bucketName = "demo_bucket";
        Bucket bucket = new Bucket(env, zoneName, bucketName);
        //最终上传到对象存储的文件显示的文件名称
        String objectKey = "myfile";
        Bucket.PutObjectInput input = new Bucket.PutObjectInput();
        //要上传的本地文件的路径
        File f = new File("/your_file_path.txt");
        input.setBodyInputFile(f);
        input.setContentLength(f.length());
        RequestHandler reqHandler = bucket.putObjectAsyncRequest(objectKey, input,
                new ResponseCallBack<Bucket.PutObjectOutput>() {
                    public void onAPIResponse(Bucket.PutObjectOutput output) {
                        if (output.getStatueCode() != 201) {
                            System.out.println("Message = " + output.getMessage());
                            System.out.println("RequestId = " + output.getRequestId());
                            System.out.println("Code = " + output.getCode());
                            System.out.println("StatueCode = " + output.getStatueCode());
                            System.out.println("Url = " + output.getUrl());
                        }
                        System.exit(0);
                    }
                });
        Calendar instance = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai"));
        String gmtTime = QSSignatureUtil.formatGmtDate(instance.getTime());
        //验证需要这个Date header
        reqHandler.getBuilder().setHeader(QSConstant.HEADER_PARAM_KEY_DATE, gmtTime);
        String strToSignature = reqHandler.getStringToSignature();
        String serverAuthorization = QSSignatureUtil.generateSignature(env.getAccessSecret(),
                strToSignature);
        reqHandler.setSignature(env.getAccessKey(), serverAuthorization);
        //异步发送
        reqHandler.sendAsync();
    }catch (QSException e) {
        e.printStackTrace();
    }
}