七牛云对象存储

2019/10/22 对象存储

前言

上一篇文章整理了阿里云对象存储相关笔记,这一片文章学习下使用七牛云对象存储,通过这篇文章你将了解到关于七牛云对象存储中几个方面知识点:

  • 七牛云文件上传封装
  • 七牛云文件下载封装
  • 七牛云资源管理模块
  • 图片鉴别
  • CDN处理等

1.1 七牛云返回魔法变量

七牛云在设置获取上传凭证的时候设置StringMap参数例如:

policyMap.put("returnBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize)}");
// 表示在上传等一系列操作中,返回的数据中包含这几项数据

可以根据七牛云的文档上设置返回其他我们需要的参数: 七牛云returnbody返回变量设置

1.2 七牛云设置callback

七牛云中还可以设置callback等异步回调:七牛云设置callback

需要回调本地方法有几个条件:

1.2.1 callbackUrl 设置:

上传成功后,七牛云向业务服务器发送 POST 请求的 URL。必须是公网上可以正常进行 POST 请求并能响应 HTTP/1.1 200 OK 的有效 URL。另外,为了给客户端有一致的体验,我们要求 callbackUrl 返回包 Content-Type 为 “application/json”,即返回的内容必须是合法的 JSON 文本。出于高可用的考虑,本字段允许设置多个 callbackUrl(用英文符号 ; 分隔),在前一个 callbackUrl 请求失败的时候会依次重试下一个callbackUrl。一个典型例子是:http:///callback;http:///callback,并同时指定下面的 callbackHost 字段。在 callbackUrl 中使用 ip 的好处是减少对 dns 解析的依赖,可改善回调的性能和稳定性。指定 callbackUrl,必须指定 callbackbody,且值不能为空

1.2.2 callbackBody设置:

上传成功后,七牛云向业务服务器发送 Content-Type: application/x-www-form-urlencoded 的 POST 请求。业务服务器可以通过直接读取请求的 query 来获得该字段,支持魔法变量和自定义变量。callbackBody 要求是合法的 url query string。例如key=$(key)&hash=$(etag)&w=$(imageInfo.width)&h=$(imageInfo.height)。如果callbackBodyType指定为application/json,则callbackBody应为json格式,例如:{“key”:”$(key)”,”hash”:”$(etag)”,”w”:”$(imageInfo.width)”,”h”:”$(imageInfo.height)”}。

1.2.3 callbackBodyType设置:

上传成功后,七牛云向业务服务器发送回调通知 callbackBody 的 Content-Type。默认为 application/x-www-form-urlencoded,也可设置为 application/json。

1.2.3 可以自己定义变量:

写法{“x:x”:{y}} 定义了x变量

1.3 七牛云上传封装

1.3.1 七牛云普通文件上传

 /**
     *  直接上传file 文件
     * @param fileParam
     * @return
     */
    public static BaseResponse uploadFile(FileParam fileParam){
        try {
            // 基于基类方法获取上传uploadManager()
            UploadManager uploadManager = getUploadManager();
            // 上传方法
            Response response = uploadManager.put(fileParam.getFile(), fileParam.getFileName(), getUpToken(fileParam.getBucket()));
            LOGGER.debug("上传七牛云反馈:{}",response.bodyString());
            return BaseResponse.success(response);
        } catch (QiniuException e) {
            LOGGER.error("文件{} 上传失败,失败原因:",fileParam.getFileName(),e.getMessage());
            return BaseResponse.faild(e.getMessage());
        }
    }

1.3.2 上传输入流

   /**
     *   通过流的方式上传文件
     * @param inputStreamParam
     * @return
     */
    public static BaseResponse uploadFileByInputStream(InputStreamParam inputStreamParam){
        UploadManager uploadManager = getUploadManager();
        try {
            Response response = uploadManager.put(inputStreamParam.getInputStream(), inputStreamParam.getFileName(), getUpToken(inputStreamParam.getBucket()),null,null);
            LOGGER.debug("上传七牛云反馈:{}",response.bodyString());
            return BaseResponse.success(response);
        } catch (QiniuException e) {
            LOGGER.error("文件{} 上传失败,失败原因:",inputStreamParam.getInputStream(),e.getMessage());
            return BaseResponse.faild(e.getMessage());
        }
    }

