当前位置: 首页 > 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…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !

我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...

9-Oracle 23 ai Vector Search 特性 知识准备

很多小伙伴是不是参加了 免费认证课程&#xff08;限时至2025/5/15&#xff09; Oracle AI Vector Search 1Z0-184-25考试&#xff0c;都顺利拿到certified了没。 各行各业的AI 大模型的到来&#xff0c;传统的数据库中的SQL还能不能打&#xff0c;结构化和非结构的话数据如何和…...

文件上传漏洞防御全攻略

要全面防范文件上传漏洞&#xff0c;需构建多层防御体系&#xff0c;结合技术验证、存储隔离与权限控制&#xff1a; &#x1f512; 一、基础防护层 前端校验&#xff08;仅辅助&#xff09; 通过JavaScript限制文件后缀名&#xff08;白名单&#xff09;和大小&#xff0c;提…...