OSS(Object Storage Service)即对象存储服务

OSS将数据文件以对象/文件(Object)的形式上传到存储空间(Bucket)中。OSS提供的是一个Key-Value键值对形式的对象存储服务。用户可以根据Object的名称(Key)唯一地址获取该Object的内容。OSS只能对文件进行读写(删)操作。

Object

对象由元信息(Object Meta)、用户数据(Data)和文件名(Key)组成。

对象由存储空间内部唯一的Key来标识。对象元信息是一个键值对,表示了对象的一些属性,比如最后修改时间、大小等信息,同时用户也可以在元信息中存储一些自定义的信息。

对象的生命周期是从上传成功到被删除为止。在整个生命周期内,对象信息不可变更,重复上传同名的对象会覆盖之前的对象。因此,OSS不支持修改文件的部分内容等操作。

Bucket

存储空间(Bucket)是您用于存储对象(Object)的容器,同一个存储空间的内部是扁平的,没有文件系统的目录等概念,所有对象都直接隶属于其对应的存储空间。但一个用户可以拥有多个Bucket。

强一致性

Object操作在OSS上具有原子性,操作要么成功要么失败。

OSS保证用户一旦上传完成之后读到的Object是完整的,OSS不会返回给用户一个部分上传成功的Object。

文件系统

虽然用户可以使用类似test1/test.jpg的名字,但是这并不表示用户的Object是保存在test1目录下面的。对于OSS来说,test1/test.jpg仅仅只是一个字符串,和a.jpg这种并没有本质的区别。这点和树型文件系统不同。

对于OSS来说,可以通过一些操作来模拟类似的功能,但是代价非常昂贵。比如重命名目录,希望将test1目录重命名成test2,那么OSS的实际操作是将所有以test1/开头的Object都重新复制成以test2/开头的Object,这是一个非常消耗资源的操作。

但另外一方面,OSS能支持高并发访问,建议对OSS尽量只做新建文件、删除文件、读取文件这几种操作,优先用来存储海量的非结构化数据,比如图片、视频、文档等。

调用API

  1. 获取AccessKey

    • 用户登录名称
    • AccessKey ID
    • AccessKey Secret
  2. 调用

    参见 官方文档 JavaSDK

    创建存储空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket"

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

try {
// 创建存储空间。
ossClient.createBucket(bucketName);

//异常处理
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}

流式文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
String objectName = "exampledir/exampleobject.txt";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

try {
String content = "Hello OSS";
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}

几个部分

  1. 确定endpoint(端点),accessKeyId,accessKeySecret;确定bucket名
    这个步驟可以把常量定义在配置文件中,便于重复调用
  2. 通过OSSBuilder.build实例化OSS实例对象
  3. 调用相应方法(各种增删改查)
  4. ossClient.shutdown() 关闭OSS实例

应用

使用版本 aliyun-sdk-oss.version>3.1.0</aliyun-sdk-oss.version>
两个必须依赖(适用于jdk8及以下,以上略有改动)

1
2
3
4
5
6
7
8
9
10
11
12
13
    <dependencies>
<!-- 阿里云oss-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<!-- 日期工具-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
</dependencies>

上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Service
public class OssServiceImpl implements OssService {
@Override
public String uploadFileAvatar(MultipartFile file) {

String endPoint = ConstantPropertiesUtils.END_POINT;
String accessKeyId = ConstantPropertiesUtils.ACCESS_KEY_ID;
String accessKeySecret = ConstantPropertiesUtils.ACCESS_KEY_SECRET;
String bucketName = ConstantPropertiesUtils.BUCKET_NAME;
//String url;
try {
//uuid
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
// 上传文件流。
InputStream inputStream = file.getInputStream();
//调用oss方法实现上传
//其中第二个参数是上传的路径/文件名
//可以根据路径按日期分类
//获取当前日期,使用joda
String dateTime = new DateTime().toString("yyyy/MM/dd");
String fileName = dateTime+"/"+uuid+file.getOriginalFilename();
ossClient.putObject(bucketName, fileName, inputStream);
// 关闭OSSClient。
ossClient.shutdown();
//获取url地址
return "https://" + bucketName + "." + endPoint + "/" + fileName;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}