human: 如何处理七牛云的对象存储Java SDK

gpt: [对象存储](https://developer.qiniu.com/kodo) > SDK 下载 > Java SDK

#  Java SDK

最近更新时间: 2023-08-21 15:50:48

# 简介

此 SDK 适用于 Java 8 及以上版本。使用此 SDK
构建您的网络应用程序，能让您以非常便捷地方式将数据安全地存储到七牛云上。无论您的网络应用是一个网站程序，还是包括从云端（服务端程序）到终端（手持设备应用）的架构服务或应用，通过七牛云及其
SDK，都能让您应用程序的终端用户高速上传和下载，同时也让您的服务端更加轻盈。

Java SDK 属于七牛服务端SDK之一，主要有如下功能：

  1. 提供生成客户端上传所需的上传凭证的功能
  2. 提供文件从服务端直接上传七牛的功能
  3. 提供对七牛空间中文件进行管理的功能
  4. 提供对七牛空间中文件进行处理的功能
  5. 提供七牛融合CDN相关的刷新，预取，日志功能
  6. 提供七牛视频监控QVS设备管理、流管理等功能

# 开源

  * [Java SDK 项目地址 __](https://github.com/qiniu/java-sdk)
  * [Java SDK 发布地址 __](https://github.com/qiniu/java-sdk/releases)
  * [Java SDK 历史文档](https://developer.qiniu.com/kodo/sdk/java-sdk-6)

# 安装

  * 使用Gradle
  * 使用Maven
  * 手动安装

## 注意

  * 从 7.2.24 开始，okhttp3 升级到 3.14.2，其要求 java 1.8 及以上。
  * 若为 java 1.7 ，请手动指定 okhttp3 依赖 3.12，要求 3.12.3 及以上， `com.squareup.okhttp3:okhttp:3.12.3`

    
    
        compile ('com.qiniu:qiniu-java-sdk:7.13.1') {
            exclude group: 'com.squareup.okhttp3', module: 'okhttp'
        }
        compile 'com.squareup.okhttp3:okhttp:3.12.6'
    

### Gradle

    
    
    compile 'com.qiniu:qiniu-java-sdk:7.13.+'
    

### Maven

    
    
    <dependency>
      <groupId>com.qiniu</groupId>
      <artifactId>qiniu-java-sdk</artifactId>
      <version>[7.13.0, 7.13.99]</version>
    </dependency>
    

这里的`version`指定了一个版本范围，每次更新`pom.xml`的时候会尝试去下载`7.7.x`版本中的最新版本，你可以手动指定一个固定的版本。

### 手动下载

请尽量使用包管理工具自动解决依赖问题。如果条件实在不满足，只能通过手动下载jar包的方式来解决。本项目自身jar及依赖的第三方库如下：

Java SDK依赖的第三方库及其版本如下：

    
    
    <dependencies>
        <dependency>
          <groupId>com.squareup.okhttp3</groupId>
          <artifactId>okhttp</artifactId>
          <version>3.14.2</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>com.google.code.gson</groupId>
          <artifactId>gson</artifactId>
          <version>2.8.5</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>com.qiniu</groupId>
          <artifactId>happy-dns-java</artifactId>
          <version>0.1.6</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    

库名称 | 库项目地址 | 库下载地址  
---|---|---  
qiniu-java-sdk | [链接🔗 __](https://github.com/qiniu/java-sdk)| [链接🔗 __](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22qiniu-java-sdk%22)  
happy-dns-java | [链接🔗 __](https://github.com/qiniu/happy-dns-java)| [链接🔗 __](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22happy-dns-java%22)  
okhttp3 | [链接🔗 __](https://github.com/square/okhttp)| [链接🔗 __](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.squareup.okhttp3%22)  
okio | [链接🔗 __](https://github.com/square/okio)| [链接🔗 __](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.squareup.okio%22)  
gson | [链接🔗 __](https://github.com/google/gson)| [链接🔗 __](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.google.code.gson%22)  
junit | [链接🔗 __](http://junit.org/junit4/)| [链接🔗 __](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22junit%22)  
  
可以点击每个库的下载链接，然后选择对应的jar进行下载，然后引入到项目中。

# 鉴权

Java SDK的所有的功能，都需要合法的授权。授权凭证的签算需要七牛账号下的一对有效的`Access Key`和`Secret
Key`，这对密钥可以通过如下步骤获得：

  1. 点击[注册🔗 __](https://portal.qiniu.com/signup)开通 七牛开发者帐号
  2. 如果已有账号，直接登录七牛开发者后台，点击[这里🔗 __](https://portal.qiniu.com/user/key)查看 Access Key 和 Secret Key

# 文件上传

  * 上传流程
  * 客户端上传凭证
    * 简单上传凭证
    * 覆盖上传凭证
    * 自定义上传回复凭证
    * 带回调业务服务器的凭证
    * 带数据处理的凭证
    * 带自定义参数的凭证
    * 综合上传凭证
  * 服务器直传
    * 构建配置类
    * 自定义上传域名
    * 设置请求协议为http
    * 文件上传
    * 字节数组上传
    * 数据流上传
    * 断点续传
    * 自定义参数上传
    * 解析自定义回复内容
    * 业务服务器验证存储服务回调

## 上传流程

文件上传分为客户端上传（主要是指网页端和移动端等面向终端用户的场景）和服务端上传两种场景，具体可以参考文档[业务流程](https://developer.qiniu.com/kodo/manual/1205/programming-
model)。

  * 客户端上传：Java 编写的服务端仅提供上传需要的凭证，网页端和移动端等客户端从服务端获取此凭证后使用客户端相应的 SDK 进行上传操作
  * 服务端上传：文件在服务端或者服务端作为文件的中转站，使用此 Java SDK 上传文件至七牛云端

服务端SDK在上传方面主要提供两种功能

  * 生成客户端上传所需要的上传凭证
  * 服务端上传文件到七牛云端

## 客户端上传凭证

客户端（移动端或者Web端）上传文件的时候，需要从客户自己的业务服务器获取上传凭证，而这些上传凭证是通过服务端的SDK来生成的，然后通过客户自己的业务API分发给客户端使用。根据上传的业务需求不同，七牛云Java
SDK支持丰富的上传凭证生成方式。

### 简单上传的凭证

最简单的上传凭证只需要`AccessKey`，`SecretKey`和`Bucket`就可以。

    
    
    String accessKey = "access key";
    String secretKey = "secret key";
    String bucket = "bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    String upToken = auth.uploadToken(bucket);
    System.out.println(upToken);
    

### 覆盖上传的凭证

覆盖上传除了需要`简单上传`所需要的信息之外，还需要想进行覆盖的文件名称，这个文件名称同时是客户端上传代码中指定的文件名，两者必须一致。

    
    
    String accessKey = "access key";
    String secretKey = "secret key";
    String bucket = "bucket name";
    String key = "file key";
    
    Auth auth = Auth.create(accessKey, secretKey);
    String upToken = auth.uploadToken(bucket, key);
    System.out.println(upToken);
    

### 自定义上传回复的凭证

默认情况下，文件上传到七牛之后，在没有设置`returnBody`或者`回调`相关的参数情况下，七牛返回给上传端的回复格式为`hash`和`key`，例如：

    
    
    {"hash":"Ftgm-CkWePC9fzMBTRNmPMhGBcSV","key":"qiniu.jpg"}
    

有时候我们希望能自定义这个返回的JSON格式的内容，可以通过设置`returnBody`参数来实现，在`returnBody`中，我们可以使用七牛支持的[魔法变量](https://developer.qiniu.com/kodo/manual/1235/vars#magicvar)和[自定义变量](https://developer.qiniu.com/kodo/manual/1235/vars#xvar)。

    
    
    String accessKey = "access key";
    String secretKey = "secret key";
    String bucket = "bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    StringMap putPolicy = new StringMap();
    putPolicy.put("returnBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize)}");
    long expireSeconds = 3600;
    String upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy);
    System.out.println(upToken);
    

则文件上传到七牛之后，收到的回复内容如下：

    
    
    {"key":"qiniu.jpg","hash":"Ftgm-CkWePC9fzMBTRNmPMhGBcSV","bucket":"if-bc","fsize":39335}
    

### 带回调业务服务器的凭证

上面生成的`自定义上传回复`的上传凭证适用于上传端（无论是客户端还是服务端）和七牛服务器之间进行直接交互的情况下。在客户端上传的场景之下，有时候客户端需要在文件上传到七牛之后，从业务服务器获取相关的信息，这个时候就要用到七牛的上传回调及相关回调参数的设置。

    
    
    String accessKey = "access key";
    String secretKey = "secret key";
    String bucket = "bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    StringMap putPolicy = new StringMap();
    putPolicy.put("callbackUrl", "http://api.example.com/qiniu/upload/callback");
    putPolicy.put("callbackBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize)}");
    putPolicy.put("callbackBodyType", "application/json");
    long expireSeconds = 3600;
    String upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy);
    System.out.println(upToken);
    

在使用了上传回调的情况下，客户端收到的回复就是业务服务器响应七牛的JSON格式内容。  
通常情况下，我们建议使用`application/json`格式来设置`callbackBody`，保持数据格式的统一性。实际情况下，`callbackBody`也支持`application/x-www-
form-urlencoded`格式来组织内容，这个主要看业务服务器在接收到`callbackBody`的内容时如何解析。例如：

    
    
    String accessKey = "access key";
    String secretKey = "secret key";
    String bucket = "bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    StringMap putPolicy = new StringMap();
    putPolicy.put("callbackUrl", "http://api.example.com/qiniu/upload/callback");
    putPolicy.put("callbackBody", "key=$(key)&hash=$(etag)&bucket=$(bucket)&fsize=$(fsize)");
    long expireSeconds = 3600;
    String upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy);
    System.out.println(upToken);
    

### 带数据处理的凭证

存储服务支持在文件上传到七牛之后，立即对其进行多种指令的数据处理，这个只需要在生成的上传凭证中指定相关的处理参数即可。

    
    
    String accessKey = "access key";
    String secretKey = "secret key";
    String bucket = "bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    StringMap putPolicy = new StringMap();
    
    //数据处理指令，支持多个指令
    String saveMp4Entry = String.format("%s:avthumb_test_target.mp4", bucket);
    String saveJpgEntry = String.format("%s:vframe_test_target.jpg", bucket);
    String avthumbMp4Fop = String.format("avthumb/mp4|saveas/%s", UrlSafeBase64.encodeToString(saveMp4Entry));
    String vframeJpgFop = String.format("vframe/jpg/offset/1|saveas/%s", UrlSafeBase64.encodeToString(saveJpgEntry));
    
    //将多个数据处理指令拼接起来
    String persistentOpfs = StringUtils.join(new String[]{
            avthumbMp4Fop, vframeJpgFop
    }, ";");
    putPolicy.put("persistentOps", persistentOpfs);
    
    //数据处理队列名称，必填
    putPolicy.put("persistentPipeline", "mps-pipe1");
    
    //数据处理完成结果通知地址
    putPolicy.put("persistentNotifyUrl", "http://api.example.com/qiniu/pfop/notify");
    
    long expireSeconds = 3600;
    String upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy);
    System.out.println(upToken);    
    

队列 pipeline 请参阅[创建私有队列 __](https://portal.qiniu.com/dora/media-
gate/pipeline)；转码操作具体参数请参阅[音视频转码](https://developer.qiniu.com/dora/api/audio-
and-video-transcoding-avthumb)；saveas
请参阅[处理结果另存](https://developer.qiniu.com/dora/api/processing-results-save-
saveas)。

### 带自定义参数的凭证

存储服务支持客户端上传文件的时候定义一些自定义参数，这些参数可以在`returnBody`和`callbackBody`里面和七牛内置支持的魔法变量（即系统变量）通过相同的方式来引用。这些自定义的参数名称必须以`x:`开头。例如客户端上传的时候指定了自定义的参数`x:user`和`x:age`分别是`String`和`int`类型。那么可以通过下面的方式引用：

    
    
    putPolicy.put("returnBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize),\"user\":\"$(x:user)\",\"age\",$(x:age)}");
    

或者

    
    
    putPolicy.put("callbackBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize),\"user\":\"$(x:user)\",\"age\",$(x:age)}");
    

### 综合上传凭证

上面生成上传凭证的方法，都是通过设置[上传策略🔗](https://developer.qiniu.com/kodo/manual/1206/put-
policy)相关的参数来支持的，这些参数可以通过不同的组合方式来满足不同的业务需求，可以灵活地组织你所需要的上传凭证。

### 上传凭证额外参数

默认会拒绝不在预定义之中的参数。即：

    
    
    String upToken = auth.uploadToken(bucket, key, expireSeconds, putPolicy, true);
    

若允许添加额外参数，可以将参数设置为`false`。

    
    
    String upToken = auth.uploadToken(bucket, key, expireSeconds, putPolicy, false);
    

## 服务端直传

服务端直传是指客户利用七牛服务端SDK从服务端直接上传文件到七牛云，交互的双方一般都在机房里面，所以服务端可以自己生成上传凭证，然后利用此SDK中的上传逻辑进行上传，最后从七牛云获取上传的结果，这个过程中由于双方都是业务服务器，所以很少利用到上传回调的功能，而是直接自定义`returnBody`来获取自定义的回复内容。

### 构建配置类

存储支持空间创建在不同的机房，在使用Java
SDK中的`UploadManager`上传文件之前，必须要构建一个上传用的`Configuration`对象，在该对象中，可以指定空间对应的`Region`以及其他的一些影响上传的参数。

    
    
    //构造一个带指定Region对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
    //...其他参数参考类注释
    
    UploadManager uploadManager = new UploadManager(cfg);
    //...生成上传凭证，然后准备上传
    
    

跨区域双活指定`RegionGroup`(内测功能，需要工单申请开通跨区域双活功能之后使用)

    
    
    Region region0 = Region.region0();
    Region region1 = Region.region1();
    RegionGroup regionGroup = new RegionGroup();
    regionGroup.addRegion(region0);
    regionGroup.addRegion(region1);
    Configuration config = new Configuration(regionGroup);
    config.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
    

其中关于`Region`对象和机房的关系如下：

机房 | Region  
---|---  
华东 | `Region.region0()`, `Region.huadong()`  
华北 | `Region.region1()`, `Region.huabei()`  
华南 | `Region.region2()`, `Region.huanan()`  
北美 | `Region.regionNa0()`, `Region.beimei()`  
东南亚 | `Region.regionAs0()`, `Region.xinjiapo()`  
  
### 注意

  * 若不指定 `Region` 或 `Region.autoRegion()` ，则会使用 自动判断 区域，使用相应域名处理。
  * 如果可以明确 区域 的话，最好指定固定区域，这样可以少一步网络请求，少一步出错的可能。

### 自定义区域域名

    
    
    Region region = new Region.Builder()
                    .region("z0")
                    .accUpHost("up.qiniup.com")
                    .srcUpHost("upload.qiniup.com")
                    .iovipHost("iovip.qiniuio.com")
                    .rsHost("rs.qiniu.com")
                    .rsfHost("rsf.qiniu.com")
                    .apiHost("api.qiniu.com")
                    .build();
    Configuration cfg = new Configuration(region);
    cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
    

### 设置请求协议为http

    
    
    Configuration cfg = new Configuration(zone);
    cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
    cfg.useHttpsDomains = false;
    UploadManager uploadManager = new UploadManager(cfg);
    

### 文件上传

最简单的就是上传本地文件，直接指定文件的完整路径即可上传。

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
    //...其他参数参考类注释
    
    UploadManager uploadManager = new UploadManager(cfg);
    //...生成上传凭证，然后准备上传
    String accessKey = "your access key";
    String secretKey = "your secret key";
    String bucket = "your bucket name";
    //如果是Windows情况下，格式是 D:\\qiniu\\test.png
    String localFilePath = "/home/qiniu/test.png";
    //默认不指定key的情况下，以文件内容的hash值作为文件名
    String key = null;
    
    Auth auth = Auth.create(accessKey, secretKey);
    String upToken = auth.uploadToken(bucket);
    
    try {
        Response response = uploadManager.put(localFilePath, key, upToken);
        //解析上传成功的结果
        DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
        System.out.println(putRet.key);
        System.out.println(putRet.hash);
    } catch (QiniuException ex) {
        ex.printStackTrace();
        if (ex.response != null) {
            System.err.println(ex.response);
    
            try {
                String body = ex.response.toString();
                System.err.println(body);
            } catch (Exception ignored) {
            }
        }
    }
    

### 字节数组上传

可以支持将内存中的字节数组上传到空间中。

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
    //...其他参数参考类注释
    
    UploadManager uploadManager = new UploadManager(cfg);
    //...生成上传凭证，然后准备上传
    String accessKey = "your access key";
    String secretKey = "your secret key";
    String bucket = "your bucket name";
    
    //默认不指定key的情况下，以文件内容的hash值作为文件名
    String key = null;
    
    try {
        byte[] uploadBytes = "hello qiniu cloud".getBytes("utf-8");
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket);
    
        try {
            Response response = uploadManager.put(uploadBytes, key, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            System.out.println(putRet.key);
            System.out.println(putRet.hash);
        } catch (QiniuException ex) {
            ex.printStackTrace();
            if (ex.response != null) {
                System.err.println(ex.response);
    
                try {
                    String body = ex.response.toString();
                    System.err.println(body);
                } catch (Exception ignored) {
                }
            }
        }
    } catch (UnsupportedEncodingException ex) {
        //ignore
    }
    

### 数据流上传

这里演示的是`InputStream`对象的上传，适用于所有的`InputStream`子类。这里的`ByteInputStream`只用于演示目的，实际用法根据情况而定。

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
    //...其他参数参考类注释
    
    UploadManager uploadManager = new UploadManager(cfg);
    //...生成上传凭证，然后准备上传
    String accessKey = "your access key";
    String secretKey = "your secret key";
    String bucket = "your bucket name";
    
    //默认不指定key的情况下，以文件内容的hash值作为文件名
    String key = null;
    
    try {
        byte[] uploadBytes = "hello qiniu cloud".getBytes("utf-8");
        ByteArrayInputStream byteInputStream=new ByteArrayInputStream(uploadBytes);
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket);
    
        try {
            Response response = uploadManager.put(byteInputStream,key,upToken,null, null);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            System.out.println(putRet.key);
            System.out.println(putRet.hash);
        } catch (QiniuException ex) {
            ex.printStackTrace();
            if (ex.response != null) {
                System.err.println(ex.response);
    
                try {
                    String body = ex.response.toString();
                    System.err.println(body);
                } catch (Exception ignored) {
                }
            }
        }
    } catch (UnsupportedEncodingException ex) {
        //ignore
    }
    

### 断点续上传

断点续传是在分片上传的基础上实现。SDK 内置两种上传方式：表单上传和分片上传。表单上传使用一个 HTTP POST
请求完成文件的上传，因此比较适合较小的文件。相比而言，分片上传比较适合上传比较大的文件（例如数百 MB 或更大）。  
若需深入了解上传方式之间的区别，请参阅上传类型中
[表单上传](https://developer.qiniu.com/kodo/manual/1272/form-upload) 、[分片上传 v1
版](https://developer.qiniu.com/kodo/manual/1650/chunked-upload) 和 [分片上传 v2
版](https://developer.qiniu.com/kodo/6364/multipartupload-interface) 接口说明。  
可以选择分片上传版本，推荐 Configuration.ResumableUploadAPIVersion.V2，表示 分片上传 v2 版，默认
Configuration.ResumableUploadAPIVersion.V1，表示 分片上传 v1 版。

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
    cfg.resumableUploadMaxConcurrentTaskCount = 2;  // 设置分片上传并发，1：采用同步上传；大于1：采用并发上传
    //...其他参数参考类注释
    
    //...生成上传凭证，然后准备上传
    String accessKey = "your access key";
    String secretKey = "your secret key";
    String bucket = "your bucket name";
    //如果是Windows情况下，格式是 D:\\qiniu\\test.png
    String localFilePath = "/home/qiniu/test.mp4";
    //默认不指定key的情况下，以文件内容的hash值作为文件名
    String key = null;
    
    Auth auth = Auth.create(accessKey, secretKey);
    String upToken = auth.uploadToken(bucket);
    
    String localTempDir = Paths.get(System.getenv("java.io.tmpdir"), bucket).toString();
    try {
        //设置断点续传文件进度保存目录
        FileRecorder fileRecorder = new FileRecorder(localTempDir);
        UploadManager uploadManager = new UploadManager(cfg, fileRecorder);
        try {
            Response response = uploadManager.put(localFilePath, key, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            System.out.println(putRet.key);
            System.out.println(putRet.hash);
        } catch (QiniuException ex) {
            ex.printStackTrace();
            if (ex.response != null) {
                System.err.println(ex.response);
    
                try {
                    String body = ex.response.toString();
                    System.err.println(body);
                } catch (Exception ignored) {
                }
            }
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    

### 自定义参数上传

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
    //...其他参数参考类注释
    
    //...生成上传凭证，然后准备上传
    String accessKey = "your access key";
    String secretKey = "your secret key";
    String bucket = "your bucket name";
    //如果是Windows情况下，格式是 D:\\qiniu\\test.png
    String localFilePath = "/home/qiniu/test.mp4";
    //默认不指定key的情况下，以文件内容的hash值作为文件名
    //设置上传后的文件名称
    String key = "qiniu_test.jpg";
    
    Auth auth = Auth.create(accessKey, secretKey);
    
    //上传自定义参数，自定义参数名称需要以 x:开头
    StringMap params = new StringMap();
    params.put("x:fname","123.jpg");
    params.put("x:age",20);
    
    //上传策略
    StringMap policy = new StringMap();
    //自定义上传后返回内容，返回自定义参数，需要设置 x:参数名称，注意下面
    policy.put("returnBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"fname\":\"$(x:fname)\",\"age\",$(x:age)}");
    //生成上传token
    String upToken = auth.uploadToken(bucket, key, 3600, policy);
    try {
        Response response = uploadManager.put(localFilePath, key, upToken,params,null,false);
        System.out.println(response.bodyString());
    } catch (QiniuException ex) {
        ex.printStackTrace();
        if (ex.response != null) {
            System.err.println(ex.response);
    
            try {
                String body = ex.response.toString();
                System.err.println(body);
            } catch (Exception ignored) {
            }
        }
    }
    

## 解析自定义回复内容

有些情况下，七牛返回给上传端的内容不是默认的`hash`和`key`形式，这种情况下，可能出现在自定义`returnBody`或者自定义了`callbackBody`的情况下，前者一般是服务端直传的场景，而后者则是接受上传回调的场景，这两种场景之下，都涉及到需要将自定义的回复内容解析为`Java`的类对象，一般建议在交互过程中，都采用`JSON`的方式，这样处理起来方法比较一致，而且`JSON`的方法最通用。

遇到诸如自定义`returnBody`的情况：

    
    
    putPolicy.put("returnBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize)}");
    

或者是自定义了`callbackBody`的情况：

    
    
    putPolicy.put("callbackBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize)}");
    

我们只需要自己定义了对应的类，例如：

    
    
    class MyPutRet {
        public String key; // 文件保存的 key
        public String hash; // 文件保存的 Etag
        public String bucket; // 文件保存的 bucket
        public long fsize; // 文件的大小，单位：B
    }
    

然后在获取到上传回复的`Response`对象时，使用如下的方法就可以转为自定义回复的类对象了：

    
    
    MyPutRet myPutRet=response.jsonToObject(MyPutRet.class);
    

## 业务服务器验证存储服务回调

在上传策略里面设置了上传回调相关参数的时候，七牛在文件上传到服务器之后，会主动地向`callbackUrl`发送POST请求的回调，回调的内容为`callbackBody`模版所定义的内容，如果这个模版里面引用了[魔法变量](https://developer.qiniu.com/kodo/manual/1235/vars#magicvar)或者[自定义变量](https://developer.qiniu.com/kodo/manual/1235/vars#xvar)，那么这些变量会被自动填充对应的值，然后在发送给业务服务器。

业务服务器在收到来自七牛的回调请求的时候，可以根据请求头部的`Authorization`字段来进行验证，查看该请求是否是来自七牛的未经篡改的请求。具体可以参考七牛的[回调鉴权](https://developer.qiniu.com/kodo/kb/1409/seven-
cattle-callback-and-callback-authentication)。

注意：业务端服务器回调鉴权的Content-Type类型应该与上传策略中指定的callbackBodyType相同，默认为
application/x-www-form-urlencoded，当 Content-Type 为 application/x-www-form-
urlencoded 时，签名内容必须包括请求内容。当 Content-Type 为 application/json 时，签名内容不包括请求内容。

    
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    /*
    * 这两个参数就是在定义PutPolicy参数时指定的内容
    */
    
    //回调地址
    String callbackUrl = "http://api.example.com/qiniu/callback";
    //定义回调内容的组织格式，与上传策略中的callbackBodyType要保持一致
    //String callbackBodyType = "application/x-www-form-urlencoded"; //回调鉴权的签名包括请求内容callbackBody
    String callbackBodyType = "application/json";//回调鉴权的签名不包括请求内容
    
    /**
     * 这两个参数根据实际所使用的HTTP框架进行获取
     */
    //通过获取请求的HTTP头部Authorization字段获得
    String callbackAuthHeader = "xxx";
    //通过读取回调POST请求体获得，不要设置为null
    byte[] callbackBody = null;
    
    
    Auth auth = Auth.create(accessKey, secretKey);
    //检查是否为合法的回调请求
    boolean validCallback = auth.isValidCallback(callbackAuthHeader, callbackUrl, callbackBody, callbackBodyType);
    if (validCallback) {
        //继续处理其他业务逻辑
    } else {
        //这是哪里的请求，被劫持，篡改了吧？
    }
    
    

# 下载文件

  * 公开空间
  * 私有空间

文件下载分为公开空间的文件下载和私有空间的文件下载。

## 公开空间

### 手动拼接方式

对于公开空间，其访问的链接主要是将空间绑定的域名拼接上空间里面的文件名即可访问，标准情况下需要在拼接链接之前，将文件名进行`urlencode`以兼容不同的字符。如果有其他访问处理需求，在文件名之后继续拼接即可。

    
    
    String fileName = "a/b/qiniu.jpg";
    // domainOfBucket 中的域名为用户 bucket 绑定的下载域名，下面域名仅为示例，不可使用
    String domainOfBucket = "http://mock.qiniu.com";
    String encodedFileName = URLEncoder.encode(fileName, "utf-8").replace("+", "%20");
    String finalUrl = String.format("%s/%s", domainOfBucket, encodedFileName);
    System.out.println(finalUrl);
    

### sdk 自动生成方式

sdk 封装了下载 URL 的生成，只需要输入下载所需参数即可。已支持多媒体处理命令等。

    
    
    // domain   用户 bucket 绑定的下载域名 eg: mock.qiniu.com【必须】
    // useHttps 是否使用 https【必须】
    // key      下载资源在七牛云存储的 key【必须】
    DownloadUrl url = new DownloadUrl(domain, useHttps, key);
    url.setAttname(attname) // 配置 attname
       .setFop(fop) // 配置 fop
       .setStyle(style, styleSeparator, styleParam) // 配置 style
    String urlString = url.buildURL();
    System.out.println(urlString);
    

## 私有空间

### 手动拼接方式

对于私有空间，首先需要按照公开空间的文件访问方式构建对应的公开空间访问链接，然后再对这个链接进行私有授权签名。

    
    
    String fileName = "公司/存储/qiniu.jpg";
    String domainOfBucket = "http://devtools.qiniu.com";
    String encodedFileName = URLEncoder.encode(fileName, "utf-8").replace("+", "%20");
    String publicUrl = String.format("%s/%s", domainOfBucket, encodedFileName);
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    Auth auth = Auth.create(accessKey, secretKey);
    long expireInSeconds = 3600;//1小时，可以自定义链接过期时间
    String finalUrl = auth.privateDownloadUrl(publicUrl, expireInSeconds);
    System.out.println(finalUrl);
    

#### sdk 自动生成方式

sdk 封装了下载 URL 的生成，只需要输入下载所需参数即可。已支持多媒体处理命令，过期时间 e 和 签名 token 等。

    
    
    // domain   下载 domain, eg: qiniu.com【必须】
    // useHttps 是否使用 https【必须】
    // key      下载资源在七牛云存储的 key【必须】
    DownloadUrl url = new DownloadUrl(domain, useHttps, key);
    url.setAttname(attname) // 配置 attname
       .setFop(fop) // 配置 fop
       .setStyle(style, styleSeparator, styleParam) // 配置 style
    
    // 带有效期
    long expireInSeconds = 3600;//1小时，可以自定义链接过期时间
    long deadline = System.currentTimeMillis()/1000 + expireInSeconds;
    Auth auth = Auth.create("your access key", "your secret key");
    String urlString = url.buildURL(auth, deadline);
    System.out.println(urlString);
    

# 资源管理

资源管理包括的主要功能有：

  * 获取文件信息
  * 修改文件类型
  * 移动或重命名文件
  * 复制文件副本
  * 删除空间中的文件
  * 设置或更新文件生存时间
  * 获取空间文件列表
  * 抓取网络资源到空间
  * 资源管理批量操作
    * 批量获取文件信息
    * 批量修改文件类型
    * 批量删除文件
    * 批量移动或重命名文件
    * 批量复制文件
    * 批量解冻归档存储类型文件
    * 批量混合指令操作
  * 更新镜像存储空间中的文件内容
  * 更新镜像存储空间中文件内容

## 获取文件信息

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    String bucket = "your bucket name";
    String key = "your file key";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    try {
        FileInfo fileInfo = bucketManager.stat(bucket, key);
        System.out.println(fileInfo.hash);
        System.out.println(fileInfo.fsize);
        System.out.println(fileInfo.mimeType);
        System.out.println(fileInfo.putTime);
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

## 修改文件类型

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    String key = "your file key";
    String newMimeType = "new mime type";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    //修改文件类型
    try {
        bucketManager.changeMime(bucket, key, newMimeType);
    } catch (QiniuException ex) {
        System.out.println(ex.response.toString());
    }
    

## 移动或重命名文件

移动操作本身支持移动文件到相同，不同空间中，在移动的同时也可以支持文件重命名。唯一的限制条件是，移动的源空间和目标空间必须在同一个机房。

源空间 | 目标空间 | 源文件名 | 目标文件名 | 描述  
---|---|---|---|---  
BucketA | BucketA | KeyA | KeyB | 相当于同空间文件重命名  
BucketA | BucketB | KeyA | KeyA | 移动文件到BucketB，文件名一致  
BucketA | BucketB | KeyA | KeyB | 移动文件到BucketB，文件名变成KeyB  
  
`move`操作支持强制覆盖选项，即如果目标文件已存在，可以设置强制覆盖参数`force`来覆盖那个文件的内容。

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String fromBucket = "from bucket name";
    String fromKey = "from key";
    String toBucket = "to bucket name";
    String toKey = "to key";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    try {
        bucketManager.move(fromBucket, fromKey, toBucket, toKey);
    } catch (QiniuException ex) {
        //如果遇到异常，说明移动失败
        System.err.println(ex.code());
        System.err.println(ex.response.toString());
    }
    

## 复制文件副本

文件的复制和文件移动其实操作一样，主要的区别是移动后源文件不存在了，而复制的结果是源文件还存在，只是多了一个新的文件副本。

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String fromBucket = "from bucket name";
    String fromKey = "from key";
    String toBucket = "to bucket name";
    String toKey = "to key";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    try {
        bucketManager.copy(fromBucket, fromKey, toBucket, toKey);
    } catch (QiniuException ex) {
        //如果遇到异常，说明复制失败
        System.err.println(ex.code());
        System.err
    }
    

## 删除空间中的文件

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    String key = "your file key";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    try {
        bucketManager.delete(bucket, key);
    } catch (QiniuException ex) {
        //如果遇到异常，说明删除失败
        System.err.println(ex.code());
        System.err.println(ex.response.toString());
    }
    

## 设置或更新文件的生存时间

可以给已经存在于空间中的文件设置文件生存时间，或者更新已设置了生存时间但尚未被删除的文件的新的生存时间。

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "access key";
    String secretKey = "secret key";
    String bucket = "bucket name";
    String key = "file key";
    //过期天数，该文件10天后删除
    int days = 10;
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    try {
        bucketManager.deleteAfterDays(bucket, key, days);
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

## 获取空间文件列表

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    //文件名前缀
    String prefix = "";
    //每次迭代的长度限制，最大1000，推荐值 1000
    int limit = 1000;
    //指定目录分隔符，列出所有公共前缀（模拟列出目录效果）。缺省值为空字符串
    String delimiter = "";
    
    //列举空间文件列表
    BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(bucket, prefix, limit, delimiter);
    while (fileListIterator.hasNext()) {
        //处理获取的file list结果
        FileInfo[] items = fileListIterator.next();
        for (FileInfo item : items) {
            System.out.println(item.key);
            System.out.println(item.hash);
            System.out.println(item.fsize);
            System.out.println(item.mimeType);
            System.out.println(item.putTime);
            System.out.println(item.endUser);
        }
    }
    

## 抓取网络资源到空间

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    String key = "your file key";
    String remoteSrcUrl = "http://devtools.qiniu.com/qiniu.png";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    //抓取网络资源到空间
    try {
        FetchRet fetchRet = bucketManager.fetch(remoteSrcUrl, bucket, key);
        System.out.println(fetchRet.hash);
        System.out.println(fetchRet.key);
        System.out.println(fetchRet.mimeType);
        System.out.println(fetchRet.fsize);
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

## 资源管理批量操作

### 批量获取文件信息

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    try {
        //单次批量请求的文件数量不得超过1000
        String[] keyList = new String[]{
                "qiniu.jpg",
                "qiniu.mp4",
                "qiniu.png",
        };
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
        batchOperations.addStatOps(bucket, keyList);
        Response response = bucketManager.batch(batchOperations);
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
    
        for (int i = 0; i < keyList.length; i++) {
            BatchStatus status = batchStatusList[i];
            String key = keyList[i];
            System.out.print(key+"\t");
            if (status.code == 200) {
                //文件存在
                System.out.println(status.data.hash);
                System.out.println(status.data.mimeType);
                System.out.println(status.data.fsize);
                System.out.println(status.data.putTime);
            } else {
                System.out.println(status.data.error);
            }
        }
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

### 批量修改文件类型

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    try {
        //单次批量请求的文件数量不得超过1000
        HashMap<String, String> keyMimeMap = new HashMap<>();
        keyMimeMap.put("qiniu.jpg", "image/jpg");
        keyMimeMap.put("qiniu.png", "image/png");
        keyMimeMap.put("qiniu.mp4", "video/mp4");
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
    
        //添加指令
        for (Map.Entry<String, String> entry : keyMimeMap.entrySet()) {
            String key = entry.getKey();
            String newMimeType = entry.getValue();
            batchOperations.addChgmOp(bucket, key, newMimeType);
        }
    
        Response response = bucketManager.batch(batchOperations);
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
    
        int index = 0;
        for (Map.Entry<String, String> entry : keyMimeMap.entrySet()) {
            String key = entry.getKey();
            System.out.print(key + "\t");
            BatchStatus status = batchStatusList[index];
            if (status.code == 200) {
                System.out.println("change mime success");
            } else {
                System.out.println(status.data.error);
            }
            index += 1;
        }
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

### 批量删除文件

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    try {
        //单次批量请求的文件数量不得超过1000
        String[] keyList = new String[]{
                "qiniu.jpg",
                "qiniu.mp4",
                "qiniu.png",
        };
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
        batchOperations.addDeleteOp(bucket, keyList);
        Response response = bucketManager.batch(batchOperations);
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
    
        for (int i = 0; i < keyList.length; i++) {
            BatchStatus status = batchStatusList[i];
            String key = keyList[i];
            System.out.print(key + "\t");
            if (status.code == 200) {
                System.out.println("delete success");
            } else {
                System.out.println(status.data.error);
            }
        }
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

### 批量移动或重命名文件

    
    
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    try {
        //单次批量请求的文件数量不得超过1000
        String[] keyList = new String[]{
                "qiniu.jpg",
                "qiniu.mp4",
                "qiniu.png",
        };
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
        for (String key : keyList) {
            batchOperations.addMoveOp(bucket, key, bucket, key + "_move");
        }
    
        Response response = bucketManager.batch(batchOperations);
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
    
        for (int i = 0; i < keyList.length; i++) {
            BatchStatus status = batchStatusList[i];
            String key = keyList[i];
            System.out.print(key + "\t");
            if (status.code == 200) {
                System.out.println("move success");
            } else {
                System.out.println(status.data.error);
            }
        }
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

### 批量复制文件

    
    
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    try {
        //单次批量请求的文件数量不得超过1000
        String[] keyList = new String[]{
                "qiniu.jpg",
                "qiniu.mp4",
                "qiniu.png",
        };
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
        for (String key : keyList) {
            batchOperations.addCopyOp(bucket, key, bucket, key + "_copy");
        }
    
        Response response = bucketManager.batch(batchOperations);
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
    
        for (int i = 0; i < keyList.length; i++) {
            BatchStatus status = batchStatusList[i];
            String key = keyList[i];
            System.out.print(key + "\t");
            if (status.code == 200) {
                System.out.println("copy success");
            } else {
                System.out.println(status.data.error);
            }
        }
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

### 批量解冻归档存储类型文件

    
    
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    try {
        //单次批量请求的文件数量不得超过1000
        String[] keyList = new String[]{
                "qiniu.jpg",
                "qiniu.mp4",
                "qiniu.png",
        };
        int freezeAfterDays = 7 ;
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
        for (String key : keyList) {
            batchOperations.addRestoreArchiveOps(bucket, freezeAfterDays, key);
        }
    
        Response response = bucketManager.batch(batchOperations);
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
    
        for (int i = 0; i < keyList.length; i++) {
            BatchStatus status = batchStatusList[i];
            String key = keyList[i];
            System.out.print(key + "\t");
            if (status.code == 200) {
                System.out.println("restoreAr success");
            } else {
                System.out.println(status.data.error);
            }
        }
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

### 批量混合指令操作

其实`batch`接口支持混合指令的处理，不过为了方便解析请求的回复，一般不推荐这样做。

    
    
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    
    try {
        //单次批量请求的文件数量不得超过1000
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
    
        //添加混合指令
        batchOperations.addStatOps(bucket, "qiniu.png", "qiniu.jpg");
        batchOperations.addCopyOp(bucket, "qiniu.png", bucket, "qiniu_copy1.png");
        batchOperations.addMoveOp(bucket, "qiniu2.png", bucket, "qiniu3.png");
        batchOperations.addDeleteOp(bucket, "qiniu4.png");
        batchOperations.addRestoreArchiveOps(bucket, 1, "qiniu.png");
    
    
        Response response = bucketManager.batch(batchOperations);
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
    
        for (BatchStatus status : batchStatusList) {
            if (status.code == 200) {
                System.out.println("operation success");
            } else {
                System.out.println(status.data.error);
            }
        }
    } catch (QiniuException ex) {
        System.err.println(ex.response.toString());
    }
    

## 更新镜像存储空间中文件内容

对于配置了镜像存储的空间，如果镜像源站更新了文件内容，则默认情况下，七牛不会再主动从客户镜像源站同步新的副本，这个时候就需要利用这个`prefetch`接口来主动地将空间中的文件和更新后的源站副本进行同步。调用方式很简单，指定空间和文件名即可。

    
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    
    String bucket = "your bucket name";
    String key = "your file key";
    
    Auth auth = Auth.create(accessKey, secretKey);
    BucketManager bucketManager = new BucketManager(auth, cfg);
    try {
        bucketManager.prefetch(bucket, key);
    } catch (QiniuException ex) {
        //如果遇到异常，说明更新失败
        System.err.println(ex.code());
        System.err.println(ex.response.toString());
    }
    

# 持久化数据处理

## 发送数据处理请求

对于已经保存到七牛空间的文件，可以通过发送持久化的数据处理指令来进行处理，这些指令支持七牛官方提供的指令，也包括客户自己开发的自定义数据处理的指令。数据处理的结果还可以通过七牛主动通知的方式告知业务服务器。

    
    
    String accessKey = "access key";
    String secretKey = "secret key";
    
    //待处理文件所在空间
    String bucket = "bucket name";
    //待处理文件名
    String key = "file key";
    
    Auth auth = Auth.create(accessKey, secretKey);
    
    //数据处理指令，支持多个指令
    String saveMp4Entry = String.format("%s:avthumb_test_target.mp4", bucket);
    String saveJpgEntry = String.format("%s:vframe_test_target.jpg", bucket);
    String avthumbMp4Fop = String.format("avthumb/mp4|saveas/%s", UrlSafeBase64.encodeToString(saveMp4Entry));
    String vframeJpgFop = String.format("vframe/jpg/offset/1|saveas/%s", UrlSafeBase64.encodeToString(saveJpgEntry));
    //将多个数据处理指令拼接起来
    String persistentOpfs = StringUtils.join(new String[]{
            avthumbMp4Fop, vframeJpgFop
    }, ";");
    
    //数据处理队列名称，必须
    String persistentPipeline = "mps-pipe1";
    //数据处理完成结果通知地址
    String persistentNotifyUrl = "http://api.example.com/qiniu/pfop/notify";
    
    //构造一个带指定 Region 对象的配置类
    Configuration cfg = new Configuration(Region.region0());
    //...其他参数参考类注释
    
    //构建持久化数据处理对象
    OperationManager operationManager = new OperationManager(auth, cfg);
    try {
    
        String persistentId = operationManager.pfop(bucket, key, persistentOpfs, persistentPipeline, persistentNotifyUrl, true);
        //可以根据该 persistentId 查询任务处理进度
        System.out.println(persistentId);
    
        OperationStatus operationStatus = operationManager.prefop(persistentId);
        //解析 operationStatus 的结果
    } catch (QiniuException e) {
        System.err.println(e.response.toString());
    }
    

## 查询数据处理请求状态

由于数据处理是异步处理，可以根据发送处理请求时返回的 `persistentId`
去查询任务的处理进度，如果在设置了`persistentNotifyUrl`
的情况下，直接业务服务器等待处理结果通知即可，如果需要主动查询，可以采用如上代码中的：

    
    
    OperationStatus operationStatus = operationManager.prefop(persistentId);
    //解析 operationStatus 的结果
    

# CDN相关功能

  * 文件刷新
  * 目录刷新
  * 刷新查询
  * 文件预取操作
  * 获取域名流量
  * 获取域名带宽
  * 获取日志下载链接
  * 构建时间戳防盗链访问链接

## 文件刷新

    
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    Auth auth = Auth.create(accessKey, secretKey);
    CdnManager c = new CdnManager(auth);
    
    //待刷新的链接列表
    String[] urls = new String[]{
            "http://javasdk.qiniudn.com/gopher1.jpg",
            "http://javasdk.qiniudn.com/gopher2.jpg",
            //....
    };
    try {
        //单次方法调用刷新的链接不可以超过100个
        CdnResult.RefreshResult result = c.refreshUrls(urls);
        System.out.println(result.code);
        //获取其他的回复内容
    } catch (QiniuException e) {
        System.err.println(e.response.toString());
    }
    

## 目录刷新

    
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    Auth auth = Auth.create(accessKey, secretKey);
    CdnManager c = new CdnManager(auth);
    
    //待刷新的目录列表，目录必须以 / 结尾
    String[] dirs = new String[]{
            "http://javasdk.qiniudn.com/gopher1/",
            "http://javasdk.qiniudn.com/gopher2/",
            //....
    };
    try {
        //单次方法调用刷新的目录不可以超过10个，另外刷新目录权限需要联系技术支持开通
        CdnResult.RefreshResult result = c.refreshDirs(dirs);
        System.out.println(result.code);
        //获取其他的回复内容
    } catch (QiniuException e) {
        System.err.println(e.response.toString());
    }
    

## 刷新查询

    
    
    public static void getRefreshResult() {
    	String accessKey = "";
    	String secretKey = "";
    	String url ="http://fusion.qiniuapi.com/v2/tune/refresh/list";
    	String body = "{\"urls\":[\"http://p9w3dsbag.bkt.clouddn.com/demo.html\"]}";
    	Auth auth = Auth.create(accessKey, secretKey);
    	StringMap str = auth.authorization(url, body.getBytes(), Client.JsonMime);
    	Client client = new Client();
    	try {
    		Response r = client.post(url, body.getBytes(), str);
    		System.out.println(r.reqId);
    		System.out.println(r.bodyString());
    	} catch (QiniuException e) {
    		// TODO Auto-generated catch block
    		e.printStackTrace();
    	}		
    }
    

## 文件预取

    
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    Auth auth = Auth.create(accessKey, secretKey);
    CdnManager c = new CdnManager(auth);
    
    //待预取的文件链接
    String[] urls = new String[]{
            "http://javasdk.qiniudn.com/gopher1.jpg",
            "http://javasdk.qiniudn.com/gopher2.jpg",
            //...
    };
    try {
        //单次调用方法预取的链接数量不得超过100个
        CdnResult.PrefetchResult result = c.prefetchUrls(urls);
        System.out.println(result.code);
        //获取其他的回复内容
    } catch (QiniuException e) {
        System.err.println(e.response.toString());
    }
    

## 获取域名流量

    
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    Auth auth = Auth.create(accessKey, secretKey);
    CdnManager c = new CdnManager(auth);
    
    //域名列表
    String[] domains = new String[]{
            "img1.example.com",
            "img2.example.com",
    };
    
    //开始和结束日期
    String fromDate = "2017-01-02";
    String toDate = "2017-01-10";
    //数据粒度，支持的取值为 5min ／ hour ／day
    String granularity = "day";
    
    try {
        CdnResult.FluxResult fluxResult = c.getFluxData(domains, fromDate, toDate, granularity);
        //处理得到的结果数据
        //...
    } catch (QiniuException e) {
        System.err.println(e.response.toString());
    }
    

## 获取域名带宽

    
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    Auth auth = Auth.create(accessKey, secretKey);
    CdnManager c = new CdnManager(auth);
    
    //域名列表
    String[] domains = new String[]{
            "img1.example.com",
            "img2.example.com",
    };
    
    //开始和结束日期
    String fromDate = "2017-01-02";
    String toDate = "2017-01-10";
    //数据粒度，支持的取值为 5min ／ hour ／day
    String granularity = "day";
    
    try {
        CdnResult.BandwidthResult bandwidthResult = c.getBandwidthData(domains, fromDate, toDate, granularity);
        //处理得到的结果数据
        //...
    } catch (QiniuException e) {
        System.err.println(e.response.toString());
    }
    

## 获取日志下载链接

    
    
    String accessKey = "your access key";
    String secretKey = "your secret key";
    Auth auth = Auth.create(accessKey, secretKey);
    CdnManager c = new CdnManager(auth);
    
    //域名列表
    String[] domains = new String[]{
            "img1.example.com",
            "img2.example.com",
    };
    
    //具体日期
    String logDate = "2017-01-02";
    
    try {
        CdnResult.LogListResult logListResult = c.getCdnLogList(domains, logDate);
        //处理得到的结果数据
        //...
    } catch (QiniuException e) {
        System.err.println(e.response.toString());
    }
    

## 构建时间戳防盗链访问链接

具体算法可以参考：[时间戳防盗链](https://developer.qiniu.com/fusion/kb/timestamp-hotlinking-
prevention)

    
    
    String host = "http://video.example.com";
    String fileName = "基本概括.mp4";
    
    //查询参数
    StringMap queryStringMap = new StringMap();
    queryStringMap.put("name", "七牛");
    queryStringMap.put("year", 2017);
    queryStringMap.put("年龄", 28);
    
    //链接过期时间
    long deadline = System.currentTimeMillis() / 1000 + 3600;
    
    //签名密钥，从后台域名属性中获取
    String encryptKey = "xxx";
    String signedUrl;
    try {
        signedUrl = CdnManager.createTimestampAntiLeechUrl(host, fileName,
                queryStringMap, encryptKey, deadline);
        System.out.println(signedUrl);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    

# API 参考

  * [存储 API 参考](https://developer.qiniu.com/kodo/api/3939/overview-of-the-api)
  * [融合CDN API 参考](https://developer.qiniu.com/fusion)
  * [官方数据处理 API 参考](https://developer.qiniu.com/dora)
  * [视频监控QVS API 参考](https://developer.qiniu.com/qvs)

# 常见问题

  * QiniuExeption 保留了请求响应的信息，失败情况下会抛出此异常，可以提交给我们排查问题。
  * API 的使用，demo 可以参考[单元测试 __](https://github.com/qiniu/java-sdk/blob/master/src/test)。

# 相关资源

如果您有任何关于我们文档或产品的建议和想法，欢迎您通过以下方式与我们互动讨论：

  * [技术论坛 __](http://segmentfault.com/qiniu)\- 在这里您可以和其他开发者愉快的讨论如何更好的使用七牛云服务
  * [提交工单 __](https://support.qiniu.com/tickets/new)\- 如果您的问题不适合在论坛讨论或希望及时解决，您也可以提交一个工单，我们的技术支持人员会第一时间回复您
  * [博客 __](http://blog.qiniu.com)\- 这里会持续更新发布市场活动和技术分享文章
  * [微博 __](http://weibo.com/qiniutek)
  * [常见问题 __](https://support.qiniu.com/question)

# 贡献代码

  1. Fork

  2. 创建您的特性分支 git checkout -b my-new-feature

  3. 提交您的改动 git commit -am ‘Added some feature’

  4. 将您的修改记录提交到远程 git 仓库 git push origin my-new-feature

  5. 然后到 github 网站的该 git 远程仓库的 my-new-feature 分支下发起 Pull Request

# 许可证

Copyright © 2014 qiniu.com

基于 MIT 协议发布:

  * [www.opensource.org/licenses/MIT __](http://www.opensource.org/licenses/MIT)

以上内容是否对您有帮助？