Springboot---整合对象储存服务MinIO

news2024/10/7 10:14:14

OSS

「OSS」的英文全称是Object Storage Service,翻译成中文就是「对象存储服务」,官方一点解释就是对象存储是一种使用HTTP API存储和检索非结构化数据和元数据对象的工具。

白话文解释就是将系统所要用的文件上传到云硬盘上,该云硬盘提供了文件下载、上传等一列服务,这样的服务以及技术可以统称为OSS,业内提供OSS服务的厂商很多,知名常用且成规模的七牛云等。一般我们做网站还是服务都希望将文件放在一个指定的服务器,并且更好的管理,并且动静分离更好的提升软件性能我之间写过如何springboot整合七牛云,感兴趣的可以了解一下,但是由于七牛云需要自己购买他的服务器,对于学生做项目不友好,所以今天介绍的是开源可以自己搭建的oss服务

Minio

介绍:
MinIO 是在 GNU Affero 通用公共许可证 v3.0 下发布的高性能对象存储。 它是与 Amazon S3 云存储服务兼容的 API。 使用 MinIO 为机器学习、分析和应用程序数据工作负载构建高性能基础架构。Minio官网

搭建(DOCKER)

docker的好处不用多说了,最主要的是服务的安装与卸载很方便,这里也提供docker的学习笔记,那么现在开始搭建

拉取镜像

使用之间可以先查看下各个版本

 docker search minio

一般选择star最多的版本

docker pull  minion

在虚拟机或者云服务创建一个文件夹,并且包含一个数据,一个配置文件目录做挂载
在这里插入图片描述运行

docker run -p 9001:9000 -p 9090:9090      --net=host      --name minio      -d --restart=always      -e "MINIO_ACCESS_KEY=minioadmin"      -e "MINIO_SECRET_KEY=minioadmin"     -v  /home/hadoop/minio/data:/data      -v /home/hadoop/minio/config:/root/.minio      minio/minio server      /data --console-address ":9091" -address ":9001"

访问虚拟机ip:服务端口在这里插入图片描述
账号密码是配置文件中指定的

  • MINIO_ACCESS_KEY=minioadmin
  • MINIO_SECRET_KEY=minioadmin

对象储存服务中,数据是按照bucket 桶来的,所以先新建一个桶在这里插入图片描述

java测试上传文件

  @Test
    @DisplayName("测试minio上传下载")
    public void testMn() throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        client = MinioClient.builder().credentials("minioadmin", "minioadmin")
                .endpoint("http://192.168.249.132:9001").build();
        FileInputStream inputStream;
        PutObjectArgs putObjectArgs;
//        读取文件转换为输入流
      
            inputStream = new FileInputStream("D:\\list.html");

//        上传一个对象 需要使用聚合对象包装在里面()

            putObjectArgs = PutObjectArgs.builder()
                    .object("list.html")//文件名
                    .contentType("text/html")//文件类型
                    .bucket("leadnews")//区域名
                    .stream(inputStream, inputStream.available(), -1).build();//转换为流进行传输
            client.putObject(putObjectArgs);
       
    }

这样就可以实现上传了,现在进行封装,
便于使用
建立配置属性类便于动态注入数据

@Data
@ConfigurationProperties(prefix = "minio")  // 文件上传 配置前缀file.oss
public class MinIOConfigProperties implements Serializable {

    private String accessKey;
    private String secretKey;
    private String bucket;
    private String endpoint;
    private String readPath;
}

配置文件

minio:
  accessKey: minioadmin
  secretKey: minioadmin
  bucket: leadnews
  endpoint: http://192.168.249.132:9001
  readPath: http://192.168.249.132:9001

注入配置类实列化



@Data
@Configuration
@EnableConfigurationProperties({MinIOConfigProperties.class})
//当引入FileStorageService接口时
@ConditionalOnClass(FileStorageService.class)
public class MinIOConfig {

    @Autowired
    private MinIOConfigProperties minIOConfigProperties;

    @Bean
    public MinioClient buildMinioClient() {
        return MinioClient
                .builder()
                .credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
                .endpoint(minIOConfigProperties.getEndpoint())
                .build();
    }
}

文件处理接口

public interface FileStorageService {


    /**
     *  上传图片文件
     * @param prefix  文件前缀
     * @param filename  文件名
     * @param inputStream 文件流
     * @return  文件全路径
     */
    public String uploadImgFile(String prefix, String filename,InputStream inputStream);

