当前位置: 首页 > news >正文

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)作为搜索服务基础工具,期待一下吧~~

相关文章:

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

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;https://gitee.com/csps/mingyue 源码地址&#xff08;前端&#xff09;&#xff1a;https://gitee.com/csps…...

Jenkins 页面部分显示Http状态403 被禁止

前言 生产环境Jenkins部署了一段时间了&#xff0c;结果今天在流水线配置中&#xff0c;部分页面显示Jenkins 页面部分显示Http状态403 被禁止&#xff0c;修改配置点击保存之后偶尔也会出现这个。 问题 以下是问题图片 解决 在全局安全配置里面&#xff0c;勾选上启用代…...

ajax day4

1、promise链式调用 /*** 目标&#xff1a;把回调函数嵌套代码&#xff0c;改成Promise链式调用结构* 需求&#xff1a;获取默认第一个省&#xff0c;第一个市&#xff0c;第一个地区并展示在下拉菜单中*/let pname axios({url: http://hmajax.itheima.net/api/province,}).t…...

8.Spring EL与ExpressionParser

Spring EL与ExpressionParser 文章目录 Spring EL与ExpressionParser介绍**使用SpEL来计算评估文字字符串表达式**使用SpEL来计算评估 bean 属性 – “item.name” 介绍 Spring表达式语言(SpEL)支持多种功能&#xff0c;并且可以测试这个特殊的“ExpressionParser”接口的表达…...

Go和Java实现迭代器模式

Go和Java实现迭代器模式 1、迭代器模式 迭代器模式是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素&#xff0c;不需要知道 集合对象的底层表示。 迭代器模式属于行为型模式。 意图&#xff1a;提供一种方法顺序访问一个聚合对象中各个…...

如何在 Vue.js 和 Nuxt.js 之间做出选择?

开篇 今天看了一位国外大佬的文章&#xff0c;主要是他对在项目中如何选择 Vue.js 或 Nuxt.js 的看法&#xff0c;欢迎大家在评论区发表看法&#xff0c;以下内容是他关于这个问题看法的整理&#xff0c;由于翻译水平有限&#xff0c;欢迎大家指正。 国外大佬的看法 Vue.js在开…...

(二十三)大数据实战——Flume数据采集之采集数据聚合案例实战

前言 本节内容我们主要介绍一下Flume数据采集过程中&#xff0c;如何把多个数据采集点的数据聚合到一个地方供分析使用。我们使用hadoop101服务器采集nc数据&#xff0c;hadoop102采集文件数据&#xff0c;将hadoop101和hadoop102服务器采集的数据聚合到hadoop103服务器输出到…...

Linux: network: dhcp: mtu 这个里面也有关于网卡的MTU设置;

https://linux.die.net/man/5/dhcp-options 需注意这个DHCP配置选项。 option interface-mtu uint16; This option specifies the MTU to use on this interface. The minimum legal value for the MTU is 68. 假如在网卡的配置文件中设置了dhcp获取IP信息&#xff0c;可能导…...

Android中使用图片水印,并且能够在线下载字体并应用于水印

Android中使用图片水印&#xff0c;并且能够在线下载字体并应用于水印 要在Android中使用图片水印&#xff0c;并且能够在线下载字体并应用于水印&#xff0c;可以按照以下步骤进行&#xff1a; 1.使用Picasso、Glide或其他图片加载库加载图片&#xff1a; ImageView imageV…...

HTTP文件服务

在工作中&#xff0c;往往会需要将文件同时共享给很多台电脑。 本篇介绍HHDESK的HTTP文件服务功能&#xff0c;通过浏览器&#xff0c;将本地资源共享给任意主机。 1 共享文件 首页——资源管理——服务端——“”&#xff0c;在弹出框中选择HTTP文件服务。 填写各项内容。…...

nginx配置获取客户端的真实ip

场景描述&#xff1a; 访问路径&#xff1a; A机器 - > B机器的 ->C虚拟机 &#xff1a; A机器为客户端用户&#xff0c;本地地址为 192.168.0.110 B机器为服务端反向代理服务器 本地地址为192.168.0.128 –>&#xff08;192.168.56.1&#xff09; C机器为B主机安…...

1990-2022上市公司董监高学历工资特征信息数据/上市公司高管信息数据

1990-2022上市公司董监高学历工资特征信息数据/上市公司高管信息数据 1、时间&#xff1a;1990-2022年&#xff08;统计截止日期为 2022年7月&#xff09; 2、指标&#xff1a;证券代码、统计截止日期、姓名、国籍、籍贯、籍贯所在地区代码、出生地、出生地所在地区代码、性别…...

Java程序连接 Mysql 超时问题 - 数据包过大,导致超时,# 配置网络超时时间 socketTimeout: 1800000

问题 Java程序连接 Mysql 超时问题 解决方法 如果存在 yml 等类似的配置文件&#xff0c;那么可以配置一下 socket 连接超时的参数&#xff0c;例如 # 配置网络超时时间 半小时&#xff0c;计算公式 60秒*1000毫秒*30分钟 socketTimeout: 1800000...

c++分层最短路(洛谷飞行路线)acwing版

分层最短路算法是在SPFA算法的基础上&#xff0c;将每个点分成若干层&#xff0c;从而使得每个点之间的转移只在同一层次或上下两个相邻层次之间进行&#xff0c;减少了每轮的迭代次数&#xff0c;优化了算法的效率。 #include <iostream> #include <cstdio> #inc…...

Python bs4 BeautifulSoup库使用记录

目录 介绍 安装 初始化 解析器 使用方法 优势 Python标准库 lxml HTML lxml XML html5lib 格式化输出 对象 tag Name 多值属性 其他方法 NavigableString BeautifulSoup Comment 遍历 子节点 父节点 兄弟节点 回退和前进 搜索 过滤器 字符串 正则表达…...

Jmeter系列-插件安装(5)

前言 jmeter4.0以上&#xff0c;如现在最新的5.2.1版本是有集成插件的只需要在官网下载 plugins-manager.jar 包&#xff0c;放在jmeter安装路径的lib/ext目录下即可使用&#xff1a;https://jmeter-plugins.org/install/Install/但并不能满足所有需求&#xff0c;仍然需要安装…...

spring aop源码解析

spring知识回顾 spring的两个重要功能&#xff1a;IOC、AOP&#xff0c;在ioc容器的初始化过程中&#xff0c;会触发2种处理器的调用&#xff0c; 前置处理器(BeanFactoryPostProcessor)后置处理器(BeanPostProcessor)。 前置处理器的调用时机是在容器基本创建完成时&#xff…...

使用Unity的Input.GetAxis(““)控制物体移动、旋转

使用Unity的Input.GetAxis("")控制物体移动、旋转 Input.GetAxis("") 是 Unity 引擎中的一个方法&#xff0c;用于获取游戏玩家在键盘或游戏手柄上输入的某个轴&#xff08;Axis&#xff09;的值。这里的 "" 是一个字符串参数&#xff0c;表示要…...

【CSS】画个三角形或圆形或环

首先通过调整边框&#xff0c;我们可以发现一些端倪 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><style>.box{width: 150px;height:150px;border: 50px solid black;}</style&g…...

AI项目六:基于YOLOV5的CPU版本部署openvino

若该文为原创文章&#xff0c;转载请注明原文出处。 一、CPU版本DEMO测试 1、创建一个新的虚拟环境 conda create -n course_torch_openvino python3.8 2、激活环境 conda activate course_torch_openvino 3、安装pytorch cpu版本 pip install torch torchvision torchau…...

记录YDLidar驱动包交叉编译时出现的一点问题

由于一不小心把交叉编译的系统根目录破坏了&#xff0c;所以一股脑将交叉编译系统根目录全删了重新安装&#xff0c;安装后&#xff0c;交叉编译发现ydlidar的ros包驱动出现了库无法链接的错误(刚刚还是好好的)&#xff0c;但是又想不起来之前是怎么解决的了&#xff0c;所以还…...

嵌入式学习笔记(32)S5PV210的向量中断控制器

6.6.1异常处理的2个阶段 可以将异常处理分为2个阶段来理解。第一个阶段是异常向量表跳转&#xff1b;第二个阶段是进入了真正的异常处理程序irq_handler之后的部分。 6.6.2回顾&#xff1a;中断处理的第一个阶段&#xff08;异常向量表跳转阶段&#xff09;处理 &#xff08;…...

linux下安装qt、qt触摸屏校准tslib

linux下安装qt 在 Linux 系统下安装 Qt&#xff0c;可以通过以下步骤进行操作&#xff1a;1. 下载 Qt 安装包&#xff1a;首先&#xff0c;你需要从 Qt 官方网站&#xff08;https://www.qt.io/&#xff09;下载适用于 Linux 的 Qt 安装包。选择与你的系统和需求相匹配的版本&…...

C++之unordered_map,unordered_set模拟实现

unordered_map&#xff0c;unordered_set模拟实现 哈希表源代码哈希表模板参数的控制仿函数增加正向迭代器实现*运算符重载->运算符重载运算符重载! 和 运算符重载begin()与end()实现 unordered_set实现unordered_map实现map/set 与 unordered_map/unordered_set对比哈希表…...

React Router,常用API有哪些?

react-router React Router是一个用于构建单页面应用程序&#xff08;SPA&#xff09;的库&#xff0c;它是用于管理React应用中页面导航和路由的工具。SPA是一种Web应用程序类型&#xff0c;它在加载初始页面后&#xff0c;通过JavaScript来动态加载并更新页面内容&#xff0…...

JVM类加载和双亲委派机制

当我们用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把类加载到JVM&#xff0c;本文主要说明类加载机制和其具体实现双亲委派模式。 一、类加载机制 类加载过程&#xff1a; 类加载的过程是将类的字节码加载到内存中的过程&#xff0c;主要包括…...

P-MVSNet ICCV-2019 学习笔记总结 译文 深度学习三维重建

文章目录 5 P-MVSNet ICCV-20195.0 主要特点5.1 文章概述5.2 研究方法5.2.1 特征提取5.2.2 学习局域匹配置信5.2.3 深度图预测5.2.4 Loss方程MVSNet系列最新顶刊 对比总结5 P-MVSNet ICCV-2019 深度学习三维重建 P-MVSNet-ICCV-2019(原文、译文、批注) 下载 5.0 主要特点 …...

vueshowpdf 移动端pdf文件预览

1、安装 npm install vueshowpdf -S2、参数 属性说明类型默认值v-model是否显示pdf--pdfurlpdf的文件地址String- scale 默认放大倍数 Number1.2 minscale 最小放大倍数 Number0.8 maxscale 最大放大倍数 Number2 3、事件 名称说明回调参数closepdf pdf关闭事件-pdferr文…...

C#根据excel文件中的表头创建数据库表

C#根据excel文件中的表头创建数据库表 private void button1_Click(object sender, EventArgs e){string tableName tableNameTextBox.Text;string connectionString "";using (OpenFileDialog openFileDialog new OpenFileDialog()){openFileDialog.Filter &quo…...

js通过xpath定位元素并且操作元素以下拉框select为例

js也可以使用xpath定位元素&#xff0c;现在实例讲解。 页面上有一个下拉框&#xff0c;里面内容有三个&#xff0c;用F12看一下 一、使用xpath定位这个下拉框select eldocument.evaluate(//select[name"shoppingPreference"], document).iterateNext()二、为下拉框…...

做网页用的网站/如何做网络推广赚钱

打开方式非常简单 直接把APK拖到AS里去即可Android Analyser结果发现是so库太过庞大。。。没辙了&#xff0c;我这里的情况可以删去一个arm的&#xff0c;估计可以减小32m左右。。。到时候还要再测试看看&#xff0c;能不能稳住。。。...

自己建设淘宝客网站需要备案么/百度seo优化按年收费

作者&#xff1a;朱金灿 来源&#xff1a;http://blog.csdn.net/clever101 eclipse的代码组织架构是这样的&#xff1a;第一级是工作空间&#xff0c;第二级是工程项目。因此&#xff0c;eclipse的工作空间其实相当于visual studio的解决方案&#xff0c;本质就是一系列相关工…...

Java做新闻网站/百度竞价收费标准

做这题 来为上年 上海的那个状压bfs做铺垫 _ 这题 不难 就是 多开一维 存下 钥匙的状态就好了 表示在 (x,y)这个坐标点 已经收集到了哪些钥匙 多做点 状压的题目 就会来感觉的. 1 #include <iostream>2 #include <queue>3 #include <cstring>4 using namespa…...

wordpress文章图片保存到本地/南京seo全网营销

Swift是一种类型安全的语言。类型安全的语言鼓励推荐在你代码中的值尽量要清楚其所属的类型。如果在你的代码中有一个预先好的字符串&#xff0c;你就不能错误地把他传递或者赋值给一个整数。 因为Swift是类型安全的&#xff0c;当编译你的代码时就会做类型检测并且以错误的方式…...

wordpress合并js css/南宁网站快速排名提升

利用命令行virt-install来安装虚拟机。virt-install 是一个使用“libvirt” hypervisor 管理库构建新虚拟机的命令行工具&#xff0c;此工具使用串行控制台&#xff0c;SDL&#xff08;Simple DirectMedia Layer&#xff09;图形或者VNC客户端/服务器。--name 虚拟机名字 --…...

购物网站建设论文答辩/企业邮箱怎么申请

安装 要使用 MyBatis&#xff0c; 只需将 mybatis-x.x.x.jar 文件置于 classpath 中即可。 如果使用 Maven 来构建项目&#xff0c;则需将下面的 dependency 代码置于 pom.xml 文件中&#xff1a; <dependency><groupId>org.mybatis</groupId> <artifactI…...