山河云对象存储的 Java SDK 已在 GitHub 开源,本文为简要使用文档。更多详细信息请参见 GitHub 项目 和 Java SDK API 文档。

Java SDK 使用 Snips 工具生成,各接口调用的均与 山河云对象存储的 API 相对应。其返回码、请求头、错误码等规定请参照具体的 Qingstor Restful API 文档。

SDK 示例请参见 SDK Example。

使用 SDK 之前请先在 管理控制台申请 Access key。

安装

在线安装

山河云对象存储推荐使用如下方式进行安装。

需要注意的是,需将以下配置中的版本号,替换为您所需要的版本号。山河云对象存储建议使用最新版本。

  • 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>

离线安装

  • 方式一:使用 Fat Jar

    在 GitHub 上,山河云对象存储的 SDK,随着每次 Release 都会附上可供下载的 Fat Jar。Fat Jar 会将 SDK 和所有相关依赖打包为一个 Jar 包,这样用户在使用时只需导入该包就可以使用 SDK。

    下载时,按下图所示,选择报名中带有 all 的安装包。

    java_sdk_1
  • 方式二:手动下载 SDK 所有依赖

    1. 浏览器中访问 https://central.sonatype.com/artifact/com.yunify/qingstor.sdk.java。进入 QingStor Java SDK 详情页面。

    2. 在详情页点击 Dependencies 标签,Dependencies 标签页面,可查看所有的依赖以及对应的版本。

      java_sdk_4
    3. 具体到某一项来说,如下图所示,各参数说明如下。

      artifactId: jackson-databind

      groupId: com.fasterxml.jackson.core

      version: 2.9.10.8

      java_sdk_6

初始化服务

发起请求前需要初始化服务。以下代码初始化了一个 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 用于操作 山河云对象存储服务,如调用 Service 级别的 API 或创建指定的 Bucket 对象来调用 Bucket 和 Object 级别的 API。

代码示例

  1. 获取账户下的 Bucket 列表

    ListBucketsOutput listOutput = stor.listBuckets(null);
  2. 初始化并创建 Bucket,需要指定 Bucket 名称和所在 Zone:

    // 您要在哪个 zone 创建/操作 bucket.
    String zoneName = "jn1a";
    Bucket bucket = stor.getBucket("您的 bucket 名字", zoneName);
    Bucket.PutBucketOutput output = bucket.put();
    if (output.getStatueCode() == 201) {
        // Created
        System.out.println("Put Bucket: Created.");
    }
  3. 获取 Bucket 中存储的 Object 列表

    Bucket.ListjavaObjectsOutput listObjectsOutput = Bucket.listObjects(null);
    List<KeyModel> objectKeys = listObjectsOutput.getKeys();
  4. 创建一个 Object

    1. 上传一个文件

      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);
    2. 上传一个流式文件。流式上传前计算流的 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());
          }
  5. 删除一个 Object

    Bucket.DeleteObjectOutput deleteObjectOutput = bucket.deleteObject("test_file");
  6. 如果用户本地时间与网络时间不同步会因签名原因造成请求失败。用户还需要从服务端获取网络时间。

    1. 获取服务端时间:

      Calendar instance = Calendar.getInstance(TimeZone.getTimeZone("Asia/Beijing"));
      String gmtTime = QSSignatureUtil.formatGmtDate(instance.getTime());
      return gmtTime;
    2. 将获取到的服务端时间设置到 SDK 中:

      reqHandler.getBuilder().setHeader(QSConstant.HEADER_PARAM_KEY_DATE, gmtTime);
      reqHandler.sendAsync();
  7. 使用服务端签名,以上传文件为例:

    public static void javaSdkSendDemo() {
        try {
            //引入jar包后先把相关导入按照IDE提示一一导入
            //创建EvnContext
            EnvContext env = new EnvContext("your_access_key", "your_secret_key");
    
            //你的bucket所在的zone,比如pek3a
            String zoneName = "jn1a";
    
            //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();
        }
    }