1.3.3 封装异步上传文件

    /**
     *   异步上传 byte[] 数据
     * @param byteParam byteParam
     * @param handler 异步处理成功调用方法(客户端需要实现这个接口中的方法)
     */
    public static BaseResponse asyncPutData(ByteParam byteParam, UpCompletionHandler handler){
        UploadManager uploadManager = getUploadManager();
        try {
            uploadManager.asyncPut(byteParam.getData(),byteParam.getFileName(),getUpToken(byteParam.getBucket()),null,null, false,handler);
            return BaseResponse.success(null);
        } catch (IOException e) {
            return BaseResponse.faild(e.getMessage());
        }
    }

1.3.4 封装callBack

    /**
     *   调用七牛云设置回调接口
     * @param fileParam 上传file文件
     * @param policy 设置回调参数
     *  "callbackUrl":         "<RequestUrlForAppServer   string>",
     *  "callbackHost":        "<RequestHostForAppServer  string>",
     *  "callbackBody":        "<RequestBodyForAppServer  string>",
     *  "callbackBodyType":    "<RequestBodyTypeForAppServer  string>",
     * @return
     */
    public  static BaseResponse putFileCallBack(FileParam fileParam,StringMap policy){
        String policyToken = getPolicyToken(policy,fileParam.getBucket());
        UploadManager uploadManager = getUploadManager();
        try {
            Response response = uploadManager.put(fileParam.getFile(), fileParam.getFileName(), policyToken);
           LOGGER.debug("上传文件回调 {}",response.bodyString());
            return BaseResponse.success(response);
        } catch (QiniuException e) {
            LOGGER.error("文件{} 上传失败,失败原因:",fileParam.getFileName(),e.getMessage());
            return BaseResponse.faild(e.getMessage());
        }
    }

1.3.5 断点续传(会在本地生成一个记录文件记录上传的一些信息)

   /**
     *   断点续传 (record 记录放在系统临时文件夹下)
     * @param fileParam 文件信息
     * @return
     */
    public static BaseResponse resumeFile(FileParam fileParam){
        String recordPath = System.getProperty("java.io.tmpdir");
        UploadManager uploadManager = getResumeUploadManager(recordPath);
        try {
            Response response = uploadManager.put(fileParam.getFile(), fileParam.getFileName(), getUpToken(fileParam.getBucket()));
            return BaseResponse.success(response);
        } catch (QiniuException e) {
            e.printStackTrace();
            LOGGER.error("断点续传出错 {}",e.getMessage());
            return BaseResponse.faild(e.getMessage());
        }
    }

