Mall脚手架总结(五) —— SpringBoot整合MinIO实现文件管理

前言

        在项目中我们经常有资源的上传和下载的功能需求,比如用户头像、产品图片、配置文件等等,大数据量的文件存储无疑需要更高性能的数据存储服务,对于无需对结构实现复杂查询的文件对象来说,对象存储服务无疑是一个较好的选择,在下面的文章中荔枝也会梳理脚手架整合MinIO实现文件管理。希望能帮助到有需要的小伙伴~~~


文章目录

前言

一、MinIO实现文件管理

1.1 为什么使用对象存储服务

1.1.1 OSS与传统的文件系统的区别

1.1.2 OSS与非关系型数据库的用法区分

1.2 CorsFilter

1.2.1 跨源资源共享

1.2.2 CorsFilter剖析

1.3 @RequestPart注解

MultipartFile和File

1.4 MinioClient

1.5 Minio的访问策略

总结


一、MinIO实现文件管理

1.1 为什么使用对象存储服务

        在项目中,往往有些数据比如头像、资源文件等,这些数据的数据量往往比较大但又不需要执行频繁的数据操作,也没有复杂的结构关系,这些数据的存储我们往往尝试选择更好的存储方式。就拿图片来说吧,存在MySQL这种关系型数据库明显不是很合适,因为它是块存储的,要先将文件编码成二进制文本才能存进去,同时关系型数据库中会增加大量的数据比如索引、字段、日志等,查询效率明显差强人意。这时候我们需要一个能够直接存储整个文件对象的工具,这时我们就要用OSS(对象存储服务)。 

1.1.1 OSS与传统的文件系统的区别

        相比于传统的文件管理系统,对象存储服务提供了一种更简单、更灵活的数据源存储方式,无需我们预先定义文件系统的目录结构,而是将文件作为一个对象来存储,文件数据的管理和检索更加方便。在对象存储服务中,每个对象都有一个唯一的标识符(通常是一个特定的URL)

1.1.2 OSS与非关系型数据库的用法区分

        小伙伴们可能跟荔枝一样,想起图像、文件这些数据是不是也可以存在非关系型数据库里面比如MongoDB。是的的确可以,但我们要弄清楚要存储文件的操作情况,根据OSS和非关系型数据库的应用场景来选择适合需求的存储工具。

  • 对象存储服务: 适用于大规模的、静态的文件存储需求,例如图片、音频、视频文件等。对象存储通常具有较高的可扩展性和稳定性。
  • 非关系型数据库: 适用于需要对存储的文件进行复杂查询、分析和变换的场景,例如社交网络应用、日志分析等。

总结一下,之所以选择MinIO是因为其在无需过多操作的文件数据对象的存储上表现更优异,但是注意的是MinIO不是数据库,而是一种数据对象存储服务! 

云存储和云数据库区别:MinIO与MySQL对比以及存储的相关知识_minio数据库_Fishermen_sail的博客-CSDN博客  

1.2 CorsFilter

在正式梳理CorsFilter之前我们需要了解什么是CROS

1.2.1 跨源资源共享

        CORS(Cross-origin resource sharing)跨源资源共享,是一种用于在浏览器和服务器之间进行安全跨域数据传输的机制。在 Web 开发中,CORS 允许网页从不同的域(协议、域名、端口)请求受限制资源,而不受同源策略的限制。正常情况下,浏览器是会阻止跨域请求来加载自身的资源,而CORS 通过在服务器端设置响应头的方式,允许服务器声明哪些源可以访问其资源,从而绕过了同源策略的限制。

浏览器将CORS请求分为两类:简单请求和非简单请求。

  • 简单请求:浏览器会自动在请求头中增加一个Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)之后服务器再根据这个值,决定是否同意这次请求;
  • 非简单请求:浏览器会自动发送一个请求方法为Option的预检请求,里面也包含着Origin字段、Access-Control-Request-Method(列出浏览器的CORS请求会用到哪些HTTP方法)以及Access-Control-Request-Headers(指定浏览器CORS请求会额外发送的头信息字段)。

