文件存储引擎模块封装和使用分享

Zonezzc / 2023-08-24 / 原文

image

文件存储引擎模块封装和使用分享

背景

需求

在项目开发过程中,经常会使用到文件存储相关的功能,如:

  1. 存储发票文件
  2. 提供发票下载地址
  3. ……

调研

诸如此类的功能就需要使用到本地存储或云服务商提供的存储功能。当然,这对于开发高手的 zone 来说都是小意思,上网一查,对象存储哪家强?

image

第一位赫然显示了百家号创作者推荐的阿里云 OSS 服务,那行,就你吧,还要赶紧摸鱼等下班呢。接 API 嘛,小意思分分钟搞定,写个工具类封装一点上传下载方法那有多难。

开发

在下班点过了 1 小时之后 zone 终于写完了基于 OSS 对象存储服务封装的 FileUploadUtil.java​,并且与业务方法结合,实现了产品的需求。

身为同事的你问:「为什么是 FileUploadUtil​,光上传了那下载呢?」
zone 淡定回答:「奥,下载也在工具类里面,用 OssUtil​ 命名怕后来的同事找不到,FileUploadUtil​ 多见名知意呀。」
你问:「下载方法也在里面那为什么不用 FileUtil​ 命名工具类呢?」
zone 淡定回答:「当然是因为 FileUtil ​被之前的开发占用掉了,我这个工具类里面有云存储,当然比​ FileUtil ​更高级咯,得区分开来。」
你问:「行吧,大佬 NB,回头我直接抄了昂。」
zone 淡定回答:「随便用。」

多项目复用

半年时间匆匆流逝,曾经的的 FileUploadUtil ​工具类随着 zone 和同事娴熟的 CV 大法,在公司的项目里遍地开花。闲暇时间,每当看到新接手的项目中不是由自己 V 过去的 ​FileUploadUtil​,自豪感爆棚,我太牛了。

服务商迁移

但是好景不长,今天新来的技术总监说 OSS 的云服务太贵了,我们要「降本」,换 AWS 的 S3 对象存储吧,能免费用一年,所有项目都给我迁。随着总监的一声令下,正摸鱼的 zone 不爽了,由于公司里 80% 的项目用的都是 FileUploadUtil​,迁移的事情不出所料的落在了自己头上。得,曾经觉的自己有多牛,今天就觉的自己有多苦。活还是得干,zone 看了一下 S3 的接口文档,刷刷刷的把 FileUploadUtil ​给改了,顺便把剩下的 20% 项目里也 V 过去了新改到接入 S3 的 ​FileUploadUtil​。

技术总监验收之后说:「小伙子你很不错,降本这件事情我记你一笔。」zone 就这样亲眼看到总监真就记了一笔,再也没有下文了。半个月后,期待的升职加薪还没有发生,新的运维总监来了,直接用数据安全问题为由说服了爱国老板,又要把对象存储迁回 OSS。这回 zone 连人都没见,也不知道缘由,就看到任务系统来了个紧急迁移任务。技术总监也是够懒,标题「云存储」内容直接就三字「迁回去」。zone 看了看手里的奶茶和任务系统里的驳回选项,忍住了嘴里的爆珠还是选择嚼碎了吞下去,毕竟生活不易。

多重实现 P0 事件

