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

背景

需求

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

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

调研

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

第一位赫然显示了百家号创作者推荐的阿里云 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​ 对象删除掉,人是偷了懒,但程序可不惯着,这回 zone 在把 FileUploadUtil​ 换回来的时候,项目直接启动失败。这咋回事啊,查看报错信息,原来是有同名 Bean!

bash 复制代码
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​ Bean 并不叫这个名字,叫什么 ossClient1​、ossClient2​,由于之前没有仔细检查,在切换了 S3 服务半个月后的今天,竟然还有文件的上传和下载在使用 OSS 服务,这把 zone 吓得出了一身冷汗,赶紧修复了代码并上报了技术总监。技术总监也不含糊,10 分钟后就定了个 P0 事件给捅上去了,20 分钟后全公司就通过邮件知道了 zone 这个名字,通宵达旦的问题修复就此展开了序幕。

复盘

经过这次 P0 事件,zone 痛定思痛,决定从根本上解决。

之前存在的技术问题

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

看着这些问题,zone 把脑袋一拍,接着就有了一个大胆的想法,不如就趁这次,设计一个「文件存储引擎」。

概念

设计

模板模式

​效果

第一版

实现内容

bash 复制代码
.
├── 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
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 对象
java 复制代码
    @Resource
    private StorageEngine storageEngine;
使用 StorageEngine 提供的文件上传下载方法

​第二版

实现内容

​使用方式

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

yml 复制代码
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 对象
java 复制代码
    @Resource
    private StorageEngine storageEngine;

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

相关推荐
韩立学长36 分钟前
【开题答辩实录分享】以《自助游网站的设计与实现》为例进行选题答辩实录分享
java·mysql·spring
ss27338 分钟前
线程池:任务队列、工作线程与生命周期管理
java·后端
不像程序员的程序媛43 分钟前
Spring的cacheEvict
java·后端·spring
SAP小崔说事儿1 小时前
在数据库中将字符串拆分成表单(SQL和HANA版本)
java·数据库·sql·sap·hana·字符串拆分·无锡sap
凌云若寒1 小时前
半导体代加工企业标签模板痛点的全景式解决方案
java
shoubepatien1 小时前
JAVA -- 11
java·后端·intellij-idea
利剑 -~2 小时前
jdk源码解析
java·开发语言
Predestination王瀞潞2 小时前
JDK安装及环境变量配置
java·linux·开发语言
谷哥的小弟2 小时前
Spring Framework源码解析——PropertiesLoaderUtils
java·后端·spring·框架·源码
JIngJaneIL2 小时前
基于java+ vue助农电商系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端