更为详细的内容参见博文:

 http://www.ruanyifeng.com/blog/2016/04/cors.html

https://blog.csdn.net/zzuhkp/article/details/120631687

1.2.2 CorsFilter剖析

        CorsFilter是一个用于处理跨域资源共享(CORS)的过滤器。在SpringBoot中整合MinIO实现文件管理的时候我们需要自定义一个配置类来允许跨域访问,需要通过Spring中web框架中的CorsFilter来封装我们的配置信息。

 完整的类继承关系如下:

简单看一下这个类的源码:

public class CorsFilter extends OncePerRequestFilter {private final CorsConfigurationSource configSource;private CorsProcessor processor = new DefaultCorsProcessor();public CorsFilter(CorsConfigurationSource configSource) {Assert.notNull(configSource, "CorsConfigurationSource must not be null");this.configSource = configSource;}public void setCorsProcessor(CorsProcessor processor) {Assert.notNull(processor, "CorsProcessor must not be null");this.processor = processor;}protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//获取配置信息CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(request);//处理请求boolean isValid = this.processor.processRequest(corsConfiguration, request, response);if (isValid && !CorsUtils.isPreFlightRequest(request)) {//过滤器链过滤filterChain.doFilter(request, response);}}
}
  • CorsConfigurationSource对象:代表了当前请求的 CORS 配置。
  • CorsProcessor类:负责处理请求,并根据 CORS 配置信息判断是否允许该请求。
  • doFilterInternal 方法:该方法CorsFilter的父类 OncePerRequestFilter 类中的一个抽象方法,需要在子类中实现。在这个方法中,首先从configSource获取当前请求的 CORS 配置信息。然后,通过CorsProcessor对象(默认使用DefaultCorsProcessor类)处理当前请求。
  • processRequest 方法:processRequest 方法是 CorsProcessor 接口中的一个方法,用于处理请求。具体的 CORS 处理逻辑在该方法中实现。
  • filterChain.doFilter 方法:如果请求是有效的且不是预检请求(Preflight Request),则调用 filterChain.doFilter(request, response)继续处理请求链。

在SpringBoot项目中我们仅需要通过一个配置类向其传入配置信息即可,如下面的示例代码,UrlBasedCorsConfigurationSource是CorsConfigurationSource接口的一个实现类。

@Configuration
public class GlobalCorsConfig {/*** 允许跨域调用的过滤器*/@Beanpublic CorsFilter corsFilter() {//配置信息CorsConfiguration config = new CorsConfiguration();//允许所有域名进行跨域调用config.addAllowedOriginPattern("*");//允许跨越发送cookieconfig.setAllowCredentials(true);//放行全部原始头信息config.addAllowedHeader("*");//允许所有请求方法跨域调用config.addAllowedMethod("*");UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", config);return new CorsFilter(source);}
}

区分CorsConfiguration 和CorsConfigurationSource 

