对象存储服务-MinIO基本集成

news2025/1/23 22:30:23

是什么

MinIO 是一个高性能的分布式对象存储服务,适合存储非结构化数据,如图片,音频,视频,日志等。对象文件最大可以达到5TB。

安装启动

mkdir -p  /usr/local/minio
cd /usr/local/minio

# 下载安装包
wget https://dl.min.io/server/minio/release/linux-amd64/minio

下载完毕后:

在当前minio目录下,会出现一个minio文件

# 给予权限
chmod +x minio

# 创建minio文件存储目录及日志目录
mkdir -p /usr/local/minio/data
mkdir -p /usr/local/minio/logs

然后在 /usr/local/minio/目录下,新建一个run.sh并编辑以下内容

vim run.sh,然后将以下内容保存到run.sh,并为其赋予执行权限chmod u+x run.sh

run.sh内容如下:

#!/bin/bash
export MINIO_ACCESS_KEY=minio
export MINIO_SECRET_KEY=minio123456
# nohup启动服务 指定文件存放路径 /root/data 还有设置日志文件路径 /root/minio/log
nohup ./minio server --address :9000 --console-address :9001 /usr/local/minio/data > /usr/local/minio/logs/minio.log 2>&1 &

启动minIO

# 启动minio服务
./run.sh
# 查看日志
tail -f /usr/local/minio/logs/minio.log 

平台使用

地址:http://127.0.0.1:9000(注意开放对应端口9000、9001)【当端口 9000 用于连接到 API 时,MinIO 会自动将浏览器访问重定向到 MinIO 控制台9001。】

输入账号密码后,

创建bucket,名字随意,创建完成后服务器/usr/local/minio/data下也会创建这个文件目录

image-20230817143405545
image-20230818141243167
http://www.dedeyun.com/it/java/102599.html

SpringBoot集成MinIO

1.添加依赖

            <dependency>
                <groupId>io.minio</groupId>
                <artifactId>minio</artifactId>
                <version>8.4.1</version>
            </dependency>

2.配置文件

spring:
  minio:
    endpoint: http://124.222.253.33:9000
    access-key: minio
    secret-key: minio123456
    bucket-name: file
  servlet:
    multipart: # 上传文件最大大小
      max-file-size: 1024MB
      max-request-size: 1024MB

3.配置类创建客户端

@Data
@Component
@ConfigurationProperties(prefix = "spring.minio")
public class MinioConfig {

    private String endpoint;

    private String accessKey;

    private String secretKey;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }
}

4.核心业务类

仅有一些基础操作

@Slf4j
@Service
public class FileService {

    @Autowired
    private MinioClient minioClient;

    private static final String SEPARATOR = "/";

    @Value("${spring.minio.bucket-name}")
    private String bucketName;

    /**
     * 上传文件
     *
     * @param file 文件对象
     * @param id   设备ID
     */
    public void uploadFile(MultipartFile file, Long id) {
        try {
            // 创建bucket
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }

            // 同名文件会进行覆盖
            String objectName = file.getOriginalFilename();

            @Cleanup
            InputStream inputStream = file.getInputStream();
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(id + SEPARATOR + objectName) // 多文件夹
                            .stream(inputStream, file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build());

        } catch (Exception e) {
            log.error("文件上传失败!{}", e.getMessage());
            throw new RuntimeException("文件上传失败,请重新上传");
        }
    }

    /**
     * 删除文件
     *
     * @param path 文件路径
     */
    public void removeObject(String path) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(path)
                    .build());
        } catch (Exception e) {
            log.error("文件删除失败!{}", e.getMessage());
            throw new RuntimeException("文件删除失败,请重新删除");
        }
    }

    /**
     * 文件列表
     *
     * @param id 设备ID
     */
    public List<FileInfo> listFiles(Long id) {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).recursive(true).build());

        List<FileInfo> infos = new ArrayList<>();
        results.forEach(r -> {
            FileInfo info = new FileInfo();
            try {
                Item item = r.get();
                // 最多一层文件夹
                String path = item.objectName();
                int idx = path.indexOf(SEPARATOR);
                if (path.substring(0, idx).equals(id.toString())) {
                    info.setPath(path);
                    info.setFileName(path.substring(idx + 1));
                    info.setSize(item.size());
                    infos.add(info);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        return infos;
    }

    /**
     * 下载文件
     *
     * @param response response
     * @param path     文件路径
     */
    public void downFile(HttpServletResponse response, String path) {
        try {
            @Cleanup
            OutputStream outputStream = response.getOutputStream();
            @Cleanup
            InputStream inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(this.bucketName)
                    .object(path).build());
            response.reset();
            String fileName = path.substring(path.indexOf(SEPARATOR) + 1);
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    URLEncoder.encode(fileName.substring(fileName.lastIndexOf(SEPARATOR) + 1), "UTF-8"));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("UTF-8");
            FileCopyUtils.copy(inputStream, outputStream);
        } catch (Throwable e) {
            log.error("文件下载失败!{}", e.getMessage());
            throw new RuntimeException("文件下载失败,请重新下载");
        }
    }
}

