阿里云OSS-使用经验总结,存储,账号-权限,分页,缩略图,账号切换

最近项目中,需要使用云存储,最后选择了阿里云-对象存储服务OSS。
总的来说,比较简单,但是仍然遇到了几个问题,需要总结下。

1.OSS总的使用介绍
  https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_object.html?spm=5176.docoss/api-reference/abstract.6.264.Zq5Hof
  和其它各种技术类似,帮助文档常见的栏目主要是:新手指南(入门)、产品简介、API手册(讲某个接口的用法)、SDK(API的具体化,具体到编程语言)
  最佳实践、计量付费等。
  
2.服务的价值
  之前用过又拍云,听说过七牛云存储。
  总的来说,不同的云厂商做得都差不多,功能总体一致,细节有所差异。
  访问量大的公司,还是最好比较下服务的细节,测试下各家的性能。
  
  就功能来说,对象存储的云服务或者就统一叫做“云存储”,不就是:存储(上传)、下载、访问(图片,直接在网页中展示)、批量查询。
  周边功能,账户权限、文件权限等。
  
  具体到文件存储,和本地Java的API,第三方的API都类似,只不过这个时候,存储的实际物理位置在远程服务器上。
  高端一点的说法,就是“云”。
  
3.OSS和云存储
  云存储,是一种广泛的称谓。
  对象存储,文件存储,其它存储,则场景更加具体一些。
  云数据库,本质还是云存储,只是不是标准文件罢了。
  
4.API和SDK
  官方文档:https://help.aliyun.com/document_detail/oss/api-reference/abstract.html?spm=5176.docoss/sdk/java-sdk/manage_object.6.196.zg3gsg
  配置账号和密码,建立远程连接,执行操作,关闭连接。
  太多太多的SDK,都是这么几步。
  
5.遇到的几个问题
  a.账户权限

    用自己的账号,阿里云的AccessKeyId和AccessSecret,没有遇到任何问题。
但是,用别人给的账号,创建bucket和批量查询的时候,总是提示没有权限。
第1次遇到权限问题的时候,还不能确认,以为是某个地方没有配置正确。再次遇到的时候,就提交了工单,和官方的技术支持人员确定了。
不懂的问题,提交工单,阿里云的工单服务,还是很不错的。

问题原因:别人给的账号密码,是子账户,分配权限不够。

新手入门,直接使用最高权限就好。
更深入的权限管理,RAM和STS使用指南,可参考
https://help.aliyun.com/document_detail/oss/practice/ram_guide.html?spm=5176.docoss/api-reference/abstract.6.179.H0uY1x
  
  b.图片
    普通的文本文件,图片,都是文件,存储方式没啥区别。
需要注意的是,在云端,图片逻辑上是“目录”存储,实际物理层次不是,可以根据前缀prefix,来模拟目录。

图片,可以有额外的云服务,比如图片缩略图、缩放、反转、水印、防盗链等。
    目前遇到的问题是,大尺寸的高清图片,缩略图的宽度很小时,不够清晰,而官网上的缩略图案例却还比较清晰,不清楚为啥。

  c.分页访问
    官方API,是根据nextMarker(可以理解为下1页开始的id),来分页的,每页最多获得1000条。
没有提供,一次性获得所有图片的接口,只能多次迭代,拿到所有的key。

在实际需要中,后端管理系统,想分页查看图片列表,但是由于阿里云的API功能有限,只能有“上一页”和“下一页”。
类似“1 2 3 4 5 .. 100 101”这种分页展示方式,只能自己去实现。

我在做的时候,是通过多次迭代获得所有图片列表,缓存到Redis中,然后手动实现分页来做的。

6.自己封装的代码
   只贴自己的核心代码,周边的实体类和第三方jar,不再列出。
   
 

 import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List; import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile; import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.ListObjectsRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.PutObjectRequest; //阿里云对象存储服务OSS工具