  • CorsConfiguration类:用于配置CORS规则。你可以在这个对象上设置允许的来源、允许的HTTP方法、允许的请求头等
  • CorsConfigurationSource接口:用于提供CorsConfiguration对象,通过自定义实现类可以根据请求的不同,为不同的资源提供不同的CORS配置。

1.3 @RequestPart注解

前端中我们上传数据到服务器中通常在form表单中用一个enctype标记为multipart/form-dataPOST请求来实现,在input表单中声明type为file即可实现文件上传。

<form action="http://127.0.0.1" method="post" enctype="multipart/form-data"><input type="file" name="file1" value="请选择文件"/><br/><input type="submit"/>
</form>

而在Spring中我们可以通过@RequestPart注解来获取表单上传的数据。该注解是Spring 框架中用于处理multipart/form-data请求中的文件上传的注解。

@ApiOperation("文件上传")
@RequestMapping(value = "/upload", method = RequestMethod.POST)
@ResponseBody
public CommonResult upload(@RequestPart("file") MultipartFile file) 

MultipartFile和File

这一部分大家可以看看荔枝梳理的文章嘿~

彻底弄懂Java中的MultipartFile接口和File类_荔枝当大佬的博客-CSDN博客

1.4 MinioClient

该类是Java操作MinIO客户端的工具库,用于与MinIO对象存储服务进行交互。

创建MinIO客户端的操作

//创建一个MinIO的Java客户端
MinioClient minioClient =MinioClient.builder().endpoint(访问地址).credentials(登陆令牌,登录密钥).build();

文件上传操作代码

@Controller
@Api(tags = "MinioController")
@Tag(name = "MinioController", description = "MinIO对象存储管理")
@RequestMapping("/minio")
public class MinioController {private static final Logger LOGGER = LoggerFactory.getLogger(MinioController.class);@Value("${minio.endpoint}")private String ENDPOINT;@Value("${minio.bucketName}")private String BUCKET_NAME;@Value("${minio.accessKey}")private String ACCESS_KEY;@Value("${minio.secretKey}")private String SECRET_KEY;@ApiOperation("文件上传")@RequestMapping(value = "/upload", method = RequestMethod.POST)@ResponseBodypublic CommonResult upload(@RequestPart("file") MultipartFile file) {try {//创建一个MinIO的Java客户端MinioClient minioClient =MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY,SECRET_KEY).build();//检查桶是否存在boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(BUCKET_NAME).build());if (isExist) {LOGGER.info("存储桶已经存在!");} else {//创建存储桶并设置只读权限minioClient.makeBucket(MakeBucketArgs.builder().bucket(BUCKET_NAME).build());BucketPolicyConfigDto bucketPolicyConfigDto = createBucketPolicyConfigDto(BUCKET_NAME);SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder().bucket(BUCKET_NAME).config(JSONUtil.toJsonStr(bucketPolicyConfigDto)).build();//将策略配置应用到指定的 MinIO 存储桶中minioClient.setBucketPolicy(setBucketPolicyArgs);}String filename = file.getOriginalFilename();SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");// 设置存储对象名称String objectName = sdf.format(new Date()) + "/" + filename;// 使用putObject上传一个文件到存储桶中PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(BUCKET_NAME).object(objectName).contentType(file.getContentType()).stream(file.getInputStream(), file.getSize(), ObjectWriteArgs.MIN_MULTIPART_SIZE).build();minioClient.putObject(putObjectArgs);LOGGER.info("文件上传成功!");MinioUploadDto minioUploadDto = new MinioUploadDto();minioUploadDto.setName(filename);minioUploadDto.setUrl(ENDPOINT + "/" + BUCKET_NAME + "/" + objectName);return CommonResult.success(minioUploadDto);} catch (Exception e) {e.printStackTrace();LOGGER.info("上传发生错误: {}!", e.getMessage());}return CommonResult.failed();}
}

这里的 BucketPolicyConfigDto类是自定义的访问策略类。

@Data
@EqualsAndHashCode
@Builder
public class BucketPolicyConfigDto {private String Version;private List<Statement> Statement;@Data@EqualsAndHashCode@Builderpublic static class Statement {private String Effect;private String Principal;private String Action;private String Resource;}
}

删除文件操作

MinioClient minioClient = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY,SECRET_KEY).build();
minioClient.removeObject(RemoveObjectArgs.builder().bucket(BUCKET_NAME).object(objectName).build());

1.5 Minio的访问策略

MinIO中的访问策略主要有三种:public、private和consume(自定义)

  • Version: 策略的版本,目前的版本为 "2012-10-17"。
  • Statement: 一个数组,包含了访问规则的定义。

每个 Statement 包含以下属性:

  • Effect: 指定策略的效果,可以是 "Allow"(允许)或 "Deny"(拒绝)。
  • Action: 指定允许或拒绝的操作,可以是一个字符串或一个字符串数组,例如 "s3:GetObject" 或 ["s3:GetObject", "s3:PutObject"]。
  • Resource: 指定操作作用的资源,可以是一个字符串或一个字符串数组,例如 "arn:aws:s3:::my-bucket/*"。
  • Principal: 指定被授权的实体,可以是 "*"(表示所有用户)或特定的用户或角色。

一个简单的访问策略 

{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"AWS": ["*"]},"Action": ["s3:GetObject"],"Resource": ["arn:aws:s3:::mall/*.**"]}]
}

