七牛图片多文件一次上传

         前几天在做项目时:遇到七牛图片上传,一次9张上传,但是七牛目前没有提供这种上传方式,那么怎么处理,难不成我通过for循环上传,这样有点不切合项目的需求,容易出错,想了很多办法,想起rxjava2.0可以实现list集合便利,发送数据到下游observable.那么能使用rxjava实现图片上传吗?答案是:可以的.

具体实现思路如下:

  1. 项目要求图片是有序的,用户的选择就是上传顺序,也就是图片返回路径的顺序
  2. 使用rxjava2.0的fromIterable这个操作符才给下游发送数据,使用concatMap来保证有序

思路有了,改怎么处理,也絮叨很多错误,在下面会有说明:

  1. 七牛图片中不能有中文,不能有特殊符号,且图片的类型不能是" image/* "(可以是null),这样都会引起图片上传失败
  2. 如果想实现图片覆盖上传,最好是启用七牛的策略上传模式
  3. 七牛图片上传的token有效时长和官方文档保持一致,也就是未来30m-60m,不然会有token失效的异常.
  4. 如果才用的是非策略模式上传会提示"file exist",不会提示文件上传成功.

以上是我在开发中遇到的错误具体该怎么规避,我会贴出相关代码,

下面的代码是讲文件的中文名字改正拼音,不过我建议直接使用md5,不用再引入拼音库.



import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.github.promeg.pinyinhelper.Pinyin.isChinese;
import static com.github.promeg.pinyinhelper.Pinyin.toPinyin;


public class HanZiUtils {
    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        if (m.find()) {
            return true;
        }
        return false;
    }

    public static String filterChinese(String str) {
        // 用于返回结果
        String result = str;
        boolean flag = isContainChinese(str);
        if (flag) {// 包含中文
            // 用于拼接过滤中文后的字符
            StringBuffer sb = new StringBuffer();
            // 用于校验是否为中文
            boolean flag2 = false;
            // 用于临时存储单字符
            char chinese = 0;
            // 5.去除掉文件名中的中文
            // 将字符串转换成char[]
            char[] charArray = str.toCharArray();
            // 过滤到中文及中文字符
            for (int i = 0; i < charArray.length; i++) {
                chinese = charArray[i];
                flag2 = isChinese(chinese);
                if (flag2) {// 不是中日韩文字及标点符号
                    sb.append(toPinyin(chinese).toLowerCase());
                }else{
                    sb.append(chinese);
                }
            }
            result = sb.toString();
        }
        return result;
    }
}

在用户选择完图片后使用上面的工具类判断调用方法如下:

   String name = HanZiUtils.filterChinese(name);//把中文名称转换成拼音
   /**
     * 七牛下载的路径
     */
    public static final String DOWN_LOAD_URL = "";
    /**
     * 七牛空间域名
     */
    public static final String BUKET_NAME = "";

这样就把中文名称改成拼音了.然后保存.




import android.annotation.SuppressLint;
import android.graphics.Bitmap;

import com.kalading.engineers.BuildConfig;
import com.kaopiz.kprogresshud.KProgressHUD;
import com.qiniu.android.common.Zone;
import com.qiniu.android.http.ResponseInfo;
import com.qiniu.android.storage.Configuration;
import com.qiniu.android.storage.UpCompletionHandler;
import com.qiniu.android.storage.UploadManager;
import com.qiniu.android.utils.UrlSafeBase64;

import org.json.JSONException;
import org.json.JSONObject;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;



/**
 * 七牛上传工具类
 */
public class QiniuUploadUtils {
    //七牛后台的key
    private static String AccessKey = "";
    //七牛后台的secret
    private static String SecretKey = "";

    private static final String MAC_NAME = "HmacSHA1";
    private static final String ENCODING = "UTF-8";