    /**
     *  上传html文件
     * @param prefix  文件前缀
     * @param filename   文件名
     * @param inputStream  文件流
     * @return  文件全路径
     */
    public String uploadHtmlFile(String prefix, String filename,InputStream inputStream);

    /**
     * 删除文件
     * @param pathUrl  文件全路径
     */
    public void delete(String pathUrl);

    /**
     * 下载文件
     * @param pathUrl  文件全路径
     * @return
     *
     */
    public byte[]  downLoadFile(String pathUrl);

}

imp

@Slf4j
@EnableConfigurationProperties(MinIOConfigProperties.class)
@Import(MinIOConfig.class)
public class MinIOFileStorageService implements FileStorageService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinIOConfigProperties minIOConfigProperties;

    private final static String separator = "/";

    /**
     * @param dirPath
     * @param filename  yyyy/mm/dd/file.jpg
     * @return
     */
    public String builderFilePath(String dirPath,String filename) {
        StringBuilder stringBuilder = new StringBuilder(50);
        if(!StringUtils.isEmpty(dirPath)){
            stringBuilder.append(dirPath).append(separator);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        String todayStr = sdf.format(new Date());
        stringBuilder.append(todayStr).append(separator);
        stringBuilder.append(filename);
        return stringBuilder.toString();
    }

    /**
     *  上传图片文件
     * @param prefix  文件前缀
     * @param filename  文件名
     * @param inputStream 文件流
     * @return  文件全路径
     */
    @Override
    public String uploadImgFile(String prefix, String filename,InputStream inputStream) {
        String filePath = builderFilePath(prefix, filename);
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .object(filePath)
                    .contentType("image/jpg")
                    .bucket(minIOConfigProperties.getBucket()).stream(inputStream,inputStream.available(),-1)
                    .build();
            minioClient.putObject(putObjectArgs);
            StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
            urlPath.append(separator+minIOConfigProperties.getBucket());
            urlPath.append(separator);
            urlPath.append(filePath);
            return urlPath.toString();
        }catch (Exception ex){
            log.error("minio put file error.",ex);
            throw new RuntimeException("上传文件失败");
        }
    }

    /**
     *  上传html文件
     * @param prefix  文件前缀
     * @param filename   文件名
     * @param inputStream  文件流
     * @return  文件全路径
     */
    @Override
    public String uploadHtmlFile(String prefix, String filename,InputStream inputStream) {
        String filePath = builderFilePath(prefix, filename);
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .object(filePath)
                    .contentType("text/html")
                    .bucket(minIOConfigProperties.getBucket()).stream(inputStream,inputStream.available(),-1)
                    .build();
            minioClient.putObject(putObjectArgs);
            StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
            urlPath.append(separator+minIOConfigProperties.getBucket());
            urlPath.append(separator);
            urlPath.append(filePath);
            return urlPath.toString();
        }catch (Exception ex){
            log.error("minio put file error.",ex);
            ex.printStackTrace();
            throw new RuntimeException("上传文件失败");
        }
    }

    /**
     * 删除文件
     * @param pathUrl  文件全路径
     */
    @Override
    public void delete(String pathUrl) {
        String key = pathUrl.replace(minIOConfigProperties.getEndpoint()+"/","");
        int index = key.indexOf(separator);
        String bucket = key.substring(0,index);
        String filePath = key.substring(index+1);
        // 删除Objects
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build();
        try {
            minioClient.removeObject(removeObjectArgs);
        } catch (Exception e) {
            log.error("minio remove file error.  pathUrl:{}",pathUrl);
            e.printStackTrace();
        }
    }


    /**
     * 下载文件
     * @param pathUrl  文件全路径
     * @return  文件流
     *
     */
    @Override
    public byte[] downLoadFile(String pathUrl)  {
        String key = pathUrl.replace(minIOConfigProperties.getEndpoint()+"/","");
        int index = key.indexOf(separator);
        String bucket = key.substring(0,index);
        String filePath = key.substring(index+1);
        InputStream inputStream = null;
        try {
            inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minIOConfigProperties.getBucket()).object(filePath).build());
        } catch (Exception e) {
            log.error("minio down file error.  pathUrl:{}",pathUrl);
            e.printStackTrace();
        }

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while (true) {
            try {
                if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break;
            } catch (IOException e) {
                e.printStackTrace();
            }
            byteArrayOutputStream.write(buff, 0, rc);
        }
        return byteArrayOutputStream.toByteArray();
    }
}

