阿里雲對象存儲服務,OSS使用經驗總結,圖片存儲,分頁查詢

阿里雲OSS-使用經驗總結,存儲,帳號-權限,分頁,縮略圖,帳號切換html


最近項目中,須要使用雲存儲,最後選擇了阿里雲-對象存儲服務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、防盜鏈、自定義域名),稍微麻煩一點.   按道理來說,一週能夠掌握絕大部份內容。   先快速瀏覽文檔,把項目中最須要的先實現,更多高端功能,用到的時候,再深刻研究也是不錯的。      在遇到問題的時候,網上搜索了下,基本尚未資料,只能去官網,實現不行,就提交工單,和權威的官方技術支持人員交流。
相關文章
相關標籤/搜索