对象存储

  • Java SDK

    最近更新时间:2017-11-17 17:52:13

    简介

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

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

    1. 提供生成客户端上传所需的上传凭证的功能
    2. 提供文件从服务端直接上传七牛的功能
    3. 提供对七牛空间中文件进行管理的功能
    4. 提供对七牛空间中文件进行处理的功能
    5. 提供七牛CDN相关的刷新,预取,日志功能

    开源

    安装

    Gradle

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

    Maven

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

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

    手动下载

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

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

    <dependencies>
        <dependency>
          <groupId>com.qiniu</groupId>
          <artifactId>qiniu-java-sdk</artifactId>
          <version>7.2.6</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>com.squareup.okhttp3</groupId>
          <artifactId>okhttp</artifactId>
          <version>3.3.1</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>com.google.code.gson</groupId>
          <artifactId>gson</artifactId>
          <version>2.6.2</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>com.qiniu</groupId>
          <artifactId>happy-dns-java</artifactId>
          <version>0.1.4</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
    库名称 库项目地址 库下载地址
    qiniu-java-sdk 链接🔗 链接🔗
    happy-dns-java 链接🔗 链接🔗
    okhttp3 链接🔗 链接🔗
    okio 链接🔗 链接🔗
    gson 链接🔗 链接🔗
    junit 链接🔗 链接🔗

    可以点击每个库的下载链接,然后选择对应的jar进行下载,然后引入到项目中。

    鉴权

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

    1. 点击注册🔗开通七牛开发者帐号
    2. 如果已有账号,直接登录七牛开发者后台,点击这里🔗查看 Access Key 和 Secret Key

    文件上传

    上传流程

    七牛文件上传分为客户端上传(主要是指网页端和移动端等面向终端用户的场景)和服务端上传两种场景,具体可以参考文档七牛业务流程

    服务端SDK在上传方面主要提供两种功能,一种是生成客户端上传所需要的上传凭证,另外一种是直接上传文件到云端。

    客户端上传凭证

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

    简单上传的凭证

    最简单的上传凭证只需要AccessKeySecretKeyBucket就可以。

    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或者回调相关的参数情况下,七牛返回给上传端的回复格式为hashkey,例如:

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

    有时候我们希望能自定义这个返回的JSON格式的内容,可以通过设置returnBody参数来实现,在returnBody中,我们可以使用七牛支持的魔法变量自定义变量

    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 请参阅创建私有队列;转码操作具体参数请参阅音视频转码;saveas 请参阅处理结果另存

    带自定义参数的凭证

    七牛支持客户端上传文件的时候定义一些自定义参数,这些参数可以在returnBodycallbackBody里面和七牛内置支持的魔法变量(即系统变量)通过相同的方式来引用。这些自定义的参数名称必须以x:开头。例如客户端上传的时候指定了自定义的参数x:userx:age分别是Stringint类型。那么可以通过下面的方式引用:

    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)}");
    

    综合上传凭证

    上面的生成上传凭证的方法,都是通过设置上传策略🔗相关的参数来支持的,这些参数可以通过不同的组合方式来满足不同的业务需求,可以灵活地组织你所需要的上传凭证。

    上传凭证额外参数

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

    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对象,在该对象中,可以指定空间对应的Zone以及其他的一些影响上传的参数。

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    UploadManager uploadManager = new UploadManager(cfg);
    //...生成上传凭证,然后准备上传
    

    其中关于Zone对象和机房的关系如下:

    机房 Zone对象
    华东 Zone.zone0()
    华北 Zone.zone1()
    华南 Zone.zone2()
    北美 Zone.zoneNa0()

    文件上传

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

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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) {
        Response r = ex.response;
        System.err.println(r.toString());
        try {
            System.err.println(r.bodyString());
        } catch (QiniuException ex2) {
            //ignore
        }
    }
    

    字节数组上传

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

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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) {
            Response r = ex.response;
            System.err.println(r.toString());
            try {
                System.err.println(r.bodyString());
            } catch (QiniuException ex2) {
                //ignore
            }
        }
    } catch (UnsupportedEncodingException ex) {
        //ignore
    }
    

    数据流上传

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

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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) {
            Response r = ex.response;
            System.err.println(r.toString());
            try {
                System.err.println(r.bodyString());
            } catch (QiniuException ex2) {
                //ignore
            }
        }
    } catch (UnsupportedEncodingException ex) {
        //ignore
    }
    

    断点续上传

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    //...生成上传凭证,然后准备上传
    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) {
            Response r = ex.response;
            System.err.println(r.toString());
            try {
                System.err.println(r.bodyString());
            } catch (QiniuException ex2) {
                //ignore
            }
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    

    解析自定义回复内容

    有些情况下,七牛返回给上传端的内容不是默认的hashkey形式,这种情况下,可能出现在自定义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;
        public String hash;
        public String bucket;
        public long fsize;
    }
    

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

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

    业务服务器验证七牛回调

    在上传策略里面设置了上传回调相关参数的时候,七牛在文件上传到服务器之后,会主动地向callbackUrl发送POST请求的回调,回调的内容为callbackBody模版所定义的内容,如果这个模版里面引用了魔法变量或者自定义变量,那么这些变量会被自动填充对应的值,然后在发送给业务服务器。

    业务服务器在收到来自七牛的回调请求的时候,可以根据请求头部的Authorization字段来进行验证,查看该请求是否是来自七牛的未经篡改的请求。具体可以参考七牛的回调鉴权

    注意:业务端服务器回调鉴权的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 = "七牛/云存储/qiniu.jpg";
    String domainOfBucket = "http://devtools.qiniu.com";
    String encodedFileName = URLEncoder.encode(fileName, "utf-8");
    String finalUrl = String.format("%s/%s", domainOfBucket, encodedFileName);
    System.out.println(finalUrl);
    

    私有空间

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

    String fileName = "七牛/云存储/qiniu.jpg";
    String domainOfBucket = "http://devtools.qiniu.com";
    String encodedFileName = URLEncoder.encode(fileName, "utf-8");
    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);
    

    资源管理

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

    获取文件信息

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

    修改文件类型

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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来覆盖那个文件的内容。

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

    复制文件副本

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

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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
    }
    

    删除空间中的文件

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

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

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

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

    获取空间文件列表

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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);
        }
    }
    

    抓取网络资源到空间

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

    资源管理批量操作

    批量获取文件信息

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

    批量修改文件类型

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

    批量删除文件

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

    批量移动或重命名文件

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

    批量复制文件

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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());
    }
    

    批量混合指令操作

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

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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");
    
        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接口来主动地将空间中的文件和更新后的源站副本进行同步。调用方式很简单,指定空间和文件名即可。

    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    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";
    
    //构造一个带指定Zone对象的配置类
    Configuration cfg = new Configuration(Zone.zone0());
    //...其他参数参考类注释
    
    //构建持久化数据处理对象
    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());
    }
    

    文件预取

    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());
    }
    

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

    具体算法可以参考:时间戳防盗链

    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 参考

    常见问题

    • QiniuExeption 保留了请求响应的信息,失败情况下会抛出此异常,可以提交给我们排查问题。
    • API 的使用,demo 可以参考单元测试

    相关资源

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

    • 技术论坛 - 在这里您可以和其他开发者愉快的讨论如何更好的使用七牛云服务
    • 提交工单 - 如果您的问题不适合在论坛讨论或希望及时解决,您也可以提交一个工单,我们的技术支持人员会第一时间回复您
    • 博客 - 这里会持续更新发布市场活动和技术分享文章
    • 微博
    • 常见问题

    贡献代码

    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 (c) 2014 qiniu.com

    基于 MIT 协议发布:

    以上内容是否对您有帮助?
  • 提交工单