封装为模块

如果是springcloud分布式业务,文件处理可以封装为模块给其他模块使用
新建模块

    <modules>
        <module>heima-leadnews-basic</module>  <modules>
        <module>heima-file-starter</module>
    </modules>

    </modules>

在项目新建模块,依赖如上配置yaml文件不写,因为是做成模块给其他模块使用的
在该模块的resource目录新建meta-inf元数据配置文件
在这里插入图片描述
内容

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.heima.file.service.impl.MinIOFileStorageService

这个配置的作用是为了将一个模块(或库)的功能引入到应用程序中,以便在应用程序的其他部分中可以使用这个模块提供的功能。这个模块可能包含一些服务、组件或类,你可以使用@Autowired等注解来注入它们,以便在应用程序中使用。
通常情况下,如果你没有一个显式的启动类(Spring Boot应用的入口类),或者你不想将这个模块的功能包含在应用程序的启动类中,你可以使用这种方式,通过spring.factories配置来自动启用这个模块。
这个模块的配置会在应用程序启动时被Spring Boot自动加载和初始化,从而使你可以在应用程序中使用它提供的功能,而不需要手动实例化或配置相关的Bean。这种方式可以使应用程序的模块化更好,遵循了依赖注入和解耦的原则。

在需要使用的模块导入该模块即可

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

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

相关文章

chatGPT使用情况

作为一个语言模型&#xff0c;我&#xff08;ChatGPT&#xff09;被用于各种不同的应用场景。以下是一些常见的情况&#xff1a; 个人助手&#xff1a;人们可以使用我来获取信息、解答问题、获取建议或进行闲聊。我可以提供各种知识和帮助&#xff0c;从学术知识到日常生活的建…

nginx发布vue项目

1、docker拉取nginx镜像 docker pull nginx:latest2、docker安装nginx # 第一个80端口是主机端口&#xff0c;第二个80端口是内部端口&#xff0c;主机的端口 80 映射到容器内部的端口80 docker run -d --name nginx -p 80:80 -p 443:443 nginx:lateste3、输入IP访问 说明我们…

javaEE进阶

Cookie 是可以伪造的,比如说学生证是可以伪造的 Session 是不可以伪造的,这是学校系统记录在册的 如何获取 Cookie 我们先用 Servlet 原生的获取 cookie 的方式 我们在浏览器进行访问 但是实际上目前是没有 cookie 的,我们按 F12 进行添加 然后再重新访问,就能在 idea 看到 …

什么是高敏感型人格,高敏型人格如何改变自己

什么是高敏感型人格&#xff1f; 高敏感型人格&#xff0c;指的是个体情绪敏感度高&#xff0c;有好处也有不好的地方&#xff0c;比如说好处吧&#xff0c;高敏感型人格他们对情绪的感知更加细腻&#xff0c;这种特征在创作和设计方面&#xff0c;往往能到达常人所不能达到的…

NIO讲解

一&#xff1a;什么是NIO? 二&#xff1a;NIO三大组件 1. channel channel 有一点类似于 stream&#xff0c;它就是读写数据的双向通道&#xff0c;可以从 channel 将数据读入 buffer&#xff0c;也可以将 buffer 的数据写入 channel&#xff0c;而之前的 stream 要么是输入…

C/C++轻量级并发TCP服务器框架Zinx-游戏服务器开发006:基于redis查找玩家姓名+游戏业务实现总结

文章目录 1 Redis的安装与API的使用1.1 安装目录及环境变量1.2 设置远程客户端连接和守护进程1.3 启动redis1.4 Hiredis API的使用1.5 我的动态库和头文件 2 Redis的使用2.1 初始化时候2.2 结束的时候 3 测试4 Makefile5 游戏业务总结 1 Redis的安装与API的使用 1.1 安装目录及…

Kotlin HashMap entries.filter过滤forEach

