对象存储之阿里云OSS最详细的实现

Hello,大家好,我是Feri,一枚十多年的程序员,同时也是一名在读研究生,关注我,且看一个平凡的程序员如何在自我成长,只为各位小伙伴提供编程相关干货知识,希望在自我蜕变的路上,我们一起努力,努力什么时候开始都不晚,我,从现在开始做起!

零、前言

我看有小伙伴私信我说,想要快速上手阿里云的OSS对象存储,那么安排,本篇教程就是手把手带你速度掌握阿里云的OSS,实现项目中的资源存储的问题,来,学起来!

一、OSS

1.1 OSS是什么

阿里云对象存储OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,提供99.9999999999%(12个9)的数据持久性,99.995%的数据可用性。多种存储类型供选择,全面优化存储成本。

目前企业级开发,主流的资源存储解决方案,首选:云服务,阿里云-OSS、七牛云-KODO

对象存储 OSS_云存储服务_企业数据管理_存储-阿里云

1.2 OSS的存储类型

1.3 OSS的特点

提供99.9999999999%(12个9)的数据持久性,99.995%的数据可用性

1.4 OSS的应用场景

1.数据迁移

2.作为数据湖使用

3.数据存储和管理

4.数据处理平台

5.灾备与备份

1.5 OSS核心概念

1.5.1.存储空间(Bucket)

存储空间是用户用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性,包括地域、访问权限、存储类型等。用户可以根据实际需求,创建不同类型的存储空间来存储不同的数据。

  • 同一个存储空间的内部是扁平的,没有文件系统的目录等概念,所有的对象都直接隶属于其对应的存储空间。
  • 每个用户可以拥有多个存储空间。
  • 存储空间的名称在OSS范围内必须是全局唯一的,一旦创建之后无法修改名称。
  • 存储空间内部的对象数目没有限制。

存储空间的命名规范如下:

  • 只能包括小写字母、数字和短划线(-)。
  • 必须以小写字母或者数字开头和结尾。
  • 长度必须在3~63字符之间。
1.5.2 对象(Object)

对象是OSS存储数据的基本单元,也被称为OSS的文件。和传统的文件系统不同,对象没有文件目录层级结构的关系。对象由元信息(Object Meta),用户数据(Data)和文件名(Key)组成,并且由存储空间内部唯一的Key来标识。对象元信息是一组键值对,表示了对象的一些属性,比如最后修改时间、大小等信息,同时用户也可以在元信息中存储一些自定义的信息。

对象的生命周期是从上传成功到被删除为止。在整个生命周期内,除通过追加方式上传的Object可以通过继续追加上传写入数据外,其他方式上传的Object内容无法编辑,您可以通过重复上传同名的对象来覆盖之前的对象。

对象的命名规范如下:

  • 使用UTF-8编码。
  • 长度必须在1~1023字符之间。
  • 不能以正斜线(/)或者反斜线(\)开头。
1.5.3 Region(地域)

Region表示OSS的数据中心所在物理位置。用户可以根据费用、请求来源等选择合适的地域创建Bucket。一般来说,距离用户更近的Region访问速度更快。

Region是在创建Bucket的时候指定的,一旦指定之后就不允许更改。该Bucket下所有的Object都存储在对应的数据中心,目前不支持Object级别的Region设置。

1.5.4 Endpoint(访问域名)

Endpoint表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同的Region的时候,需要不同的域名。通过内网和外网访问同一个Region所需要的Endpoint也是不同的。例如杭州Region的外网Endpoint是oss-cn-hangzhou.aliyuncs.com,内网Endpoint是oss-cn-hangzhou-internal.aliyuncs.com。

1.5.5 强一致性

Object操作在OSS上具有原子性,操作要么成功要么失败,不会存在有中间状态的Object。OSS保证用户一旦上传完成之后读到的Object是完整的,OSS不会返回给用户一个部分上传成功的Object。

Object操作在OSS同样具有强一致性,用户一旦收到了一个上传(PUT)成功的响应,该上传的Object就已经立即可读,并且Object的冗余数据已经写成功。不存在一种上传的中间状态,即read-after-write却无法读取到数据。对于删除操作也是一样的,用户删除指定的Object成功之后,该Object立即变为不存在。

1.6 OSS VS 文件系统

对比项

OSS

文件系统

数据模型

OSS是一个分布式的对象存储服务,提供的是一个Key-Value对形式的对象存储服务。

文件系统是一种典型的树状索引结构。

数据获取

根据Object的名称(Key)唯一的获取该Object的内容。

虽然用户可以使用类似test1/test.jpg的名字,但是这并不表示用户的Object是保存在test1目录下面的。对于OSS来说,test1/test.jpg仅仅只是一个字符串,和a.jpg这种并没有本质的区别。因此不同名称的Object之间的访问消耗的资源是类似的。

一个名为test1/test.jpg的文件,访问过程需要先访问到test1这个目录,然后再在该目录下查找名为test.jpg的文件。

优势

支持海量的用户并发访问。

支持文件的修改,比如修改指定偏移位置的内容、截断文件尾部等。也支持文件夹的操作,比如重命名目录、删除目录、移动目录等非常容易。

劣势

OSS保存的Object不支持修改(追加写Object需要调用特定的接口,生成的Object也和正常上传的Object类型上有差别)。用户哪怕是仅仅需要修改一个字节也需要重新上传整个Object。

OSS可以通过一些操作来模拟类似文件夹的功能,但是代价非常昂贵。比如重命名目录,希望将test1目录重命名成test2,那么OSS的实际操作是将所有以test1/开头的Object都重新复制成以test2/开头的Object,这是一个非常消耗资源的操作。因此在使用OSS的时候要尽量避免类似的操作。