public class OssUtil { // 演示,创建Bucket的时候,endpoint不能带上.
// 图片上传和简单的图片访问也可以用这个。
public static String endpoint = "http://oss-cn-hangzhou.aliyuncs.com"; // 图片处理,需要用单独的地址。访问、裁剪、缩放、效果、水印、格式转换等服务。
// public static String endpointImg = "http://img-cn-hangzhou.aliyuncs.com"; public static String accessKeyId = "hi";
public static String accessKeySecret = "hi";
public static String bucketName = "hi"; // 单例,只需要建立一次链接
private static OSSClient client = null;
// 是否使用另外一套本地账户
public static final boolean MINE = false; static {
if (MINE) {
accessKeyId = "hi2";
accessKeySecret = "hi2";
bucketName = "hi2";
endpoint = "http://oss-cn-shanghai.aliyuncs.com";
}
} //配置参数
static ClientConfiguration config() {
ClientConfiguration conf = new ClientConfiguration();
conf.setMaxConnections(100);
conf.setConnectionTimeout(5000);
conf.setMaxErrorRetry(3);
conf.setSocketTimeout(2000);
return conf;
} //客户端
public static OSSClient client() {
if (client == null) {
ClientConfiguration conf = config();
client = new OSSClient(endpoint, accessKeyId, accessKeySecret, conf);
makeBucket(client, bucketName);
}
return client;
} //创建Bucket
public static void makeBucket(String bucketName) {
OSSClient client = client();
makeBucket(client, bucketName);
} //创建Bucket
public static void makeBucket(OSSClient client, String bucketName) {
boolean exist = client.doesBucketExist(bucketName);
if (exist) {
p("The bucket exist.");
return;
}
client.createBucket(bucketName);
} //上传一个文件,InputStream
public static void uploadFile(InputStream is, String key) {
OSSClient client = client();
PutObjectRequest putObjectRequest = new PutObjectRequest(
OssUtil.bucketName, key, is);
client.putObject(putObjectRequest);
} //上传一个文件,File
public static void uploadFile(File file, String key) {
OSSClient client = client();
PutObjectRequest putObjectRequest = new PutObjectRequest(
OssUtil.bucketName, key, file);
client.putObject(putObjectRequest);
} //下载一个文件到本地
public static OSSObject downloadFile(String key) {
OSSClient client = client();
GetObjectRequest getObjectRequest = new GetObjectRequest(
OssUtil.bucketName, key);
OSSObject object = client.getObject(getObjectRequest);
return object;
} //上传某个文件到某个目录,key是自动生成的
public static String uploadFile(MultipartFile file, String dir)
throws IOException {
if (null != file && !file.isEmpty() && file.getSize() > 0) {
String fileName = UuidUtil.get32UUID()
+ "."
+ StringUtils.substringAfterLast(
file.getOriginalFilename(), ".");
String ymd = DateUtil.getDays();
String key = dir + ymd + "/" + fileName;
OssUtil.uploadFile(file.getInputStream(), key);
return key;
}
return null;
} //删除某个文件
public static void delete(String key) {
if (BackendConst.OSS_DELTE_IMG) {
try {
client().deleteObject(OssUtil.bucketName, key);
} catch (Exception e) {
e.printStackTrace();
}
}
} //创建目录,不能以斜杠“/”开头
public static void makeDir(String keySuffixWithSlash) {
OSSClient client = client();
/*
* Create an empty folder without request body, note that the key must
* be suffixed with a slash
*/
if (StringUtils.isEmpty(keySuffixWithSlash)) {
return;
}
if (!keySuffixWithSlash.endsWith("/")) {
keySuffixWithSlash += "/";
}
client.putObject(bucketName, keySuffixWithSlash,
new ByteArrayInputStream(new byte[0]));
} // 实时的分页查询
public static OssPage listPage(String dir, String nextMarker,
Integer maxKeys) {
OSSClient client = client();
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(
bucketName);
if (StringUtils.isNoneBlank(dir)) {
listObjectsRequest.setPrefix(dir);
}
if (StringUtils.isNoneBlank(nextMarker)) {
listObjectsRequest.setMarker(nextMarker);
}
if (maxKeys != null) {
listObjectsRequest.setMaxKeys(maxKeys);
}
ObjectListing objectListing = client.listObjects(listObjectsRequest); List<OSSObjectSummary> summrayList = objectListing.getObjectSummaries();
List<OssItem> itemList = summaryToItem(summrayList);
OssPage page = new OssPage(); String newxNextMarker = objectListing.getNextMarker();
page.setNextMarker(newxNextMarker);
page.setSummrayList(itemList);
return page;
} //把OSS的对象,转换成自己的。因为OSS的对象没有实现Serialiable,不能序列化。
private static List<OssItem> summaryToItem(
List<OSSObjectSummary> summrayList) {
List<OssItem> itemList = new ArrayList<OssItem>();
for (OSSObjectSummary summary : summrayList) {
OssItem item = new OssItem();
try {
BeanUtils.copyProperties(item, summary);
itemList.add(item);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
return itemList;
} //一次迭代,获得某个目录下的所有文件列表
public static List<OssItem> listAll(String dir) {
OSSClient client = client();
List<OssItem> list = new ArrayList<OssItem>();
// 查询
ObjectListing objectListing = null;
String nextMarker = null;
final int maxKeys = 1000; do {
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(
bucketName).withPrefix(dir).withMarker(nextMarker)
.withMaxKeys(maxKeys);
objectListing = client.listObjects(listObjectsRequest); List<OSSObjectSummary> summrayList = objectListing
.getObjectSummaries();
List<OssItem> itemList = summaryToItem(summrayList);
list.addAll(itemList);
nextMarker = objectListing.getNextMarker();
} while (objectListing.isTruncated());
return list;
} public static void p(Object str) {
System.out.println(str);
} public static void print(OSSException oe) {
p("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
p("Error Message: " + oe.getErrorCode());
p("Error Code: " + oe.getErrorCode());
p("Request ID: " + oe.getRequestId());
p("Host ID: " + oe.getHostId());
}
}

7.图片展示和缩略图
展示图片,需要使用单独的域名
${imgDomain}/${imgUrl}@100w @100w是缩略图语法
http://b.img-cn-hangzhou.aliyuncs.com/product/xiaolei.jpg@100w

oss.properties
oss.endpoint = http://oss-cn-hangzhou.aliyuncs.com
oss.accessKeyId=hi
oss.accessKeySecret=hi
oss.bucketName=b

oss.fileDomain=http://b.oss-cn-hangzhou.aliyuncs.com
oss.imgDomain=http://b.img-cn-hangzhou.aliyuncs.com

8.小结
  先去官网看文档,大概1天可以实现基础功能。
  图片批量查询、高端的账户权限配置、图片服务(缩略图、CDN、防盗链、自定义域名),稍微麻烦一点.
  按道理来讲,一周可以掌握绝大部分内容。
  先快速浏览文档,把项目中最需要的先实现,更多高端功能,用到的时候,再深入研究也是不错的。
  
  在遇到问题的时候,网上搜索了下,基本还没有资料,只能去官网,实现不行,就提交工单,和权威的官方技术支持人员交流。

阿里云对象存储服务,OSS使用经验总结,图片存储,分页查询的更多相关文章

  1. 阿里云对象存储 OSS 应用服务器搭建代码

    背景说明 最近做一个APP客户端图片直传阿里云OSS的服务,需要在后台开一个阿里云的OSSToken获取的接口. 阿里云官方文档地址:快速搭建移动应用直传服务. 略过移动端说明,直接看服务端的. 不是 ...

  2. 阿里云对象存储OSS与文件存储NAS的区别

    一.简介 应用场景:选择一款存储产品,面向文档数据的存取,不会涉及到数据处理. 产品选型主要从OSS和NAS中选择一款,满足文档存储的需求. 二.NAS优缺点 NAS 是一种采用直接与网络介质相连的特 ...

  3. 阿里云对象存储OSS使用 HTTPS

    一.前言 阿里云对象存储oss本身也是可以用HTTPS直接访问的,但是它本身的地址是http://***.oss-cn-hangzhou.aliyuncs.com这样的,那么如果我们想使用自己的域名, ...

  4. 阿里云对象存储OSS

    阿里云的产品种类繁多,今天让我们一起来了解下对象存储(Object Storage Service,简称OSS)吧! 什么是对象存储呢? 简单来说,对象存储OSS是阿里云提供的海量.安全和高可靠的云存 ...

  5. 阿里云对象存储OSS及CDN加速配置

    目录 十大云存储服务商 1. 登陆阿里云官网,开通对象存储服务 OSS 2. 创建存储空间 3. 绑定自定义域名 4. 配置阿里云CDN加速 5. 购买阿里云免费SSL证书 6. 阿里云CDN配置HT ...

  6. java开发之阿里云对象存储OSS和云数据库Memcache的使用

    web开发中标配:aliyun ECS(阿里云服务器),aliyun RDS(阿里云数据库),aliyun OSS(阿里云对象存储),aliyun Memcache(阿里云缓存数据库). 今天就介绍下 ...

  7. 阿里云对象存储OSS访问控制

    阿里云对象存储OSS的Android SDK提供了STS鉴权模式和自签名模式来保障移动终端的安全性. OSS可以通过阿里云STS (Security Token Service) 进行临时授权访问.交 ...

  8. Delphi阿里云对象存储OSS【支持上传文件、下载文件、删除文件、创建目录、删除目录、Bucket操作等】

    作者QQ:(648437169) 点击下载➨Delphi阿里云对象存储OSS             阿里云api文档 [Delphi阿里云对象存储OSS]支持 获取Bucket列表.设置Bucket ...

  9. 阿里云对象存储OSS支持版本管理特性

    阿里云对象存储OSS现已经全面支持“对象版本管理”特性.该功能适用于所有的存储类型以及区域.当Bucket启用该特性后,“对象版本管理”功能可以保护和恢复误删除.误覆盖的数据. 对象存储OSS“版本管 ...

随机推荐

  1. Ural 1353 Milliard Vasya&#39;s Function(DP)

    题目地址:Ural 1353 定义dp[i][j].表示当前位数为i位时,各位数和为j的个数. 对于第i位数来说.总能够看成在前i-1位后面加上一个0~9.所以状态转移方程就非常easy出来了: dp ...

  2. centos改动sshport

    vi /etc/ssh/sshd_config 找到#Port 22一段,这里是标识默认使用22port.加入一行例如以下: Port 34981 然后保存退出 然后service sshd rest ...

  3. 怎样利用WordPress创建自己定义注冊表单插件

    来源:http://www.ido321.com/1031.html 原文:Creating a Custom WordPress Registration Form Plugin 译文:创建一个定制 ...

  4. C# datagridview 删除行(转 学会、放弃博客)

    原文引入:http://zhangyanyansy.blog.163.com/blog/static/13530509720106171252978/ datagridview 删除行 2010-07 ...

  5. 洛谷P3834 可持久化线段树(主席树)模板

    题目:https://www.luogu.org/problemnew/show/P3834 无法忍受了,我要写主席树! 解决区间第 k 大查询问题,可以用主席树,像前缀和一样建立 n 棵前缀区间的权 ...

  6. scrollTop,scrollHeight,clientTop,clientHeight,offsetTop,offsetHeight实际意义 及 计算方式 附实例说明

    一.滚动距离.高度 scrollTop scrollLeft scrollHeight scrollWidth 二.相对位置.距离 offsetTop offsetLeft offsetHeight ...

  7. A Round Peg in a Ground Hole(圆与凸包)

    http://poj.org/problem?id=1584 题意:判断所给的点能不能形成凸包,并判断所给的圆是否在凸包内. 改了好几天的一个题,今天才发现是输入顺序弄错了,办过的最脑残的事情..sa ...

  8. 关于我们ajax异步请求的方法与知识

      做前端开发的朋友对于ajax异步更新一定印象深刻,作为刚入坑的小白,今天就和大家一起聊聊关于ajax异步请求的那点事.既然是ajax就少不了jQuery的知识,推荐大家访问www.w3school ...

  9. 【LuoguP5004】 专心OI - 跳房子

    首先这是一道计数类DP,那我们得先推式子,经过瞎掰乱凑,经过认真分析,我们可以得到这样的方程 F(N)=F(0)+F(1)+....+F(N-M-1) 所有F初值为1,F(1)=2 ANS=F(N+M ...

  10. sql学习--insert

    insert的四种插入方式 第一种最简单的 into 和目标列的列表是可选的 intsert [into] tableA [(col1,col2)] values(val1,val2) 第二种 ins ...