总结

        终章!荔枝把脚手架中的知识内容梳理了一遍,也确实学到了之前没有了解过的类和一些工具接口,对项目中用到的中间件的使用体会也更加深入了。有些类的源码确实太多了哈哈哈,根据自己的需求荔枝确实在有选择地阅读和理解,同时也感谢宏哥的帮助和许多博主的博文浇灌哈哈哈哈,继续加油!

今朝已然成为过去,明日依然向往未来!我是荔枝,在技术成长之路上与您相伴~~~

如果博文对您有帮助的话,可以给荔枝一键三连嘿,您的支持和鼓励是荔枝最大的动力!

如果博文内容有误,也欢迎各位大佬在下方评论区批评指正!!!

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

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

相关文章

uniapp编译到小程序Component is not found in path “components/energy/illumination“

Component is not found in path "components/energy/illumination" 直接清除缓存重新编译

Ubuntu下怎么配置vsftpd

2023年10月12日&#xff0c;周四中午 目录 首先要添加一个系统用户然后设置这个系统用户的密码给新创建的系统用户创建主目录启动vsftpd服务查看vsftpd服务的状态打开外界访问vsftpd服务所需的端口获取服务器的IP地址大功告成 首先要添加一个系统用户 useradd 用户名然后设置…

APP备案避坑指南,值得收藏

目录 什么时间节点前需完成备案&#xff1f; APP/小程序一定要做备案吗&#xff1f; 涉及前置审批的APP有哪些&#xff1f; APP 支持安卓、IOS 多个运行平台&#xff0c;应该备案多少次&#xff1f; 企业是自有服务器&#xff0c;该如何进行APP备案&#xff1f; APP备案可…

【Spring框架】Spring监听器的简介和基本使用

目录 一、观察者模式 1.1 模型介绍 1.2 观察者模式Demo 1.2.1 观察者实体 1.2.2 主题实体 1.2.3 测试代码 二、Spring监听器的介绍 2.1 事件&#xff08;ApplicationEvent&#xff09; 2.1.1 Spring内置事件 2.1.2 Spring内置事件 2.2 事件监听器&#xff08;Applic…

三大方法快速发现商业规律

文章目录 三大方法快速发现商业规律一、市场调研二、数据分析三、案例分析 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作者、产品软文创造者、技术文章评审老师、问卷调查…

PHP LFI 利用临时文件Getshell

PHP LFI 利用临时文件 Getshell 姿势-安全客 - 安全资讯平台 LFI 绕过 Session 包含限制 Getshell-安全客 - 安全资讯平台 目录 PHP LFI 利用临时文件Getshell 临时文件 linux 和 windows的 临时文件存储规则 linux和windows对临时文件的命名规则 PHPINFO()特性 原理 条…

Python点击exe后报错:Failed to execute script xxxx问题的解决办法

最近工作在弄人脸识别的问题&#xff0c;从gitee来pull了一个但是发现报了一个Failed to execute script XXX的问题 造成这个问题的原因是执行文件exe存放的目录不对&#xff0c;可能在打包前exe文件并不是存在在这个位置。 解决方案将exe文件尝试存在在不同目录下&#xff…

详解Pinia和Vuex

一、vuex介绍 1.什么是vuex&#xff1f;为什么要使用vuex? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 在vue最重要的就是数据驱动和组件化&#x…

Qt之submodule编译

工作中会遇到这样一种情况&#xff1a;qt应用程序在运行时提示找不到某个qt的动态库。我遇到的是缺少libQt5Websocket.so&#xff0c;因为应用程序是在x86平台银河麒麟v10上开发&#xff0c;能够正常编译运行&#xff0c;然后移植到rk3588&#xff08;aarch64架构&#xff09;上…