1.3.6 分片上传(将上传的文件分成4M一个块,按照块来上传)

 /**
     *  使用ResumeUploader 实现分块上传
     *  通过线程异步上传,守护线程监控上传进度
     * @param fileParam 文件参数类
     */
    public static void resumeUpload(FileParam fileParam){
        String recordPath = System.getProperty("java.io.tmpdir");
        try {
            final FileRecorder fileRecorder = new FileRecorder(recordPath);
            final String recorderKey = fileRecorder.recorderKeyGenerate(fileParam.getFileName(), fileParam.getFile());
            final ResumeUploader resumeUploader = getResumeUploader(fileRecorder, fileParam);
            Thread thread = new Thread(){
                @Override
                public void run() {
                    try {
                        resumeUploader.upload();
                    } catch (QiniuException e) {
                        e.printStackTrace();
                    }
                }
            };
            thread.start();
            Thread record = new Thread(){
                @Override
                public void run() {
                    while(true){
                        showRecord("上传文件", fileRecorder, recorderKey);
                    }

                }
            };
            record.setDaemon(true);
            record.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 /**
     *   显示上传进度
     * @param pre
     * @param recorder
     * @param recordKey
     */
    private static void showRecord(String pre, FileRecorder recorder, String recordKey) {
        try {
            byte[] data = recorder.get(recordKey);
            if (data != null) {
                String jsonString = new String(data);
                if( jsonString.trim() !=""){
                    JSONObject object = JSONObject.parseObject(new String(data), JSONObject.class);
                    Long offset = object.getLong("offset");
                    Long size = object.getLong("size");
                    BigDecimal divide = new BigDecimal(offset).divide(new BigDecimal(size),4,BigDecimal.ROUND_HALF_UP);
                    if(divide.intValue() == 1){
                        recorder.del(recordKey);
                    }
                    Object modify_time1 = concurrentMap.get(offset);
                    if(modify_time1 ==null){
                        LOGGER.debug("更新一次{}",offset);
                        LOGGER.debug("{},上传进度{} %",pre,divide.multiply(new BigDecimal(100)));
                        concurrentMap.put(offset,offset);
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.error("展示进度信息报错{}",e.getMessage());
        }
    }

1.4 七牛云下载链接封装

1.4.1 获取存储空间上的下载链接

    /**
     * 生成文件的下载链接
     *
     * @param downloadParam
     * @return
     */
    public static String getDownloadFileUrl(DownloadParam downloadParam) {
        try {
            String fileName = downloadParam.getIsFileNameEncoded() ? downloadParam.getFileName()
                    : URLEncoder.encode(downloadParam.getFileName(), "UTF-8");
            String publicFileUrl =
                    String.format("%s/%s", downloadParam.getDomainOfBucket(), fileName);
            if (!downloadParam.getPrivate()) {
                //公有空间直接返回地址
                return publicFileUrl;
            }
            return getAuth().privateDownloadUrl(publicFileUrl, downloadParam.getExpireInSeconds());
        } catch (UnsupportedEncodingException e) {
            logger.error("fail to get download file url with downloadVo = {}", downloadParam.toString());
            e.printStackTrace();
        }
        return null;
    }

1.4.2 将七牛云上的多个文件作为压缩文件

/**
     * 将七牛云上的多个文件作为压缩文件 下载
     *
     * @param zipFilePath    filePath 生成压缩包路径
     * @param downloadVos
     */
    public static void compressToZipFiles(String zipFilePath, DownloadParam... downloadVos) {
        if (CollectionUtils.isEmpty(downloadVos)) {
            logger.debug("downloadVos is null");
            return;
        }
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(zipFilePath);
            ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);
            for (DownloadParam downloadVo : downloadVos) {
                String fileUrl = getDownloadFileUrl(downloadVo);
                if (fileUrl == null) {
                    continue;
                }
                ZipEntry entry = new ZipEntry(getRealFileName(downloadVo.getFileName()));
                zipOutputStream.putNextEntry(entry);
                int len = 0;
                byte[] buffer = new byte[2048];
                URL url = new URL(fileUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(10 * 1000);
                InputStream is = conn.getInputStream();
                while ((len = is.read(buffer)) != -1) {
                    zipOutputStream.write(buffer, 0, len);
                    zipOutputStream.flush();
                }
                is.close();
                zipOutputStream.close();
            }
        } catch (Exception e) {
            logger.error("fail to compress file to zip:{}", e);
        }

    }

1.4.3 生成下载二维码

例如http://p73pu13b2.bkt.clouddn.com/vedio.mp4?qrcode

1.5 七牛云资源管理模块

1.5.1 获取文件信息

/**
     *  获得文件信息
     * @param bucket 存储空间
     * @param key 文件名称
     * @return
     */
    public static FileInfo getFileInfo(String bucket,String key){
        if(StringUtils.isNullOrEmpty(bucket)){
            LOGGER.debug("bucket is not null");
            return null;
        }
        try {
            BucketManager bucketManager = getBucketManager();
            return bucketManager.stat(bucket,key);
        } catch (QiniuException e) {
            e.printStackTrace();
            LOGGER.error("获得文件信息报错");
        }
        return null;
    }

1.5.2 修改文件的mimeType类型

 /**
     *  修改文件的mimeType 类型
     * @param bucket 存储空间
     * @param key 文件key
     * @param newMimeType 文件mimeType 类型
     */
    public static BaseResponse changeMimeType(String bucket, String key, String newMimeType ){
        if(StringUtils.isNullOrEmpty(bucket)){
            LOGGER.debug("bucket is not null");
            return BaseResponse.faild("bucket is not null");
        }
        try {
            BucketManager bucketManager = getBucketManager();
            Response response = bucketManager.changeMime(bucket, key, newMimeType);
            return BaseResponse.success(response);
        } catch (QiniuException e) {
            e.printStackTrace();
            return BaseResponse.faild(e.getMessage());
        }
    }

1.5.3 复制文件

     /**
     *  相同账号下一个存储空间的文件向另一个存储空间复制
     * @param fromBucket 来自于哪一个存储空间
     * @param toBucket 复制到指定存储空间
     * @param fromKey 复制文件名称
     * @param toKey 复制到另一个空间文件名称
     * @param force 如果空间有相同名称的文件则强制覆盖
     */
    public static BaseResponse copy(String fromBucket, String toBucket, String fromKey, String toKey, boolean force){
        if(CollectionUtils.isEmpty(fromBucket,toBucket,fromKey,toKey)){
            LOGGER.error("复制参数不能为空");
            return BaseResponse.faild("复制参数不能为空");
        }
        try {
            BucketManager bucketManager = getBucketManager();
            Response response = bucketManager.copy(fromBucket, fromKey, toBucket, toKey, force);
            return BaseResponse.success(response);
        } catch (QiniuException e) {
            LOGGER.error("复制文件出错{}",e.getMessage());
            return BaseResponse.faild(e.getMessage());
        }
    }

1.5.4 移动文件

    /**
     *  相同账号下 移动不同存储空间的文件
     * @param fromBucket 来自于哪一个存储空间
     * @param toBucket 复制到指定存储空间
     * @param fromKey 复制文件名称
     * @param toKey 复制到另一个空间文件名称
     * @param force 如果空间有相同名称的文件则强制覆盖
     */
    public static BaseResponse move(String fromBucket,String fromKey,String toBucket,String toKey,boolean force){
        if(CollectionUtils.isEmpty(fromBucket,fromKey,toBucket,toKey)){
            LOGGER.error("移动文件参数不能为空");
            return BaseResponse.faild("移动文件参数不能为空");
        }
        try {
            BucketManager bucketManager = getBucketManager();
            Response response = bucketManager.move(fromBucket, fromKey, toBucket, toKey, force);
            return BaseResponse.success(response);
        } catch (QiniuException e) {
            LOGGER.error("移动文件出错{}",e.getMessage());
            return BaseResponse.faild(e.getMessage());
        }
    }

1.5.5 删除文件

   /**
     *  删除 一个bucket 下的文件
     * @param key  文件名称
     * @param bucket 存储空间
     */
    public static BaseResponse deleteFile(String bucket, String key){
        if(CollectionUtils.isEmpty(bucket,key)){
            LOGGER.error("删除文件时,bucket 和 key 不能为空");
            return BaseResponse.faild("参数异常");
        }
        try {
            BucketManager bucketManager = getBucketManager();
            Response response = bucketManager.delete(bucket, key);
            LOGGER.debug("七牛云删除反馈{}",response.bodyString());
            return BaseResponse.success(response);
        } catch (QiniuException e) {
            LOGGER.error("异常信息{}",e.getMessage());
            return BaseResponse.faild(e.getMessage());
        }
    }

1.5.6 重命名文件

    /**
     *  重命名文件
     * @param bucket
     * @param oldKey
     * @param newKey
     * @param force
     */
    public static BaseResponse rename(String bucket,String oldKey,String newKey,boolean force){
        if(CollectionUtils.isEmpty(bucket,oldKey,newKey)){
            LOGGER.error("重命名参数不合法");
            return BaseResponse.faild("参数不合法");
        }
        try {
            BucketManager bucketManager = getBucketManager();
            Response rename = bucketManager.rename(bucket, oldKey, newKey, force);
            return BaseResponse.success(rename);
        } catch (QiniuException e) {
            LOGGER.error("七牛云重命名错误{}",e.getMessage());
            return BaseResponse.faild(e.getMessage());
        }
    }

1.6 图片鉴别

1.6.1 图片鉴黄

   /**
     *  鉴黄识别
     * @param imageUrl bucket 内的图片
     * @return response
     */
    public static String identificationImagePlup(String imageUrl){
        if(StringUtils.isNullOrEmpty(imageUrl)){
            logger.debug("imageUrl is null");
            return null;
        }
        imageUrl = imageUrl+"?"+ Constant.QPULP;
        try {
            return getClient().get(imageUrl).bodyString();
        } catch (QiniuException e) {
            e.printStackTrace();
            logger.error("鉴黄识别出错了{}",e.getMessage());
        }
        return null;
    }

1.6.2 图片鉴别暴恐识别

   /**
     *  鉴别暴恐识别
     * @param imageUrl 图片路径
     * @return
     */
    public static String identificationImageTerror(String imageUrl){
        if(StringUtils.isNullOrEmpty(imageUrl)){
            logger.debug("imageUrl is null");
            return null;
        }
        imageUrl = imageUrl +"?"+Constant.QTERROR;
        try {
            return getClient().get(imageUrl).bodyString();
        } catch (QiniuException e) {
            e.printStackTrace();
            logger.error("鉴别暴恐识别出错了{}",e.getMessage());

        }
        return null;
    }

1.6.3 图片鉴别是否为政治人物

    /**
     *  鉴别是否为政治人物
     * @param imageUrl 图片路径
     * @return
     */
    public static String identificationImagePolitician(String imageUrl){
        if(StringUtils.isNullOrEmpty(imageUrl)){
            logger.debug("imageUrl is null");
            return null;
        }
        imageUrl = imageUrl +"?"+Constant.QPOLITICIAN;
        try {
            return getClient().get(imageUrl).bodyString();
        } catch (QiniuException e) {
            e.printStackTrace();
            logger.error("鉴别是否为政治人物出错了{}",e.getMessage());
        }
        return null;
    }

1.7 CDN处理

1.7.1 cdn 更新urls

    /**
     * cdn 更新urls
     * 单次方法调用刷新的链接不可以超过100个
     * @param urls 待刷新的链接列表
     * @return
     */
    public static CdnResult.RefreshResult refreshUrls(String[] urls){
        if(CollectionUtils.isEmpty(urls)){
            logger.debug("param is null");
            return null;
        }
        CdnManager cdnManager = getCdnManager();
        try {
           return cdnManager.refreshUrls(urls);
        } catch (QiniuException e) {
            logger.error("cdn 刷新连接{}",e.getMessage());
            return null;
        }
    }

1.7.2 cdn 刷新目录

    /**
     * cdn 刷新目录
     * 单次方法调用刷新的目录不可以超过10个,另外刷新目录权限需要联系技术支持开通
     * @param dirs 待刷新的目录列表,目录必须以 / 结尾
     * @return BaseResponse
     */
        public static CdnResult.RefreshResult refreshDirs(String[] dirs){
        if(CollectionUtils.isEmpty(dirs)){
            logger.debug("param is null");
            return null;
        }
        CdnManager cdnManager = getCdnManager();
        try {
           return cdnManager.refreshDirs(dirs);
        } catch (QiniuException e) {
            logger.error("cdn 刷新目录{}",e.getMessage());
            return null;
        }
    }

1.7.3 获取流量

    /**
     *   TODO 这个返回参数需要再封装
     *  获取某个时间段的流量
     * @param domains 域名列表
     * @param fromDate 时间起始
     * @param toDate 截止到什么时间
     * @param granularity 时间粒度(数据粒度,支持的取值为 5min/hour /day)
     * @return
     */
    public static Map<String, CdnResult.FluxData> getFluxData(String[] domains, String fromDate, String toDate, String granularity){
        if(CollectionUtils.isEmpty(domains)){
            logger.debug("domains is null");
            return null;
        }
        try {
            CdnManager cdnManager = getCdnManager();
            CdnResult.FluxResult fluxResult = cdnManager.getFluxData(domains, fromDate, toDate, granularity);
            return fluxResult.data;
        } catch (QiniuException e) {
            e.printStackTrace();
            logger.error("获取七牛云域名出错了{}",e.getMessage());
        }
        return null;
    }

1.7.4 获取带宽

    /**
     *  获取域名下的带宽
     * @param domains 域名列表
     * @param fromDate 起始时间
     * @param toDate 结束时间
     * @param granularity 时间粒度 数据粒度,支持的取值为 5min/hour /day)
     * @return
     */
    public static Map<String, CdnResult.BandwidthData> getBandwidthData(String[] domains, String fromDate, String toDate, String granularity){
        if(CollectionUtils.isEmpty(domains)){
            logger.debug("domains is null");
            return null;
        }
        try {
            CdnManager cdnManager = getCdnManager();
            CdnResult.BandwidthResult bandwidthData = cdnManager.getBandwidthData(domains, fromDate, toDate, granularity);
            return bandwidthData.data;
        } catch (QiniuException e) {
            e.printStackTrace();
            logger.error("获取域名下的宽带出错了{}",e.getMessage());
        }
        return null;
    }

1.7.5 获取日志下载链接

    /**
     *   获取域名下 某一天的日志下载链接
     * @param domains 域名列表
     * @param logDate 具体的某一天时间
     * @return
     */
    public static Map<String, CdnResult.LogData[]> getCdnLogList(String[] domains,String logDate){
        if(CollectionUtils.isEmpty(domains) || StringUtils.isNullOrEmpty(logDate)){
            logger.debug("param is null");
            return null;
        }
        try {
            CdnManager cdnManager = getCdnManager();
            CdnResult.LogListResult cdnLogList = cdnManager.getCdnLogList(domains, logDate);
            return cdnLogList.data;
        } catch (QiniuException e) {
            e.printStackTrace();
            logger.error("获取日志链接出错{}",e.getMessage());
        }
        return null;
    }

Search

    Table of Contents