oss入门学习
最近学习oss,顺便整理了一下java sdk相关的随笔,看看就行。
什么是oss
阿里云对象存储OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,提供99.9999999999%(12个9)的数据持久性,99.995%的数据可用性。多种存储类型供选择,全面优化存储成本。
oss中重要的对象(Bucket、Object、Region、Endpoint和AccessKey)
bucket(存储空间)
Bucket是用户用来管理所存储Object的储物空间。每个用户可以拥有多个Bucket。Bucket的名称在OSS的范围内必须是全局唯一的,一旦创建之后无法修改名称。Bucket内部的Object数目是没有限制的。用户可以简单的把Bucket理解为本地电脑的一个文件夹。
Bucket的命名规范:Bucket名称只能包括小写字母、数字和短横线(-);必须以小写字母或者数字开头;长度必须在3到63字节之间。
Object(存储对象)
Object是OSS存储数据的基本单元,称为OSS对象,也被称为OSS的文件。用户可以把Object简单理解为文件夹中的文件。
Bucket对用户来说是一个管理Object的单元,所有的Object都必须隶属于某个Bucket。Bucket有一些属性用来控制Region、Object的访问控制、Object的生命周期等,这些属性是作用在该Bucket下所有的Object上的,因此用户可以灵活创建不同的Bucket来完成不同的管理功能。
Object的命名规范如下:使用的是UTF-8编码;长度必须在1到1023字节之间;不能以“/”或者“”开头;Object的名称是区别大小写的。
Region(存储地域)
Region表示OSS的数据中心所在的区域,经纬度位置。用户可以根据费用、请求来源等综合选择数据存储的Region。一般来说,距离用户更近的Region访问速度更快。目前已经开通的Region有杭州、上海、深圳、北京、青岛、香港、美国和新加坡。
Region是在创建Bucket的时候指定的,一旦指定之后就不允许更改,该Bucket下所有的Object都存储在对应的数据中心,目前不支持Object级别的Region设置。Region大家可以理解为OSS的存储地域。
Endpoint(访问域名)
Endpoint表示OSS对外服务的访问域名。OSS以HTTP REST API的形式对外提供服务,当访问不同Region的时候,需要不同的域名。通过内网和外网访问同一个Region所需要的Endpoint也是不同的。
例如杭州地区的url:
外网Endpoint:https://oss-cn-hangzhou.aliyuncs.com
内网Endpoint:https://oss-cn-hangzhou-internal.aliyuncs.com
AccessKey(密钥)
关于AccessKey,AccessKey简称AK,指的是访问身份验证中用到的AccessKeyId和AccessKeySecret。OSS通过使用AccessKeyId和AccessKeySecret对称加密的方法来验证某个请求的发送者身份。AccessKeyId用于标示用户,AccessKeySecret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,其中AccessKeySecret必须保密。AccessKey可以理解为OSS被访问时验证身份的钥匙。
代码演示流程
常量
// Endpoint以杭州为例,其它Region请按实际情况填写。
public static final String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
public static final String accessKeyId = "<yourAccessKeyId>";
public static final String accessKeySecret = "<yourAccessKeySecret>";
//存储空间名 全剧唯一
public static final String bucketName = "yourBucketName";
// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
public static final String objectName = "<yourObjectName>";
安装
<!--引入依赖sdk-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
创建oss对象
/**
* 创建OSSCLient对象
* @param endpoint 访问域名
* @param accessKeyId 密钥id
* @param accessKeySecret 密钥
*/
public void createOss(String endpoint, String accessKeyId, String accessKeySecret) {
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
}
创建存储空间
/**
* 创建存储空间
* @param ossClient oss对象
* @param bucketName 存储空间名
*/
public void createBucket(OSS ossClient, String bucketName) {
ossClient.createBucket(bucketName);
}
文件上传
这里主要学习的是分片上传,因为安全性较高。
分片上传:其原理其实就是在客户端将文件分割成多个小的分片,然后再将这些分片一片一片的上传给服务端,服务端拿到所有分片后再将这些分片合并起来还原成原来的文件。那服务端怎么知道我合并出来的文件是否和服务端上传的文件完全一样呢?这就需要用到文件的MD5值了。文件的MD5值就相当于是这个文件的“数字指纹”,只有当两个文件内容完全一样时,他们的MD5值才会一样。所以在上传文件前,客户端需要先计算出文件的MD5值,并且把这MD5值传递给服务端。服务端在合并出文件后,在计算合并出的文件的MD5值,与客户端传递过来的进行比较,如果一致,则说明上传成功,若不一致,则说明上传过程中可能出现了丢包,上传失败。
后续准备学习断点上传。
断点续传其实是利用分片上传的特性,上次上传中断时,已经有部分分片已上传到服务端,这部分就可以不用重复上传了。
分片上传(Multipart Upload)分为以下三个步骤:
1.初始化一个分片上传事件。
调用ossClient.initiateMultipartUpload方法返回OSS创建的全局唯一的uploadId。
2.上传分片。
调用ossClient.uploadPart方法上传分片数据。
说明
对于同一个uploadId,分片号(PartNumber)标识了该分片在整个文件内的相对位置。如果使用同一个分片号上传了新的数据,则OSS上该分片已有的数据将会被覆盖。
OSS将收到的分片数据的MD5值放在ETag头内返回给用户。
OSS计算上传数据的MD5值,并与SDK计算的MD5值比较,如果不一致则返回InvalidDigest错误码。
3.完成分片上传。
所有分片上传完成后,调用ossClient.completeMultipartUpload方法将所有分片合并成完整的文件。
/**
* 分片上传
* @param ossClient oss对象
* @param bucketName 存储空间
* @param objectName 存储对象
* @throws IOException
*/
public void upload(OSS ossClient, String bucketName, String objectName) throws IOException {
//创建InitiateMultipartUploadRequest对象
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);
// 如果需要在初始化分片时设置文件存储类型,请参考以下示例代码。
// ObjectMetadata metadata = new ObjectMetadata();
// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
// request.setObjectMetadata(metadata);
//初始化分片
InitiateMultipartUploadResult uploadResult = ossClient.initiateMultipartUpload(request);
//返回uploadId,它是分片上传事件的唯一标识,可以根据该uploadId发起相关的操作,比如取消分片上传、查询分片上传等。
String uploadId = uploadResult.getUploadId();
//partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
List<PartETag> partETags = new ArrayList<>();
//每个分片的大小,用于计算文件有多少个分片,单位为字节。
final long partSize = 5 * 1024 *1024L; //5MB
//填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
final File sampleFile = new File("你需要上传的文件的本地绝对路径");
long fileLength = sampleFile.length();
int partCount = (int) (fileLength / partSize);
if(fileLength % partSize != 0) {
partCount++;
}
//遍历分片上传
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 ==partCount) ? (fileLength - startPos) : partSize;
InputStream inputStream = new FileInputStream(sampleFile);
//跳过已经上传的分片
inputStream.skip(startPos);
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(objectName);
uploadPartRequest.setInputStream(inputStream);
uploadPartRequest.setUploadId(uploadId);
//设置分片大小。除了最后一个分片没有大小限制,其他分片最小为100KB。
uploadPartRequest.setPartSize(curPartSize);
//设置分片号。每一个上传的分片都有一个分片号,取值范围为1~10000,如果超出这个范围,OSS将返回InvalidArgument错误码。
uploadPartRequest.setPartNumber(i + 1);
// 每个分片不需要按顺序上传,甚至可以在不同客户端上传,OSS会按照分片号排序组成完整的文件。
UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
// 每次上传分片之后,OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
partETags.add(uploadPartResult.getPartETag());
//创建CompleteMultipartUploadRequest对象。
//在执行完成分片上传操作时,需要提供所有有效的partETags。OSS收到提交的partETags后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,哦时尚将把这些分片组合成一个完整的文件。
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
// 如果需要在完成文件上传的同时设置文件访问权限,请参考以下示例代码。
// completeMultipartUploadRequest.setObjectACL(CannedAccessControlList.PublicRead);
//完成上传。
CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
System.out.println(completeMultipartUploadResult.getETag());
}
}
文件下载
这里主要是通过生成有期限的URL,然后访客自行去下载。
/**
* 生成有期限的URL
* @param ossClient oss对象
* @param bucketName 存储空间
* @param objectName 存储对象
* @return
*/
public URL ossUrl(OSS ossClient, String bucketName, String objectName) {
//设置Url过期时间。
Date date = new Date(new Date().getTime() + 3600 * 1000);
//生成以GET方法访问的签名Url,访客可以直接通过浏览器访问相关内容。
URL url = ossClient.generatePresignedUrl(bucketName, objectName, date);
return url;
}