zoukankan      html  css  js  c++  java
  • 阿里云对象存储服务,OSS使用经验总结,图片存储,分页查询

    阿里云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、防盗链、自定义域名),稍微麻烦一点.
      按道理来讲,一周可以掌握绝大部分内容。
      先快速浏览文档,把项目中最需要的先实现,更多高端功能,用到的时候,再深入研究也是不错的。
      
      在遇到问题的时候,网上搜索了下,基本还没有资料,只能去官网,实现不行,就提交工单,和权威的官方技术支持人员交流。
  • 相关阅读:
    题目1009:二叉搜索树
    腾讯云API 生成Authentication Header加密字符串 C#代码示例
    《神经网络与深度学习》
    《神经网络与深度学习》第一章 使用神经网络来识别手写数字(三)- 用Python代码实现
    Rust语言的多线程编程
    C# DataTable的Select()方法不支持 != 判断
    《神经网络与深度学习》第一章 使用神经网络来识别手写数字(二)- 用梯度下降来训练学习
    C# 对多个文件进行zip压缩
    《神经网络与深度学习》:第一章 使用神经网络来识别手写数字(一)
    谷歌浏览器如何查看或获取Cookie字符串
  • 原文地址:https://www.cnblogs.com/qitian1/p/6462478.html
Copyright © 2011-2022 走看看