controller

@RestController
public class FileController {

    @Autowired
    private FileService fileService;

    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file, Long id) {
        fileService.uploadFile(file, id);
        return "上传成功";
    }

    @GetMapping("/download")
    public String downloadFile(HttpServletResponse response, String path) {
        fileService.downFile(response, path);
        return "下载成功";
    }

    @DeleteMapping("/delete")
    public String deleteFile(String path) {
        fileService.removeObject(path);
        return "删除成功";
    }

    @GetMapping("/list")
    public List<FileInfo> listFiles(Long id) {
        return fileService.listFiles(id);
    }
}

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

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

相关文章

NextJs - Error Handling (错误处理)

Error.js 的作用 使用 error.js 文件规则&#xff0c;可以优雅地处理嵌套路由中的意外运行时错误。 在 React Error Boundary 中自动封装路由段及其嵌套子段。 使用文件系统层次结构来调整粒度&#xff0c;为特定网段量身定制错误 UI。 将错误隔离到受影响的网段&#xff0…

红帆OA SQL注入漏洞复现

0x01 产品简介 红帆iOffice.net从最早满足医院行政办公需求&#xff08;传统OA&#xff09;&#xff0c;到目前融合了卫生主管部门的管理规范和众多行业特色应用&#xff0c;是目前唯一定位于解决医院综合业务管理的软件&#xff0c;是最符合医院行业特点的医院综合业务管理平…

怎么修改图片的分辨率?

怎么修改图片的分辨率&#xff1f;很多人还不知道分辨率是什么意思&#xff0c;以为代表了图片的清晰度&#xff0c;然而并不是这样的&#xff0c;其实图片的分辨率就是图片尺寸大小的意思。修改图片的分辨率即改变图片的尺寸&#xff0c;通常以像素为单位表示。分辨率决定了图…

【腾讯云Cloud Studio实战训练营】使用Cloud Studio社区版快速构建React完成点餐H5页面还原

陈老老老板&#x1f9b8; &#x1f468;‍&#x1f4bb;本文专栏&#xff1a;生活&#xff08;主要讲一下自己生活相关的内容&#xff09; &#x1f468;‍&#x1f4bb;本文简述&#xff1a;生活就像海洋,只有意志坚强的人,才能到达彼岸。 &#x1f468;‍&#x1f4bb;上一篇…

如何优雅做好项目管理?

导言 项目本身无好坏之分&#xff0c;项目管理有做好与做坏之别。在互联网大厂的体制下&#xff0c;想要做坏一个项目很难&#xff08;可以通过换人、追加资源等方式消除风险&#xff09;&#xff0c;想要做好一个项目不容易&#xff0c;需要团队及PM付出大量心血和精力。在这…

实时业务需求和数据处理要求的满足:流处理的能力

随着数据量和数据种类的不断增加&#xff0c;企业和组织对于实时数据处理和业务响应的需求也越来越迫切。传统的批处理方式无法满足业务对于实时性和即时响应的要求&#xff0c;因此&#xff0c;流处理技术应运而生。通过流处理能力&#xff0c;可以有效地处理实时数据&#xf…

Python爬虫常用:谷歌浏览器驱动——Chromedriver 插件安装教程

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 我们在做爬虫的时候经常要使用谷歌浏览器驱动&#xff0c;今天分享下这个Chromedriver 插件的安装方法。 话不多说&#xff0c;直接开搞&#xff0c;如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 第一步、打开谷…

VR仿真实训系统编辑平台赋予老师更多自由和灵活性

为了降低院校教师在VR虚拟现实方面应用的门槛&#xff0c;VR公司深圳华锐视点融合多年的VR虚拟仿真实训系统制作经验&#xff0c;制作了VR动物课件编辑器&#xff0c;正在逐渐受到师生们的关注和应用。 简单来说&#xff0c;VR畜牧专业课件编辑器是一种可以制作虚拟现实动物教学…