二、OSS的使用

2.1 准备工作

使用步骤:

1.开通OSS服务

2.创建存储空间

3.编写代码,实现OSS存储

2.2 代码实现OSS

1.依赖jar

<dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.13.0</version>
</dependency>

2.封装工具类

public class AliOssUtil {
    // Region请按实际情况填写
    public static final String ENDPOINT = "https://oss-cn-beijing.aliyuncs.com";
    // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
    public static final String KEY = "";
    public static final String KEYSECFET = "";
    //存储空间名称
    public static final String BUCKET="data215";
    //客户端对象,用于管理存储空间和文件等OSS资源,可以有一个或多个OSSClient。OSSClient可以并发使用
    public static OSS ossClient;
    static {
         ossClient= new OSSClientBuilder().build(ENDPOINT, KEY, KEYSECFET);
    }

    /**
     * 资源上传
     * @param objname 对象名称
     * @param data 数据内容
     * @param urlDate 访问地址的失效时间
     * @return 访问地址*/
    public static String upload(byte[] data,String objname,Date urlDate){
        //1.校验对象名是否存在
        if(!checkName(objname)) {
            //2.上传资源到oss服务器
            PutObjectResult result = ossClient.putObject(BUCKET, objname, new ByteArrayInputStream(data));
            //3.验证上传的结果
            if (StringUtils.hasLength(result.getETag())) {
                //4.成功,返回访问地址
                return createURL(objname, urlDate);
            }
        }
        return null;
    }
    /**
     * 生成OSS的访问地址
     * @param objname oss对象名称
     * @param date 访问地址的有效期*/
    public static String createURL(String objname, Date date){
        return ossClient.generatePresignedUrl(BUCKET,objname,date).toString();
    }
    /**
     * 验证对象名是否存在
     * @return 如果返回值为true,则文件存在,否则存储空间或者文件不存在*/
    public static boolean checkName(String objname){
        return ossClient.doesObjectExist(BUCKET,objname);
    }
    /**
     * 删除OSS文件*/
    public static boolean del(String objname){
         ossClient.deleteObject(BUCKET,objname);
         return true;
    }

3.单元测试

public class OssTest {
    @Test
    public void t1() throws Exception {
        FileInputStream fis=new FileInputStream("H:\\图片\\2.jpg");
        ByteArrayOutputStream baos=new ByteArrayOutputStream();
        byte[] data=new byte[1024];
        int len=0;
        while ((len=fis.read(data))!=-1){
            baos.write(data,0,len);
        }
        //上传
        Calendar calendar=Calendar.getInstance();
        calendar.add(Calendar.YEAR,1);
        System.err.println(AliOssUtil.upload(baos.toByteArray(),"20210830_2.jpg",calendar.getTime()));
    }
    @Test
    public void t2(){
        Calendar calendar=Calendar.getInstance();
        calendar.add(Calendar.YEAR,1);
        System.err.println(AliOssUtil.createURL("20210830_2.jpg",calendar.getTime()));
    }
}

2.3 基于OSS实现图片上传

1.依赖jar

<dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.13.0</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>

2.实现配置

spring:  
	servlet:
    multipart:
      max-file-size: 10MB #单个文件上限
      max-request-size: 50MB #一次请求的总文件上限

3.实现上传接口

 public R uploadImg(MultipartFile file) throws IOException {
        //1.校验
        if(!file.isEmpty()){
            //2.获取上传的文件名
            String fn=file.getOriginalFilename();
            //3.获取上传的文件内容
            byte[] data=file.getBytes();
            //4.生成url的有效期
            Date date= DateUtil.getTime(1);
            //4.将资源上传给OSS
            String url= AliOssUtil.upload(data,fn,date);
            //5.验证上传是否成功
            if(StringUtils.hasLength(url)){
                //6.上传成功,记录操作日志
                OssLog log=new OssLog(AliOssUtil.BUCKET,fn,url,1,new Date(),date);
                dao.save(log);
                //返回
                return R.ok(log);
            }
        }
        return R.fail();
    }

4.修复问题

1.文件名相同的问题

2.文件名过长

/**
     * 实现文件名重命名,并保证文件名的长度不超过*/
    public static String rename(String fileName){
        //1.验证长度
        if(fileName.length()>20){
            //2.如果超过,截取,从后往前截取,保留后缀名
            fileName=fileName.substring(fileName.length()-20);
        }
        //3.重命名 UUID
        return UUID.randomUUID().toString().replaceAll("-","")+"_"+fileName;
    }
public R uploadImg(MultipartFile file) throws IOException {
        //1.校验
        if(!file.isEmpty()){
            //2.获取上传的文件名
            String fn= FileUtil.rename(file.getOriginalFilename());
            //3.获取上传的文件内容
            byte[] data=file.getBytes();
            //4.生成url的有效期
            Date date= DateUtil.getTime(1);
            //4.将资源上传给OSS
            String url= AliOssUtil.upload(data,fn,date);
            //5.验证上传是否成功
            if(StringUtils.hasLength(url)){
                //6.上传成功,记录操作日志
                OssLog log=new OssLog(AliOssUtil.BUCKET,fn,url,1,new Date(),date);
                dao.save(log);
                //返回
                return R.ok(log);
            }
        }
        return R.fail();
    }

5.运行测试

好啦,今天这篇就打这啦,有任何问题可以随时进行评论交流,如果你有什么想要Feri更新的,请私聊我想要学习的内容,也可以随时关注,私信我哟,成长的路上,有你们相伴,真是人生一大幸事!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值