**关于阿里云oss图片批量上传问题解析**
2017-03-31 10:50
357 查看
关于阿里云oss图片批量上传问题解析
背景
最近在项目开发过程中遇到的问题,消耗了比较久的时间,过程曲折,虽然最终达到目的,但是鉴于各种常用的云数据在对象存储方面大同小异,所以记录一下。
理一下思路:
我们在调用第三方对象存储API的时候,通常需要解决以下问题:
通用性
参数
阅读阿里云的API以及SDK文档,找关键字,事实证明这样真不好,发现几个重要的字段:Endpoint、Bucket、STS、OssClient、KeyObject、Meta、data、OSSAsyncTask,我理解就是拿一个地址一层层找文件,完整的url长这样:
“http://” +BucketName+ “.” +END_POINT + “/” + ObjectKey
数据处理
准备工作
代码片段:
AliAuthRes代码:
UploadListener代码:
总结:期间走了不少弯路,事实证明真的要仔细看文档,
补充一点:上传结束后,如果有图片上传失败,用户选择不重试,记得删除已经上传成功的图片,
毕竟是垃圾文件,耗空间,而空间是要钱的。吸取教训,以后用百度云什么的就可以参考了。
背景
最近在项目开发过程中遇到的问题,消耗了比较久的时间,过程曲折,虽然最终达到目的,但是鉴于各种常用的云数据在对象存储方面大同小异,所以记录一下。
理一下思路:
我们在调用第三方对象存储API的时候,通常需要解决以下问题:
1.考虑通用性 2.在调用API过程中需要的参数. 3.如何处理数据(使用方式、成功与失败) 4.调用过程中的异常处理
通用性
在整个App中好几个界面都涉及到图片上传,根据每个界面上传的特点,将其整合成了一个工具类。
参数
阅读阿里云的API以及SDK文档,找关键字,事实证明这样真不好,发现几个重要的字段:Endpoint、Bucket、STS、OssClient、KeyObject、Meta、data、OSSAsyncTask,我理解就是拿一个地址一层层找文件,完整的url长这样:
“http://” +BucketName+ “.” +END_POINT + “/” + ObjectKey
1.EndPoint:Oss区域地址 Bucket:里面的容器,放文件(Object)的地方,这里提一下bucketname 2.KeyObject:上传文件在oss中的名称 3.Meta:上传文件的自我描述,算是标记,为name-value类型 data:这个就是字面上的意思 4.data:字面上的意思 5.STS:鉴权方式,关于这个方式的安全性以及涉及到的参数及其含义详见OSS文档。 6.OssClient:看到Client其实你就能联想到网络请求 7.OSSAsyncTask:异步任务,最终我就是差点当在这里, 看漏一句话:该任务属于安全上传,适用于高并发执行...我居然写到末尾把它硬生生写成同步,捂脸...
数据处理
图片上传过程中,每张图片的上传进度,成功与失败的数据返回处理, 上传过程中可能会出现的问题:比如说正在上传的图片被用户删了之类的等等。
准备工作
1.下载jar包:aliyun-oss-sdk-android-2.3.0.jar、okhttp-3.x.x.jar 和 okio-1.x.x.jar,加入libs中 2.设置权限:在manifests.xml中加入: <uses-permission android:name="android.permission.INTERNET"></uses-permission> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
代码片段:
public class PictureUpload { private static PictureUpload pictureUpload; /** * 上传client */ OSS oss; /** * 上传次数 */ int number; /** * 成功上传(本地文件名作为key,阿里云地址为value) */ Map<String, Object> success = new HashMap<>(); /** * 失败上传(返回失败文件的本地地址) */ List<String> failure = new ArrayList<>(); /** * 上传回调 */ UploadListener uploadListener; /** * 上传任务列表 */ List<OSSAsyncTask> ossAsyncTasks = new ArrayList<>(); /** * 自动更新Token */ OSSCredentialProvider credetialProvider = new OSSFederationCredentialProvider() { @Override public OSSFederationToken getFederationToken() { try { //阿里鉴权请求 AliAuthRes res = new JsonDefaultRequest(AliAuthRes.class).POST("", null, SharePerefrence.getTokenKey()); return new OSSFederationToken(res.getAccessK ca3d eyId(), res.getAccessKeySecret(), res.getSecurityToken(), res.getExpiration()); } catch (Exception e) { e.printStackTrace(); } return null; } }; /** * 单列模式 * * @return */ public static PictureUpload getInstance() { if (pictureUpload == null) { pictureUpload = new PictureUpload(); } return pictureUpload; } /** * 构造函数 */ public PictureUpload() { ClientConfiguration conf = new ClientConfiguration(); conf.setConnectionTimeout(20 * 1000); // 连接超时,默认15秒 conf.setSocketTimeout(20 * 1000); // socket超时,默认15秒 conf.setMaxConcurrentRequest(9); // 最大并发请求书,默认5个 conf.setMaxErrorRetry(3); // 失败后最大重试次数,默认2次 oss = new OSSClient(MyApplication.getInstance(), HttpConfig.END_POINT, credetialProvider, conf); } /** * 添加上传任务 * * @param paths * @param listener */ public void setDatas(final List<String> paths, UploadListener listener) { this.uploadListener = listener; ossAsyncTasks.clear(); number = 1; success.clear(); failure.clear(); for (String path : paths) { final File file = new File(path); /** * 阿里云上文件名称 */ String objectKey = UUID.randomUUID().toString() + "_" + SharePerefrence.getTokenKey() + ".jpg"; /** * 用户自定义参数 */ ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.addUserMetadata("filePath", file.getPath()); objectMetadata.addUserMetadata("fileName", file.getName()); objectMetadata.addUserMetadata("objectKey", objectKey); PutObjectRequest put = new PutObjectRequest(HttpConfig.BUCKET_NAME, objectKey, file.getPath()); put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() { @Override public void onProgress(PutObjectRequest putObjectRequest, long currentSize, long totalSize) { } }); /** * 上传任务 */ OSSAsyncTask task; task = oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() { @Override public void onSuccess(PutObjectRequest putObjectRequest, PutObjectResult putObjectResult) { number++; String aliPath = formAliPath(putObjectRequest); success.put(putObjectRequest.getMetadata().getUserMetadata().get("fileName"), aliPath); if (number == paths.size()) { uploadListener.onUploadComplete(success, failure); } } @Override public void onFailure(PutObjectRequest putObjectRequest, ClientException e, ServiceException e1) { number++; failure.add(putObjectRequest.getMetadata().getUserMetadata().get("filePath")); if (number == paths.size()) { uploadListener.onUploadComplete(success, failure); } } }); /** * 添加到上传记录 */ ossAsyncTasks.add(task); } } /** * 添加上传任务 * @param paths key:本地地址 * @param listener */ public void setDatas(final Map<String,Picture>paths, final UploadListener listener){ this.uploadListener=listener; number=1; success.clear(); failure.clear(); Iterator iterator = paths.keySet().iterator(); while (iterator.hasNext()){ final String path= (String) iterator.next(); final Picture picture=paths.get(path); File file=new File(path); String objectKey=UUID.randomUUID().toString()+"_"+SharePerefrence.getTokenKey()+".jpg"; ObjectMetadata objectMetadata=new ObjectMetadata(); objectMetadata.addUserMetadata("fileTag",picture.getTag()); objectMetadata.addUserMetadata("fileName",file.getName()); objectMetadata.addUserMetadata("filePath",file.getPath()); objectMetadata.addUserMetadata("objectKey", objectKey); final PutObjectRequest put=new PutObjectRequest(HttpConfig.BUCKET_NAME,objectKey,file.getPath()); put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() { @Override public void onProgress(PutObjectRequest putObjectRequest, long l, long l1) { //上传进度回调 } }); OSSAsyncTask task; task=oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() { @Override public void onSuccess(PutObjectRequest putObjectRequest, PutObjectResult putObjectResult) { number++; String aliPath = formAliPath(putObjectRequest); picture.setUrl(aliPath); picture.setName(putObjectRequest.getMetadata().getUserMetadata().get("fileName")); success.put(putObjectRequest.getMetadata().getUserMetadata().get("filePath"),picture); if (number==paths.size()){ uploadListener.onUploadComplete(success,failure); } } @Override public void onFailure(PutObjectRequest putObjectRequest, ClientException e, ServiceException e1) { number++; failure.add(putObjectRequest.getMetadata().getUserMetadata().get("filePath")); if (number==paths.size()){ uploadListener.onUploadComplete(success,failure); } } }); ossAsyncTasks.add(task); } } public void cancleTasks() { for (OSSAsyncTask task : ossAsyncTasks) { if (task.isCompleted()) { }else { task.cancel(); } } } /** * 拼接远程访问地址 * * @param putObjectRequest * @return */ private String formAliPath(PutObjectRequest putObjectRequest) { return "http://" + putObjectRequest.getBucketName() + "." + HttpConfig.END_POINT + "/" + putObjectRequest.getObjectKey(); }
1.为了方便管理里面的并发任务,我把所有任务都扔到一个list之中, 目前能力下只能想出这个办法,里面的setdatas()方法: 是因为项目中有的图片上传需要打标记区分。 2.上传成功之后要求需要返给服务器文件名和url,当然都有不同的要求。 3.关于进度更新ui问题:我还需要测试一下上传的速率, 采用handler方法去解决。 4.突然想到到失败后重新上传的次数问题, 个人直觉是三次都失败之后才会返回失败结果,结果还是测了之后再说。
AliAuthRes代码:
public class AliAuthRes extends ResponseMsg implements BaseModel { /** * 鉴权key */ String accessKeyId; /** * 鉴权secret */ String accessKeySecret; /** * 鉴权token */ String securityToken; /** * 鉴权时间戳 */ String expiration; public String getAccessKeyId() { return accessKeyId; } public void setAccessKeyId(String accessKeyId) { this.accessKeyId = accessKeyId; } public String getAccessKeySecret() { return accessKeySecret; } public void setAcessKeySecret(String accessKeySecret) { this.accessKeySecret = accessKeySecret; } public String getSecurityToken() { return securityToken; } public void setSecurityToken(String securityToken) { this.securityToken = securityToken; } public String getExpiration() { return expiration; } public void setExpiration(String expiration) { this.expiration = expiration; } @Override public <T extends BaseModel> T build() { AliAuthRes aliAuthRes=new AliAuthRes(); aliAuthRes.setSuccess(true); return (T) aliAuthRes; } }
UploadListener代码:
public interface UploadListener { /** * 上传完成 * * @param success * @param failure */ void onUploadComplete(Map<String, Object> success, List<String> failure); }
总结:期间走了不少弯路,事实证明真的要仔细看文档,
补充一点:上传结束后,如果有图片上传失败,用户选择不重试,记得删除已经上传成功的图片,
毕竟是垃圾文件,耗空间,而空间是要钱的。吸取教训,以后用百度云什么的就可以参考了。
相关文章推荐
- 关于IOS端图片上传到WEB端,JAVA解析图片并保存的问题(备忘)
- 关于图片批量上传的问题
- file does not exist 阿里云OSS图片上传遇到的问题
- 关于kindeditor编辑器批量上传图片不显示添加图片按钮的问题
- 关于百度ueditor图片上传到OSS问题解决
- 关于android阿里云上传图片报错初始化错误的问题
- 关于ajax 上传图片 enctype="multipart/form-data"的问题
- http关于图片压缩直接上传问题(采用mina包)
- 关于安卓调用C#的WebService上传图片问题(不使用ksoap2)
- 关于在线编辑器Kindeditor上传图片报错的问题:没有权限
- 关于UEditor在struts2下图片上传问题
- 关于ios5上的浏览器无法上传图片的问题
- 关于FCKeditor 上传图片名为中文的问题
- 关于百度world 编辑器改变上传图片的保存路径图片不显示的问题
- 关于ueditor的图片上传时返回图片存储路径的问题
- 图片上传 关于压缩的问题
- 关于V5.7 正式版 自定义字段图片上传无法点击选择的问题解决!
- jsp+servlet+javabean中关于图片上传的问题
- 关于EwebEeditor 不能上传图片问题解决方法
- kindeditor图片批量上传失败问题