026-从零搭建微服务-文件服务(二)

写在最前

如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。

源码地址(后端):https://gitee.com/csps/mingyue

源码地址(前端):https://gitee.com/csps/mingyue-ui

文档地址:https://gitee.com/csps/mingyue/wikis

OSS 基础表设计

1. OSS对象存储表

DROP TABLE IF EXISTS sys_oss;
CREATE TABLE sys_oss (oss_id           BIGINT(20)        NOT NULL                   COMMENT 'OSS对象ID',file_name        VARCHAR(255)      NOT NULL DEFAULT ''        COMMENT '文件名',original_name    VARCHAR(255)      NOT NULL DEFAULT ''        COMMENT '原名',file_suffix      VARCHAR(10)       NOT NULL DEFAULT ''        COMMENT '文件后缀名',file_url         VARCHAR(500)      NOT NULL                   COMMENT '文件URL',create_time      DATETIME          DEFAULT NULL               COMMENT '创建时间',create_by        VARCHAR(64)       DEFAULT ''                 COMMENT '上传人',update_time      DATETIME          DEFAULT NULl               COMMENT '更新时间',update_by        VARCHAR(64)       DEFAULT ''                 COMMENT '更新人',service          VARCHAR(20)       NOT NULL DEFAULT 'minio'   COMMENT '服务商',primary key (oss_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='OSS对象存储表';

2. OSS对象存储动态配置表

DROP TABLE IF EXISTS sys_oss_config;
CREATE TABLE sys_oss_config (oss_config_id     BIGINT(20)         NOT NULL                 COMMENT 'OSS动态配置ID',config_key        VARCHAR(20)        NOT NULL DEFAULT ''      COMMENT '配置key',access_key        VARCHAR(255)       DEFAULT ''               COMMENT 'accessKey',secret_key        VARCHAR(255)       DEFAULT ''               COMMENT '秘钥',bucket_name       VARCHAR(255)       DEFAULT ''               COMMENT '桶名称',prefix            VARCHAR(255)       DEFAULT ''               COMMENT '前缀',endpoint          VARCHAR(255)       DEFAULT ''               COMMENT '访问站点',domain            VARCHAR(255)       DEFAULT ''               COMMENT '自定义域名',is_https          CHAR(1)            DEFAULT 'N'              COMMENT '是否https(Y是 N否)',region            VARCHAR(255)       DEFAULT ''               COMMENT '域',access_policy     CHAR(1)            NOT NULL DEFAULT '1'     COMMENT '桶权限类型(0-private 1-public 2-custom)',status            CHAR(1)            DEFAULT '1'              COMMENT '是否默认(0是 1否)',extend            VARCHAR(255)       DEFAULT ''               COMMENT '扩展字段',create_by         VARCHAR(64)        DEFAULT ''               COMMENT '创建者',create_time       DATETIME           DEFAULT NULL             COMMENT '创建时间',update_by         VARCHAR(64)        DEFAULT ''               COMMENT '更新者',update_time       DATETIME           DEFAULT NULL             COMMENT '更新时间',PRIMARY KEY (oss_config_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='OSS对象存储动态配置表';INSERT INTO `sys_oss_config` VALUES (1, 'minio', 'd6zVm5AP07uGCqSmsTxe', 'Vsm6qQDHgGchukEpyEoeX3dTe7fic60nTi8D9a0I', 'mingyue', '', 'mingyue-minio:5000', '', 'N', '', '1', '0', '', 'admin', '2023-09-11 17:50:40', 'admin', '2023-09-11 17:50:40');
COMMIT;

OSS 配置加载

初始化OSS配置

@Override
public void init() {List<SysOssConfig> list = this.list();// 加载 OSS 初始化配置for (SysOssConfig config : list) {String configKey = config.getConfigKey();if ("0".equals(config.getStatus())) {RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey);}RedisUtils.setCacheMapValue(OssConstant.SYS_OSS_CONFIG, config.getConfigKey(), JSONUtil.toJsonStr(config));}
}

OssApplicationRunner

@Slf4j
@Component
@RequiredArgsConstructor
public class OssApplicationRunner implements ApplicationRunner {private final SysOssConfigService sysOssConfigService;@Overridepublic void run(ApplicationArguments args) {sysOssConfigService.init();log.info("初始化 OSS 配置成功");}}

改进 OssFactory

@Slf4j
public class OssFactory {private static final Map<String, OssClient> CLIENT_CACHE = new ConcurrentHashMap<>();/*** 获取默认实例*/public static OssClient instance() {// 获取redis 默认类型String configKey = RedisUtils.getCacheObject(OssConstant.DEFAULT_CONFIG_KEY);if (StrUtil.isEmpty(configKey)) {throw new OssException("文件存储服务类型无法找到!");}return instance(configKey);}/*** 根据类型获取实例*/public static OssClient instance(String configKey) {String json = RedisUtils.getCacheMapValue(OssConstant.SYS_OSS_CONFIG, configKey);if (json == null) {throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");}OssProperties properties = JSONUtil.toBean(json, OssProperties.class);OssClient client = CLIENT_CACHE.get(configKey);if (client == null) {CLIENT_CACHE.put(configKey, new OssClient(configKey, properties));log.info("创建OSS实例 key => {}", configKey);return CLIENT_CACHE.get(configKey);}// 配置不相同则重新构建if (!client.checkPropertiesSame(properties)) {CLIENT_CACHE.put(configKey, new OssClient(configKey, properties));log.info("重载OSS实例 key => {}", configKey);return CLIENT_CACHE.get(configKey);}return client;}}

移除 Nacos OSS 配置

因为从数据库加载配置,所以不在需要 Nacos 配置了

oss:configKey: minioendpoint: mingyue-minio:5000domain:prefix:accessKey: d6zVm5AP07uGCqSmsTxesecretKey: Vsm6qQDHgGchukEpyEoeX3dTe7fic60nTi8D9a0IbucketName: mingyueregion: isHttps: NaccessPolicy: 1

上传测试

{"code": 200,"msg": "操作成功","data": {"ossId": "1701490497677180930","fileName": "2023-09-12/d1b5389a465f4bf7985844916d785c06.png","originalName": "head_1.png","fileSuffix": ".png","fileUrl": "http://mingyue-minio:5000/mingyue/2023-09-12/d1b5389a465f4bf7985844916d785c06.png","createTime": "2023-09-12 14:58:41","createBy": "mingyue","service": "minio"}
}

OSS 上传信息保存

/*** 构建上传文件返回信息* @param originalFilename 原始文件名* @param suffix 文件后缀* @param configKey 配置key* @param uploadResult OSS服务返回结果* @return*/
private SysOssVo buildResult(String originalFilename, String suffix, String configKey, UploadResult uploadResult) {SysOss oss = new SysOss();oss.setFileUrl(uploadResult.getFileUrl());oss.setFileSuffix(suffix);oss.setFileName(uploadResult.getFileName());oss.setOriginalName(originalFilename);oss.setService(configKey);this.save(oss);SysOssVo sysOssVo = BeanUtil.toBean(oss, SysOssVo.class);return this.matchingUrl(sysOssVo);
}

删除文件

逻辑实现

删除数据库记录的同时需要删除OSS服务对应的文件

@Override
public Boolean deleteByOssIds(List<Long> ossIds) {List<SysOss> list = this.listByIds(ossIds);if (CollUtil.isEmpty(list)) {return Boolean.FALSE;}for (SysOss sysOss : list) {OssClient storage = OssFactory.instance(sysOss.getService());storage.delete(sysOss.getFileUrl());}return this.removeBatchByIds(ossIds);
}

删除接口

@DeleteMapping("/{ossIds}")
@Operation(summary = "删除OSS对象存储",parameters = { @Parameter(name = "ossIds", description = "oss对象Ids", required = true) })
public R<Boolean> remove(@NotEmpty(message = "主键不能为空") @PathVariable List<Long> ossIds) {return R.ok(sysOssService.deleteByOssIds(ossIds));
}

删除测试

删除前打开文件查看:http://mingyue-minio:5000/mingyue/2023-09-12/d1b5389a465f4bf7985844916d785c06.png

curl -X 'DELETE' \'http://mingyue-gateway:9100/oss/sysOss/1701490497677180930' \-H 'accept: */*' \-H 'Authorization: 6H1mlA91zFRa5yEpIl2b2mnCjbG5B44f'

删除后再打开

<Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Key>2023-09-12/d1b5389a465f4bf7985844916d785c06.png</Key><BucketName>mingyue</BucketName><Resource>/mingyue/2023-09-12/d1b5389a465f4bf7985844916d785c06.png</Resource><RequestId>17841B7B6B41C214</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId>
</Error>

下载文件

逻辑实现

@Override
public void download(Long ossId, HttpServletResponse response) throws IOException {SysOss sysOss = this.getById(ossId);if (ObjectUtil.isNull(sysOss)) {throw new ServiceException("文件数据不存在!");}FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");OssClient storage = OssFactory.instance(sysOss.getService());try (InputStream inputStream = storage.getObjectContent(sysOss.getFileUrl())) {int available = inputStream.available();IoUtil.copy(inputStream, response.getOutputStream(), available);response.setContentLength(available);}catch (Exception e) {throw new ServiceException(e.getMessage());}
}

下载接口

@GetMapping("/download/{ossId}")
@Operation(summary = "下载OSS对象存储",parameters = { @Parameter(in = ParameterIn.PATH, name = "ossIds", description = "oss对象Ids", required = true) })
public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {sysOssService.download(ossId, response);
}

下载测试

curl -X 'GET' \'http://mingyue-gateway:9100/oss/sysOss/download/1701492631160229889' \-H 'accept: */*'

image-20230912190918686

小结

文件服务基础已经完成啦,接下来可以自己尝试集成其他厂商的 OSS 服务。

文件服务更新暂告一段落,接下来弄一弄搜索服务,打算用 ES(Elasticsearch)作为搜索服务基础工具,期待一下吧~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/133899.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鼠标拖拽拖动盒子时,与盒子内某些点击事件冲突问题解决

目录 问题解决思路解决代码&#xff08;标注【主要代码】的为重点&#xff09; 问题 拖动该悬浮球时&#xff0c;鼠标弹起可能会触发悬浮球内事件 解决思路 鼠标拖动盒子时&#xff0c;将 isMove 设为 true 意为正在拖动盒子&#xff0c;此时将 class"btns_move" 遮…

利用 SOAR 加快事件响应并加强网络安全

随着攻击面的扩大和攻击变得越来越复杂&#xff0c;与网络攻击者的斗争重担落在了安全运营中心 &#xff08;SOC&#xff09; 身上。SOC 可以通过利用安全编排、自动化和响应 &#xff08;SOAR&#xff09; 平台来加强组织的安全态势。这一系列兼容的以安全为中心的软件可加快事…

单元格法近似求解多边形最大内接矩形问题【思路讲解+java实现】

文章目录 问题描述问题解决方案多边形网格化区分每个单元格是在多边形内部还是外部根据已标记单元格寻找最大内接矩形剪枝优化多角度旋转 案例测试代码实现说明 问题描述 给定一个多边形的点集&#xff0c;希望找出多边形内部面积最大的矩形。该问题可能出现在&#xff0c;从一…

聊聊Spring事务同步器TransactionSynchronization

在一些业务场景中可能我们需要去对某一个spring事务的生命周期进行监控&#xff0c;比如在这个事务提交&#xff0c;回滚&#xff0c;被挂起的时候&#xff0c;我们想要去执行一些自定义的操作&#xff0c;这怎么去做呢&#xff1f;其实spring作为一个高扩展性的框架&#xff0…

关系型三大范式与BCNF有什么用呢

学的时候就知道是一堆公式。 实际中在设计表的时候可能会用到。 前提是关系型数据库&#xff0c;比如mysql。 &#xff08;实际中oracle比mysql更好用。但是他收费啊。&#xff09; 第一范式&#xff1a;每个属性都是原子的&#xff08;需要做到每个属性都是不可分割的。&…

02 java ---- Android 基础app开发

目录 相对布局 显示一个美女 显示两个美女 安卓APP启动过程 安卓布局控件 常用布局之相对布局 常用布局之相对布局 padding和margin 按键美化 常用布局之线性布局 安卓按键响应的几种方式 直接设置按键的onClick绑定的函数 自定义类实现按键监听事件的接口 匿名内…

[NLP] LLM---<训练中文LLama2(一)>训练一个中文LLama2的步骤

一 数据集 【Awesome-Chinese-LLM中文数据集】 【awesome-instruction-dataset】【awesome-instruction-datasets】【LLaMA-Efficient-Tuning-数据集】Wiki中文百科&#xff08;25w词条&#xff09;wikipedia-cn-20230720-filteredBaiduBaiKe&#xff08;563w词条&#xff09; …

4.后端·新建子模块与开发(传统模式)

文章目录 学习资料新建子模块与各层查询entity的列表entitymapper层service层controller层 测试 学习资料 https://www.bilibili.com/video/BV13g411Y7GS?p8&spm_id_frompageDriver&vd_sourceed09a620bf87401694f763818a31c91e b站的学习视频 新建子模块与各层 在r…

Linux Ubuntu20.04深度学习环境快速配置命令记录

一、驱动安装 1、更新系统包 sudo apt-get updatesudo apt-get upgrade 2、安装显卡驱动 使用apt方式安装驱动&#xff0c;多数情况不容易成功&#xff0c; 使用一下方法更佳&#xff1a; 1.查看合适显卡的驱动版本 ubuntu-drivers devices NVIDIA GeForce 驱动程序 - …

POJ 3684 Physics Experiment 弹性碰撞

一、题目大意 我们有N个半径为R厘米的球&#xff0c;固定在距离地面高度为H的管道上&#xff0c;刚开始释放第一个&#xff0c;之后每过一秒释放一个&#xff0c;释放下面的球不会影响到上面的球的高度&#xff0c;忽略一切阻力&#xff0c;认为球之间的碰撞为弹性碰撞&#x…

【电子元件】常用电子元器件的识别之电容器

目录 前言1. 电容器的简介2.电容器的识别1. 铝电解电容器2.钽电解电容器3.固态电解电容器4.瓷介电容器5. 贴片陶瓷电容器6. 聚丙烯电容7. 金属化聚丙烯薄膜电容器8. 独石电容器9. 涤纶电容器10. 超小型金属化聚酯薄膜电容器11. 可变电容器11.1 空气可变电容器11.2 薄膜介质可变…

JMeter基础 —— 使用Badboy录制JMeter脚本!

1、使用Badboy录制JMeter脚本 打开Badboy工具开始进行脚本录制&#xff1a; &#xff08;1&#xff09;当我们打开Badboy工具时&#xff0c;默认就进入录制状态。 如下图&#xff1a; 当然我们也可以点击录制按钮进行切换。 &#xff08;2&#xff09;在地址栏中输入被测地…

国庆中秋特辑(一)浪漫祝福方式 用循环神经网络(RNN)或长短时记忆网络(LSTM)生成祝福诗词

目录 一、使用深度学习中的循环神经网络&#xff08;RNN&#xff09;或长短时记忆网络&#xff08;LSTM&#xff09;生成诗词二、优化&#xff1a;使用双向 LSTM 或 GRU 单元来更好地捕捉上下文信息三、优化&#xff1a;使用生成对抗网络&#xff08;GAN&#xff09;或其他技术…

深度学习-卷积神经网络-纹理表示卷积神经网络-卷积神经网络-[北邮鲁鹏]

这里写目录标题 参考文章全连接神经网络全连接神经网络的瓶颈全连接神经网络应用场景 卷积神经网络卷积层(CONV)卷积核卷积操作卷积层设计卷积步长(stride)边界填充特征响应图组尺寸计算 激活层池化层(POOL)池化操作定义池化操作作用池化层超参数常见池化操作 全连接层(FC)样本…

重建与发展:数字资产借贷行业朝着可持续发展迈进!

纵观历史&#xff0c;贷款和货币一样古老&#xff0c;无论哪种形式的货币都需要有其借贷市场。现在&#xff0c;比特币以其分散和透明的性质&#xff0c;在加密领域占据龙头地位。 就像之前的货币一样&#xff0c;比特币要真正蓬勃发展&#xff0c;也需要一个强大的借贷市场。然…

如何在Windows 10/11中重置网络,以及重置后的注意事项有哪些

本文介绍如何在Windows 10和Windows 11中重置网络设置。 如何重置Windows 10网络设置 在Windows10中使用网络重置实用程序相当简单。 一、进入“开始”菜单>“设置”,然后选择“网络和Internet”。 二、在左侧导航窗格中,选择“状态”以确保你正在查看网络状态窗口。然…

嵌入式入门教学——模电基础概念

目录 1、模拟信号和模拟电路 2、研究领域 3、常用术语 3.1、共价键 3.2、电场 3.3、温度的电压当量 3.4、动态信号 3.5、直流电流和交流电流 3.6、内阻 3.7、信号频率 3.8、电容 3.9、电感 3.10、相位 3.11、信号失真 3.12、电导 3.13、跨导 3.14、电位 3.15…

数据结构——图(图的存储及基本操作)

文章目录 前言一、邻接矩阵法&#xff08;顺序存储&#xff09;1.无向图存储邻接矩阵算法2.有向图存储邻接矩阵算法 二、邻接表法(图的链式存储结构)总结 前言 邻接矩阵法(图的顺序存储结构) 1.1 无向图邻接矩阵算法 1.2 有向图邻接矩阵算法邻接表法(图的一种链式存储结构) 一…

Unity WebView 中文输入支持

WebView 中文输入支持 &#x1f96a;效果展示&#x1f371;原理 &#x1f96a;效果展示 &#x1f4a1;使用版本为4.4&#xff1b; &#x1f4a1;测试环境&#xff1a;unity editor 2022.3.15f1c1、Windows&#xff1b; &#x1f371;原理 提取页面激活的输入框&#xff0c;…

github上创建分支并合并到master

github上创建分支并合并到master 目录概述需求&#xff1a; 设计思路实现思路分析1.创建分支2.commit changes3.create pull request按钮4.网页解析器5.数据处理器 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,ful…