    /**
     * 七牛云SDK
     */
    public static Configuration configuration = new Configuration.Builder()
            //.chunkSize(512 * 1024)        // 分片上传时,每片的大小。 默认256K
            //.putThreshhold(1024 * 1024)   // 启用分片上传阀值。默认512K
            .connectTimeout(60)           // 链接超时。默认10秒
            //.useHttps(true)               // 是否使用https上传域名
            .responseTimeout(60)          // 服务器响应超时。默认60秒
            //.recorder(recorder)           // recorder分片上传时,已上传片记录器。默认null
            //.recorder(recorder, keyGen)   // keyGen 分片上传时,生成标识符,用于片记录器区分是那个文件的上传记录
            .zone(Zone.zone0)        // 设置区域,指定不同区域的上传域名、备用域名、备用IP。
            .retryMax(3)
            //.dns(null)
            .build();

    private static UploadManager uploadManager = new UploadManager(configuration);

    //unix时间戳:2065-12-31 00:00:00

    private static long delayTimes = (System.currentTimeMillis()) / 1000 + 3600L;

    public interface QiNiuCallback {
        /**
         * 上传完成
         */
        void onSuccess(String picUrls);

        /**
         * 上传失败
         */
        void onError(String msg, ResponseInfo info);
    }

    public interface QiNiuCallbackImages {

        void onComplete();

        /**
         * 上传完成
         */
        void onSuccess(List<String> picUrls);

        /**
         * 上传失败
         */
        void onError(String msg);
    }