Kotlin HashMap entries.filter过滤forEach fun main(args: Array<String>) {val hashMap HashMap<String, Int>()hashMap["a"] 1hashMap["b"] 2hashMap["c"] 3println(hashMap)hashMap.entries.filter {println("filter $…

Python用requests库采集充电桩LBS位置经纬度信息

这是一个使用Python的requests库来爬取网页内容的示例。首先&#xff0c;我们需要导入requests库。然后&#xff0c;我们需要定义一个函数来处理请求。在这个函数中&#xff0c;我们需要设置爬虫IP服务器的URL和端口号&#xff0c;然后使用requests.get来获取网页内容。最后&am…

将 Figma 轻松转换为 Sketch 的免费方法

最近浏览网站的时候&#xff0c;发现很多人不知道Figma是怎么转Sketch的。众所周知&#xff0c;Figma支持Sketch文件的导入&#xff0c;但不支持Sketch的导出&#xff0c;那么Figma是如何转Sketch的呢&#xff1f;不用担心&#xff0c;建议使用神器即时设计。它是一个可以实现在…

【C++】类和对象(一):什么是面向对象,访问限定符有哪些,类定义细节,结构体和类的关系。

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

使用ffmpeg调用电脑自带的摄像头和扬声器录制音视频

1、打开cmd&#xff0c;执行chcp 65001,修改cmd的编码格式为utf8&#xff0c;避免乱码 2、执行指令ffmpeg -list_devices true -f dshow -i dummy,查看当前window的音频和视频名称 3、打开windows系统的"打开声音设置"–“麦克风隐私设置”–"允许应用访问你…

Vue 将响应式数据转为普通对象

toRaw&#xff1a;将一个 reactive 生成的响应式数据转为普通对象。 toRaw 适用于&#xff1a;获取响应式数据对应的普通对象&#xff0c;对这个普通对象所有的操作&#xff0c;都不会引起页面的更新。 markRaw&#xff1a;标记一个对象&#xff0c;使其永远不会再成为响应式…

C++中将数据添加到文件的末尾

参考:https://blog.csdn.net/qq_23880193/article/details/44279283 C中文件的读取需要包含fstream文件&#xff0c;即&#xff1a;#include 文件的读取和写入是是通过流操作来的&#xff0c;这不像输入、输出流那样&#xff0c;库中已经定义了对象cin和cout 文件的读取需要声…

lv11 嵌入式开发 ARM体系结构理论基础2

目录 1 ARM概述 1.1 处理器分类 1.2 SOC概念 2 ARM指令集概述 2.1 ARM指令集 2.2 编译原理 3 ARM存储模型 3.1 ARM数据类型 3.2 字节序 3.3 ARM指令存储 4 ARM工作模式 4.1 ARM工作模式分类 1 ARM概述 ARM的含义 ARM&#xff08;Advanced RISC Machines&#…

VB自定义版影音播放器

利用VB开放自定义播放器&#xff0c;基于系统Quatrz.dll的接口将媒体显示到指定的控件容器中&#xff0c;比如PictureBox,实现播放的基本功能&#xff0c;播放&#xff0c;暂停&#xff0c;停止&#xff0c;音量&#xff0c;平衡&#xff0c;进度&#xff0c;媒体的总时间和进度…

react组件间通信之context

一般用于【祖组件】与【后代组件】间通信 案例&#xff1a; A,B,C,D四个组件的关系分别为&#xff1a;爷爷&#xff0c;爸爸&#xff0c;儿子&#xff0c;孙子 从A向C传递参数&#xff1a;C组件为类式组件 从A向D传递参数&#xff1a;D组件为函数组件 import React, { Componen…

Rust结构体的定义和实例化

1.结构体特点 Rust的结构体跟元组类型比较类似,它们都包含多个相关的值。和元组一样&#xff0c;结构体的每一部分可以是不同类型。但不同于元组&#xff0c;结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字&#xff0c;结构体比元组更灵活&#xff1a…

第二十九章 目标检测中的测试模型评价指标(车道线感知)

前言 近期参与到了手写AI的车道线检测的学习中去&#xff0c;以此系列笔记记录学习与思考的全过程。车道线检测系列会持续更新&#xff0c;力求完整精炼&#xff0c;引人启示。所需前期知识&#xff0c;可以结合手写AI进行系统的学习。 介绍 自动驾驶的一大前提是保证人的安全…

Linux C语言(8)

1、指针 1.1 概念 指针就是地址指针是一种数据类型&#xff0c;是一种保存地址的数据类型int是一种数据类型&#xff0c;是一种保存整数的数据类型 1 2 3 4float是一种数据类型&#xff0c;是一种保存浮点数的数据类型 3.14 1.2 什么是地址 内存分配的最小单位是字节&#xf…

19、Flink 的Table API 和 SQL 中的自定义函数及示例(3)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…