NeuroImage | 右侧颞上回在语义规则学习中的作用:来自强化学习模型的证据

在现实生活中&#xff0c;许多规则的获取通常需要使用语言作为桥梁&#xff0c;特别是语义在信息传递中起着至关重要的作用。另外&#xff0c;个体使用的语言往往具有明显的奖励和惩罚元素&#xff0c;如赞扬和批评。一种常见的规则是寻求更多的赞扬&#xff0c;同时避免批评。…

【翻译】Efficient Data Loader for Fast Sampling-Based GNN Training on Large Graphs

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 此内容为机器翻译的结果&#xff0c;若有异议的地方&#xff0c;建议查看原文。 机器翻译的一些注意点&#xff0c;比如&#xff1a; 纪元、时代 > epoch工人 > worker火车、培训、训练师 > train Effic…

c# 弹出背景透明图

1. 在窗体中添加 picturebox 控件 2. 在 picturebox 中添加 “png ” 背景透明图&#xff0c;或者GIF图&#xff0c;属性设置如下 3. 在窗体初始化中&#xff0c;添加如下代码 this.BackColor Color.LimeGreen; this.TransparencyKey Color.LimeGreen; 此功能可以用来展示…

【Vue面试题三十】、vue项目本地开发完成后部署到服务器后报404是什么原因呢?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;vue项目本地开发完成后部…

一卷到底,大明哥带你横扫 Netty

上一个死磕 Java 专栏【死磕 NIO】(当然写的不是很好&#xff0c;争取今年将它重写一遍)是**【死磕 Netty】**的铺垫&#xff0c;对于我们 Java 程序员而言&#xff0c;我们在实际开发过程一般都不会直接使用 Java NIO 作为我们的网络编程框架&#xff0c;因为写出一套高质量的…

基于和声优化的BP神经网络(分类应用) - 附代码

基于和声优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于和声优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.和声优化BP神经网络3.1 BP神经网络参数设置3.2 和声算法应用 4.测试结果&#xff1a;5.M…

内网渗透——隧道代理

文章目录 代理代理使用场景VPS建立隧道frpMSF木马生成监听开启frp服务端和客户端执行exe木马文件 代理 实验环境&#xff1a; 攻击机kali&#xff1a;192.168.188.133&#xff08;NAT模式&#xff09; 模拟的公网服务器&#xff08;本机&#xff09;&#xff1a;10.9.75.239 …

kube-controller-manager和kube-scheduler不能正常启动

kube-controller-manager-k8s-worker01和kube-scheduler-k8s-worker01没有启动起来 原因&#xff1a; 解决&#xff1a;进入/etc/kubernetes/manifests 编辑 将镜像地址修改为 然后重启kubelet&#xff1a;systemctl restart kubelet.service

freefilesync文件同步软件

下载 下载链接 https://freefilesync.org/download.php 往下拉&#xff0c;看到下载的链接 下载windows版本 下载地址&#xff1a; https://freefilesync.org/download/FreeFileSync_13.0_Windows_Setup.exe 直接复制到浏览器中访问就能下载 安装 双击安装包&#xff0c;一路默…

Megatron-LM GPT 源码分析(二) Sequence Parallel分析

引用 本文基于开源代码 https://github.com/NVIDIA/Megatron-LM &#xff0c;延续上一篇Megatron-LM GPT 源码分析&#xff08;一&#xff09; Tensor Parallel分析 通过对GPT的模型运行示例&#xff0c;从三个维度 - 模型结构、代码运行、代码逻辑说明 对其源码做深入的分析。…

zookeeper应用场景(二)

单机环境下可以利用jvm级别的锁&#xff0c;比如synchronized、Lock等来实现锁&#xff0c;如果是多机部署就需要一个共享数据存储区域来实现分布式锁 一、分布式锁实现方式 1、基于数据库实现分布式锁 可以用数据库唯一索引来实现 2、基于redis实现分布式锁 redis实现的分…