    /**
     * 上传
     *
     * @param domain bucketName的名字
     * @param path   上传文件的路径地址
     */
    public static void uploadPic(final String domain, final String path, final String keys, String saveKey,
                                 final QiNiuCallback callBack) {
        try {
            // 1:第一种方式 构造上传策略
            JSONObject json = new JSONObject();
            json.put("deadline", delayTimes);// 有效时间为一个小时
            json.put("scope", domain);
            json.put("saveKey", saveKey);
            json.put("mimeLimit", "image/*");
            String encodeToString = UrlSafeBase64.encodeToString(json.toString().getBytes());
            byte[] sign = HmacSHA1Encrypt(encodeToString, SecretKey);
            String encodedSign = UrlSafeBase64.encodeToString(sign);
            final String uploadToken = AccessKey + ':' + encodedSign + ':'
                    + encodeToString;
            uploadManager.put(path, keys, uploadToken,
                    (key, info, response) -> {
                        if (info.isOK()) {
                            String urls = getFileUrl(domain, keys);
                            callBack.onSuccess(urls);
                        } else
                            callBack.onError(key, info);
                    }, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    
    public static void uploadPicList(final String domain, final String path, final String keys, String saveKey,
                                     final QiNiuCallback callBack) {
        try {
            // 1:第一种方式 构造上传策略
            JSONObject json = new JSONObject();
            json.put("deadline", delayTimes);// 有效时间为一个小时
            json.put("scope", domain);
            json.put("saveKey", saveKey);
            //json.put("mimeLimit", "image/*");
            String encodeToString = UrlSafeBase64.encodeToString(json.toString().getBytes());
            byte[] sign = HmacSHA1Encrypt(encodeToString, SecretKey);
            String encodedSign = UrlSafeBase64.encodeToString(sign);
            final String uploadToken = AccessKey + ':' + encodedSign + ':'
                    + encodeToString;
            uploadManager.put(path, keys, uploadToken,
                    new UpCompletionHandler() {
                        @Override
                        public void complete(String key, ResponseInfo info, JSONObject response) {
                            if (info.isOK()) {
                                String urls = getFileUrl(domain, keys);
                                callBack.onSuccess(urls);
                            } else
                                callBack.onError(key, info);
                        }
                    }, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用 HMAC-SHA1 签名方法对对encryptText进行签名
     *
     * @param encryptText 被签名的字符串
     * @param encryptKey  密钥
     * @return
     * @throws Exception
     */
    private static byte[] HmacSHA1Encrypt(String encryptText, String encryptKey)
            throws Exception {
        byte[] data = encryptKey.getBytes(ENCODING);
        // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
        SecretKey secretKey = new SecretKeySpec(data, MAC_NAME);
        // 生成一个指定 Mac 算法 的 Mac 对象
        Mac mac = Mac.getInstance(MAC_NAME);
        // 用给定密钥初始化 Mac 对象
        mac.init(secretKey);
        byte[] text = encryptText.getBytes(ENCODING);
        // 完成 Mac 操作
        return mac.doFinal(text);
    }

    /**
     * 通过key获取上传的资源文件的全路径
     *
     * @param key
     * @param domain bucketName的名字
     * @return
     */
    public static String getFileUrl(String domain, String key) {
        StringBuilder sb = new StringBuilder();
        sb.append(DOWN_LOAD_URL);
        try {
            //1:构造URL
            String encode = URLEncoder.encode(key, "UTF-8");
            sb.append(encode);
            //2:为url加上过期时间  unix时间
            sb.append("?e=").append(delayTimes);//delayTimes = 1451491200
            //3:对1 2 操作后的url进行hmac-sha1签名 secrect
            String s = sb.toString();
            byte[] bytes = HmacSHA1Encrypt(s, SecretKey);
            String sign = UrlSafeBase64.encodeToString(bytes);
            //4:将accsesskey 连接起来
            sb.append("&token=").append(AccessKey).append(":").append(sign);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }



    /**
     * 上传多图
     * @param kProgressHUD 弹窗提示
     * @param id        唯一标识
     * @param images    图片
     * @param qiNiuCallback 回调
     */
    @SuppressLint("CheckResult")
    public static void putImpToQuid(KProgressHUD kProgressHUD, final String id, final List<String> images,
                                    final QiNiuCallbackImages qiNiuCallback) {
        // 七牛返回的文件名
        final ArrayList<String> resultImagePath = new ArrayList<>();
        if (!kProgressHUD.isShowing()) {
            kProgressHUD.show();
        }
        Observable.fromIterable(images)
                .concatMap((Function<String, ObservableSource<String>>) path ->
                        Observable.create((ObservableOnSubscribe<String>) emitter -> {
                                    //int i = PhotoBitmapUtils.readPictureDegree(path);
                                    //Bitmap bitmap = ImageUtil.compressPixel2(path, i + "");
                                    //byte[] bytes = convertBitmap(bitmap);
                                    String[] split = path.split("/");
                                    String key = null;
                                    if (BuildConfig.DEBUG) {
                                        key = "test" + id + "-" + split[split.length - 1];
                                    } else {
                                        key = "release" + id + "-" + split[split.length - 1];
                                    }
                                    //key = filterChinese(key);
                                    JSONObject json = new JSONObject();
                                    json.put("deadline", delayTimes);// 有效时间为一个小时
                                    json.put("scope", KALADING_JISHI);
                                    json.put("saveKey", key);
                                    //json.put("mimeLimit", "image/jpeg");
                                    String encodeToString = UrlSafeBase64.encodeToString(json.toString().getBytes());
                                    byte[] sign = HmacSHA1Encrypt(encodeToString, SecretKey);
                                    String encodedSign = UrlSafeBase64.encodeToString(sign);
                                    final String uploadToken = AccessKey + ':' + encodedSign + ':' + encodeToString;
                                    LogUtils.debugInfo("Ly_002", key);
                                    uploadManager.put(path, key, uploadToken,
                                            (key1, info, response) -> {
                                        try {
                                            if (info.isOK() || info.error.equals("file exists")) {
                                                //String urls = getFileUrl(KALADING_JISHI, key1);
                                                String path1 = null;
                                                try {
                                                    path1 = response.getString("key");
                                                } catch (JSONException e) {
                                                    path1 = key1;
                                                }
                                                emitter.onNext(path1);
                                                emitter.onComplete();
                                                //LogUtils.debugInfo("Ly_002", urls);
                                                LogUtils.debugInfo("Ly_002", path1);
                                            } else {
                                                emitter.onError(new Throwable(info.error));
                                            }
                                        }catch (Exception e){
                                            emitter.onError(new Throwable(info.error));
                                        }}, null);
                                }
                        )).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(s -> {
                    resultImagePath.add(s);
                    // 如果全部完成,调用成功接口
                    if (resultImagePath.size() == images.size()) {
                        qiNiuCallback.onSuccess(resultImagePath);
                    }
                }, throwable -> {
                    LogUtils.warnInfo("===>", throwable.getMessage());
                    qiNiuCallback.onError(throwable.getMessage());
                });
    }

}

对于策略相关,官方将了很多,我参考的是在这里https://www.cnblogs.com/china-soft/p/4925683.html?utm_source=tuicool&utm_medium=referral.

到此项目已经开发完成,自测没问题.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值