【LeetCode】696 . 计数二进制子串

696 . 计数二进制子串&#xff08;简单&#xff09; 思路 我们可以将字符串按照 0 和 1 的连续段分组&#xff0c;存在 count 数组中。例如 00111011 可以得到&#xff1a;count {2,3,1,2}。这里 count 数组中两个相邻的数一定代表的是两种不同的字符。假设 count 数组中两个相…

vue3生成点选验证码,前端校验

先看效果图 verify.vue&#xff1a;源码{用时一天半的破轮子}&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; <template><div class"outside" ref&q…

寻路算法小游戏

寻路算法小demo 寻路算法有两种&#xff0c;一种是dfs 深度优先算法&#xff0c;一种是 dfs 深度优先算法 深度优先搜索的步骤分为 1.递归下去 2.回溯上来。顾名思义&#xff0c;深度优先&#xff0c;则是以深度为准则&#xff0c;先一条路走到底&#xff0c;直到达到目标。这…

spring的核心技术---bean的生命周期加案例分析详细易懂

目录 一.spring管理JavaBean的初始化过程&#xff08;生命周期&#xff09; Spring Bean的生命周期&#xff1a; 二.spring的JavaBean管理中单例模式及原型&#xff08;多例&#xff09;模式 2.1 . 默认为单例&#xff0c;但是可以配置多例 2.2.举例论证 2.2.1 默认单例 2.2…

什么是报表测试?报表测试有哪些?

报表测试主要分为&#xff1a;报表界面测试、报表安全性、报表准确性、报表展示速度&#xff08;也就是性能&#xff09;。 数据准确性测试 报表测试的系统分为两类&#xff0c;一类是业务系统中&#xff0c;带有统计分析功能模块&#xff0c;该模块中包含分析报表&#xff0c;…

Docker碎碎念

docker和虚拟机的区别 虚拟机&#xff08;VM&#xff09;是通过在物理硬件上运行一个完整的操作系统来实现的。 每个虚拟机都有自己的内核、设备驱动程序和用户空间&#xff0c;它们是相互独立且完全隔离的。 虚拟机可以在不同的物理服务器之间迁移&#xff0c;因为它们是以整…

【仿写tomcat】六、解析xml文件配置端口、线程池核心参数

线程池改造 上一篇文章中我们用了Excutors创建了线程&#xff0c;这里我们将它改造成包含所有线程池核心参数的形式。 package com.tomcatServer.http;import java.util.concurrent.*;/*** 线程池跑龙套** author ez4sterben* date 2023/08/05*/ public class ThreadPool {pr…

社科院与美国杜兰大学金融管理硕士项目——畅游于金融世界

随着社会经济的不断发展&#xff0c;职场竞争愈发激烈&#xff0c;很多同学都打算通过报考研究生来实现深造&#xff0c;提升自己的综合能力和竞争优势&#xff0c;获得优质的证书。而对于金融专业的学生和在职人员来说&#xff0c;社科院与美国杜兰大学金融管理硕士项目是一个…

ElasticSearch7.x + kibana7.x使用记录

目录 查询所有索引 查询索引的mapping信息 添加索引的同时添加mapping 在原有基础上新增字段 旧的索引迁移到新的索引&#xff08;使用场景&#xff1a;数据迁移、索引优化、数据转换&#xff09; 查询索引下的文档总数 场景1&#xff1a;某一个字段的值是数组&#xff0…

数据的深海潜行:数据湖、数据仓库与数据湖库之间的微妙关系

导言&#xff1a;数据的重要性与存储挑战 在这个信息爆炸的时代&#xff0c;数据已经成为企业的核心资产&#xff0c;而如何高效、安全、便捷地存储这些数据&#xff0c;更是每个组织面临的重大挑战。 数据作为组织的核心资产 数据在过去的几十年里从一个辅助工具演变成企业的…

视频怎么转换成gif表情包?三步完成视频在线转gif

小伙伴们在使用gif表情包的时候&#xff0c;都会注意到有些是视频片段&#xff0c;其实视频转换成gif动图已经很常见了&#xff0c;今天就来给大家演示一下使用视频转gif工具&#xff08;https://www.gif.cn&#xff09;来将视频在线转gif&#xff0c;一起来学习一下吧。 打开…