就是这次,还发现了一些隐藏问题,之前的那 20% 的项目中,为了抓紧时间下班陪妹子,并没有把别的同事写的 ossClient​ 对象删除掉,程序可不惯着,直接启动失败。

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'ossClient', defined in class path resource [com/zonezzc/FileUploadUtil.class], could not be registered. A bean with that name has already been defined in class path resource [com/zonezzc/OssConfiguration.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

已与地址为 ''127.0.0.1:52291',传输: '套接字'' 的目标虚拟机断开连接

修复这个问题的同时,zone 仔细一看,这还不是最坑的,竟然还有更多的 ​ossClient​ 实现类并不叫这个名字,叫什么 ossClient1​、ossClient2​,并且虽然已经切换了有半个月了,由于之前没有关注到这种现象,截止到今天竟然还有文件的上传和下载还在使用 OSS 的服务,吓的 zone 出了一身冷汗,赶紧修复了问题并上报了技术总监。技术总监也不含糊,10 分钟后就定了个 P0 事件给捅上去了 20 分钟后全公司就通过邮件知道了 zone 这个名字。

复盘

经过这次 P0 事件,zone 痛定思痛,决定复盘并从根本上解决这类问题。

之前存在的技术问题

  1. 工具类的使用没有在公司内进行培训,导致 CV 现象和重新开发并存,没有形成统一。
  2. 没有考虑文件存储服务商变更的可能性,导致服务商变更之后不能实现快速安全切换。
  3. 没有抽象文件存储功能,​FileUploadUtil​ 工具类代码侵入性太高,没有与业务系统解耦。

zone 把脑袋一拍,有了一个大胆的想法,不如就趁这次,设计一个文件存储引擎。

概念

image

设计

模板模式

StorageEngine​效果

第一版

实现内容

.
├── java
│   └── com
│       └── zonezzc
│           └── storage
│               └── engine
│                   ├── StorageApplication.java
│                   ├── config
│                   │   ├── CosStorageEngineConfig.java
│                   │   ├── KodoStorageEngineConfig.java
│                   │   └── OssStorageEngineConfig.java
│                   ├── core
│                   │   ├── AbstractStorageEngine.java
│                   │   ├── StorageEngine.java
│                   │   └── context
│                   │       ├── DeleteFileContext.java
│                   │       ├── DownloadUrlContext.java
│                   │       ├── ReadFileContext.java
│                   │       └── StoreFileContext.java
│                   ├── cos
│                   │   └── CosStorageEngine.java
│                   ├── kodo
│                   │   └── KodoStorageEngine.java
│                   ├── oss
│                   │   └── OssStorageEngine.java
│                   └── utils
│                       └── FileUtils.java
└── resources
    ├── application-dev.yml
    ├── application-prod.yml
    ├── application-test.yml
    └── application.yml

# application.yml
storage:
  engine:
    oss:
      endpoint: oss-cn-shanghai.aliyuncs.com
      accessKeyId: xxxxxxxxxxxxxxxxxxxxxxxx
      accessKeySecret: xxxxxxxxxxxxxxxxxxxxxxxx
      bucketName: zonezzc
    cos:
      secretId: xxxxxxxxxxxxxxxxxxxxxxxx
      secretKey: xxxxxxxxxxxxxxxxxxxxxxxx
      region: ap-shanghai
      bucketName: zonezzc-1253326811
    kodo:
      region: z2
      accessKey: xxxxxxxxxxxxxxxxxxxxxxxx
      secretKey: xxxxxxxxxxxxxxxxxxxxxxxx
      bucketName: zonezzc

使用方式

CV 大法,在项目中把所有代码复制粘贴,人工适配

注入 StorageEngine 对象
    @Resource
    private StorageEngine storageEngine;
使用 StorageEngine 提供的文件上传下载方法

image​第二版

实现内容

image​使用方式

  1. 引入对应的文件存储引擎依赖
  2. 根据提示配置 applecation.yml
  3. 注入 StorageEngine ​对象
  4. 使用 ​StorageEngine​ 提供的文件上传下载方法
引入依赖
<dependency>
    <groupId>com.zonezzc</groupId>
    <artifactId>storage-engine-oss</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
配置引擎需要的信息

image

com:
  zonezzc:
    storage:
      engine:
        oss:
          access-key-id: xxxxxxxxxxxxxxxxxxxxxxxx
          access-key-secret: xxxxxxxxxxxxxxxxxxxxxxxx
          endpoint: oss-cn-shanghai.aliyuncs.com
          bucket-name: zonezzc
          auto-create-bucket: true

注入 StorageEngine 对象
    @Resource
    private StorageEngine storageEngine;

使用 StorageEngine 提供的文件上传下载方法

image