搭建高性能分布式存储-minio

news2024/11/19 23:15:13

文章目录

    • 搭建高性能分布式存储-minio
      • Docker搭建minio(单机部署+纠删码模式)⭐
      • 创建minio的bucket(桶)⭐
      • SpringBoot+minio项目实战 ⭐
        • 1:导入minio的maven依赖
        • 2:编写MinioProperties.class
        • 3:application.yml:
        • 4:MinioConfig.class配置类
        • 5:ResponseResult(统一响应结果)
        • 6:ResponseType(响应类型枚举类)
        • 7:UploadController.class(上传接口)
        • 8:上传service接口
        • 9:上传service接口实现类:

搭建高性能分布式存储-minio

Docker搭建minio(单机部署+纠删码模式)⭐

  • 1:使用minio Docker镜像,在在单机中使用EC纠删码模式部署,8块盘中启动minio服务:
    • 注意:MINIO_ROOT_PASSWORD初始化默认密码长度必须要达到8位。
docker run --name minio -d \
    -p 9000:9000 \
    -p 50000:50000 \
    -v /mnt/minio/data1:/data1 \
    -v /mnt/minio/data2:/data2 \
    -v /mnt/minio/data3:/data3 \
    -v /mnt/minio/data4:/data4 \
    -v /mnt/minio/data5:/data5 \
    -v /mnt/minio/data6:/data6 \
    -v /mnt/minio/data7:/data7 \
    -v /mnt/minio/data8:/data8\
    -e MINIO_ROOT_USER="root" \
    -e MINIO_ROOT_PASSWORD="12345678" \
    minio/minio:latest server /data{1...8} --console-address ":50000"
  • 2:访问minio控制台:(http://服务器ip:50000/)

创建minio的bucket(桶)⭐

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

SpringBoot+minio项目实战 ⭐

1:导入minio的maven依赖
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.4.3</version>
</dependency>

<dependency>
     <groupId>commons-io</groupId>
     <artifactId>commons-io</artifactId>
     <version>2.6</version>
</dependency>
2:编写MinioProperties.class
package com.boot.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 高性能分布式存储-minio属性类
 *
 * @author youzhengjie
 * @date 2022/10/28 00:22:48
 */
@Component
@Data
@ConfigurationProperties(prefix = "minio")
@EnableConfigurationProperties({
        MinioProperties.class
})
public class MinioProperties {

    /**
     * minio的通信端点(url),和控制台端点不一样
     */
    private String endpoint;
    /**
     * 说白了就是minio的帐号
     */
    private String accessKey;
    /**
     * 说白了就是minio的密码
     */
    private String secretKey;
    /**
     * 指定操作哪一个桶
     */
    private String bucketName;
}
3:application.yml:
  • 注意:记得把下面的配置属性修改成你自己的!
minio:
  endpoint: http://192.168.184.123:9000
  access-key: root
  secret-key: 12345678
  bucket-name: security-jwt2-bucket
4:MinioConfig.class配置类
  • 作用是将MinioClient交给Spring管理,方便后续直接@AutoWired注入即可使用)
package com.boot.config;

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * minio配置类
 *
 * @author youzhengjie
 * @date 2022/10/28 00:30:31
 */
@Configuration
public class MinioConfig {

    @Autowired
    private MinioProperties minioProperties;


    /**
     * minio-client bean
     *
     * @return {@link MinioClient}
     */
    @Bean
    public MinioClient minioClient(){

        return MinioClient.builder()
                //配置minio的通信端点(url),和控制台端点不一样
                .endpoint(minioProperties.getEndpoint())
                //配置minio的帐号密码
                .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                .build();
    }

}
5:ResponseResult(统一响应结果)
package com.boot.data;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 统一响应结果
 */
@JsonInclude(JsonInclude.Include.NON_NULL) //为null的字段不进行序列化
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResponseResult<T> {

    /**
     * 响应状态码
     */
    private Integer code;

    /**
     * 响应状态码对应的信息提示
     */
    private String msg;

    /**
     * 返回给前端的数据
     */
    private T data;

    public ResponseResult(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public ResponseResult(Integer code, T data) {
        this.code = code;
        this.data = data;
    }

}
6:ResponseType(响应类型枚举类)
package com.boot.enums;

/**
 * 响应类型枚举类
 * @author youzhengjie
 * @date 2022-09-22 22:47:21
 */
public enum ResponseType {

    /**
     * 文件操作状态
     */
    IMAGE_UPLOAD_SUCCESS(901,"图片上传成功"),
    IMAGE_UPLOAD_ERROR(902,"图片上传失败"),
    FILE_FORMAT_UNSUPPORT(903,"不支持该文件格式,上传失败"),
    FILE_DELETE_SUCCESS(904,"文件删除成功"),
    FILE_DELETE_ERROR(905,"文件删除失败"),
    ;

    private int code;
    private String message;

    ResponseType(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
7:UploadController.class(上传接口)
@RestController
@Api("上传接口")
@RequestMapping(path = "/upload")
@Slf4j
public class UploadController {

    @Autowired
    @Qualifier("minioUploadServiceImpl") //指定spring注入的实现类
    private OssUploadService ossUploadService;


    /**
     * 上传头像
     *
     * @param avatarFile 头像文件(名字一定要和el-upload的:name属性一致)
     * @return {@link ResponseResult}
     */
    @OperationLog("上传头像")
    @PostMapping(path = "/avatar")
    @ApiOperation("上传头像")
    public ResponseResult uploadAvatar(MultipartFile avatarFile){

        ResponseResult result = ossUploadService.imageUpload(avatarFile);

        return result;
    }

    /**
     * 文件删除
     *
     * @param fileFullName 文件名
     * @return {@link ResponseResult}
     */
    @OperationLog("文件删除")
    @DeleteMapping(path = "/fileDelete")
    @ApiOperation("文件删除")
    public ResponseResult fileDelete(@RequestParam("fileFullName") String fileFullName){

        return ossUploadService.fileDelete(fileFullName);
    }


    /**
     * 文件下载
     *
     * @param fileName 文件名称
     * @param response 响应
     */
    @GetMapping(path = "/fileDownload")
    @ApiOperation("文件下载")
    public void fileDownload(@RequestParam("fileName") String fileName, HttpServletResponse response){

        ossUploadService.fileDownload(fileName,response);

    }
}
8:上传service接口
package com.boot.service;

import com.boot.data.ResponseResult;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;

/**
 * oss上传service接口
 * @author youzhengjie
 * @date 2022-10-06 23:13:28
 */
public interface OssUploadService {

    /**
     * oss图片上传
     * @param imageFile
     * @return 上传结果
     */
    ResponseResult imageUpload(MultipartFile imageFile);

    /**
     * oss文件删除
     * @param fileFullName 文件全名,
     *
     * @return 删除结果
     */
    ResponseResult fileDelete(String fileFullName);

    /**
     * 文件下载
     *
     * @param fileName 文件名称
     * @param response 响应
     */
    default void fileDownload(String fileName, HttpServletResponse response){

        throw new UnsupportedOperationException("该实现类暂不支持文件下载操作,请切换到其他实现类!");
    }

}
9:上传service接口实现类:
package com.boot.service.impl;

import com.boot.config.MinioProperties;
import com.boot.data.ResponseResult;
import com.boot.enums.ResponseType;
import com.boot.service.OssUploadService;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * minio上传服务service impl
 *
 * @author youzhengjie
 * @date 2022/10/28 13:59:35
 */
@Service("minioUploadServiceImpl")
@Slf4j
public class MinioUploadServiceImpl implements OssUploadService {

    @Autowired
    private MinioProperties minioProperties;

    /**
     * 注入MinioClient,用于操作minio
     */
    @Autowired
    private MinioClient minioClient;



    /**
     * 检查文件是否是图片类型
     * @param originalFilename
     * @return true代表是图片,false则不是图片
     */
    private boolean isImage(String originalFilename){
        //将文件名全部变小写
        String lowerOriginalFilename = originalFilename.toLowerCase();

        return lowerOriginalFilename.endsWith(".jpg") ||
                lowerOriginalFilename.endsWith(".png") ||
                lowerOriginalFilename.endsWith(".jpeg");
    }

    /**
     * minio图片上传
     *
     * @param imageFile 图像文件
     * @return {@link ResponseResult}
     */
    @Override
    public ResponseResult imageUpload(MultipartFile imageFile) {

        //封装响应结果
        ResponseResult<Object> result = new ResponseResult<>();

        try {
            //获取上传前的文件原名
            String oldFileName = imageFile.getOriginalFilename();

            //如果不是图片则直接返回
            if(!isImage(oldFileName)){
                result.setCode(ResponseType.FILE_FORMAT_UNSUPPORT.getCode());
                result.setMsg(ResponseType.FILE_FORMAT_UNSUPPORT.getMessage());
                return result;
            }

            //以日期作为目录,每一天的图片都会放到不同的目录下,方便管理
            String fileDir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd/"));

            //UUID文件名
            String uuidFileName = UUID.randomUUID().toString().replaceAll("-", "");

            //获取文件后缀名 .jpg
            String fileSuffix= oldFileName.substring(oldFileName.lastIndexOf("."));

            //上传到minio中的新的图片文件名
            String newFileName = new StringBuilder()
                    .append(fileDir)
                    .append(uuidFileName)
                    .append(fileSuffix).toString();

            //获取文件流
            InputStream inputStream = imageFile.getInputStream();
            //获取文件大小
            long size = imageFile.getSize();
            //获取内容类型
            String contentType = imageFile.getContentType();

            //构建文件上传所需要的东西(PutObjectArgs)
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(newFileName)
                    .stream(inputStream, size, -1)
                    .contentType(contentType)
                    .build();
            //开始进行minio文件上传
            minioClient.putObject(putObjectArgs);

            //获取该上传到minio的文件的url(使外网可以访问)
            String fileUrl=minioProperties.getEndpoint()+"/"+minioProperties.getBucketName()+"/"+newFileName;
            result.setCode(ResponseType.IMAGE_UPLOAD_SUCCESS.getCode());
            result.setMsg(ResponseType.IMAGE_UPLOAD_SUCCESS.getMessage());
            result.setData(fileUrl);
            return result;
        }catch (Exception e){
            e.printStackTrace();
            result.setCode(ResponseType.IMAGE_UPLOAD_ERROR.getCode());
            result.setMsg(ResponseType.IMAGE_UPLOAD_ERROR.getMessage());
            return result;
        }

    }

    /**
     * minio文件删除
     *
     * @param fileFullName 文件全名 。格式例如:2022/10/28/4f74aa358a4548d4860c110ebec3831f.jpg
     * @return {@link ResponseResult}
     */
    @Override
    public ResponseResult fileDelete(String fileFullName) {

        //封装响应结果
        ResponseResult<Object> result = new ResponseResult<>();

        try {
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(fileFullName)
                    .build();
            minioClient.removeObject(removeObjectArgs);
            result.setCode(ResponseType.FILE_DELETE_SUCCESS.getCode());
            result.setMsg(ResponseType.FILE_DELETE_SUCCESS.getMessage());
            return result;
        }catch (Exception e){
            e.printStackTrace();
            result.setCode(ResponseType.FILE_DELETE_ERROR.getCode());
            result.setMsg(ResponseType.FILE_DELETE_ERROR.getMessage());
            return result;
        }
    }


    /**
     * minio文件下载。
     *
     * @param fileName 文件名称 。格式例如:2022/10/28/4f74aa358a4548d4860c110ebec3831f.jpg
     * @param response 响应
     */
    @Override
    public void fileDownload(String fileName, HttpServletResponse response) {

        try {

            // 获取对象信息
            StatObjectArgs statObjectArgs = StatObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(fileName)
                    .build();
            StatObjectResponse statObject = minioClient.statObject(statObjectArgs);

            /**
             * 描述: content-type 指示响应内容的格式
             * content-disposition 指示如何处理响应内容。
             * 一般有两种方式:
             * inline:直接在页面显示-预览
             * attachment:以附件形式下载-下载
             */
            response.setContentType(statObject.contentType());
//            response.setHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            response.setHeader("Content-Disposition", "attachment; filename=" +
                    URLEncoder.encode(fileName, "UTF-8"));

            InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .object(fileName)
                    .build());

            IOUtils.copy(inputStream,response.getOutputStream());
        }catch (Exception e){
           throw new RuntimeException("文件下载失败");
        }

    }
}

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

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

相关文章

浪潮信息G7服务器智能高效的运维秘籍

数据中心的运维压力到底有多大&#xff1f;过去&#xff0c;IT圈里流传着这样一句话&#xff1a;一入运维深似海&#xff0c;从此下班是路人。随着人工智能、大数据、云计算等技术的成熟应用&#xff0c;数据中心走向集约化、规模化的趋势&#xff0c;数据中心的IT设备越来越繁…

基于platform驱动模型完成LED驱动的编写

添加设备树文件信息 myplatform{compatible"hqyj,myplatform";//厂商信息&#xff0c;用于驱动端进行匹配interrupt-parent<&gpiof>; //关联中断父节点interrupts<9 0>; //和中断父节点的关系描述符led1-gpio<&gpioe 10 0>; led2-gpio<…

Unreal UMG MVVM

Unreal UMG MVVM 文章目录 Unreal UMG MVVM背景M - VM - V扩展点 Editortime Viewmodels 编辑器界面View Bindings 编辑器界面蓝图编译相关 Runtime 创建 ViewModelViewModel 更新 背景 先阅读文档和 quabqi 的 UOD 视频分享&#xff0c;目前网上唯一的资料看眼成熟的巨硬方案…

回溯法(2)--图着色问题和旅行商问题

目录 一、图着色问题 1、算法设计 2、代码 二、旅行商问题 1、概述问题 2、穷举法 3、回溯法 一、图着色问题 1、算法设计 图着色问题&#xff0c;给定图中各个区域的相邻关系&#xff0c;抽象成一个无向图G&#xff08;V,E&#xff09;&#xff0c;给定m种颜色&…

【HarmonyOS】服务卡片 API6 JSUI跳转不同页面并携带参数

【关键字】 服务卡片、卡片跳转不同页面、卡片跳转页面携带参数 【写在前面】 本篇文章主要介绍开发服务卡片时&#xff0c;如何实现卡片点击跳转不同页面&#xff0c;并携带动态参数到js页面。在此篇文章“服务卡片 API6 JSUI跳转不同页面”中说明了如果跳转不同页面&#xf…

十、W5100S/W5500+RP2040树莓派Pico<PING(ICMP)检测网络连通性>

文章目录 1 前言2 协议简介2.1 什么是PING2.2 PING的优点2.3 PING的原理2.4 应用场景 3 WIZnet以太网芯片4 PING网络设置示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 烧录验证 5 注意事项6 相关链接 1 前言 随着网络应用的日益丰富和普及&…

代码随想录打卡第五十六天|1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和

1143.最长公共子序列 题目&#xff1a; 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的…

iPhone听筒声音小怎么办?分享5种修复方法!

最近有小伙伴反映&#xff1a;苹果手机使用了一段时间后&#xff0c;听筒声音突然变小了&#xff0c;这是什么情况&#xff1f;这确实是一个让人感到困扰的问题&#xff0c;特别是在进行重要通话的时候&#xff0c;如果听不到对方说话&#xff0c;那场面将会十分尴尬。那么&…

C语言--顺序查找、折半查找

顺序查找 实现逻辑 顺序查找&#xff08;sequential search&#xff09;就是按照数组的顺序一 一比较数组中的元素的值和所查找的值。如下图表所示&#xff0c;遍历数组进行比较。若找到&#xff0c;则break跳出循环。 a[0]a[1]a[2]a[3]a[4]912221334229?2212?2222? 实现…

出海数字化,国产CRM如何支撑?纷享销客这样思考

2023年&#xff0c;疫情阴霾逐渐消散&#xff0c;企业全球化扩张的齿轮重新加速。以科技企业、高端制造业为代表的优秀企业引领中国企业出海浪潮&#xff0c;外资企业在华的经营活跃度也在提升。 无论是”外资在华经营“还是”中资出海“&#xff0c;这些具备全球化理想的企业…

0代码0侵入的安卓骨架屏框架----二期优化

本文是对自定义骨架屏框架的优化说明。 针对目前对骨架屏的需求及为了实现骨架屏而付出的繁重劳动&#xff0c;而设计的一款0编码0业务侵入的骨架屏框架。感兴趣的可以先去看看这篇文章&#xff1a;一种简单的Android骨架屏实现方案----0侵入0成本 额&#xff0c;如果不看&am…

玻色量子成功研制光量子计算专用光纤恒温控制设备——“量晷”

​近日&#xff0c;北京玻色量子科技有限公司&#xff08;以下简称“玻色量子”&#xff09;成功研制出一款高精度量子计算专用光纤恒温控制设备——“量晷”&#xff0c;该设备能将光纤的温度变化稳定在千分之一摄氏度量级&#xff0c;即能够做到0.001C的温度稳定维持&#xf…

5道谷歌面试题:即使是天才也要怀疑自己能力了(附GPT4答案)

谷歌google&#xff0c;美国的跨国科技企业&#xff0c;致力于互联网搜索、云计算、广告技术等领域&#xff0c;开发并提供大量基于互联网的产品与服务。 这样一家实力雄厚前景无量的公司是众多求职者梦寐以求的地方&#xff0c;然而&#xff0c;谷歌的面试题却把很多优秀人才…

技术贴 | 一文掌握 Google Test 框架

一、简介 1. 引言 在开发过程中&#xff0c;如何保证代码的质量以及程序的正确性成为了我们亟需解决的问题&#xff0c;其中测试用例成为了不必可少的一部分。测试用例不仅可以帮助我们验证代码的正确性&#xff0c;还能帮助我们捕获潜在的错误&#xff0c;提高代码的可靠性和…

IO模块:钢铁安全绿色生产的智能化助手

钡铼I/O模块以其卓越的性能和可靠性&#xff0c;为钢铁行业的安全绿色生产提供了强有力的支持。这个模块拥有出色的实时监测功能&#xff0c;能够精确捕捉现场设备的工作状态&#xff0c;确保设备的正常运行。通过采用先进的预测性维护技术&#xff0c;钡铼I/O模块能够提前发现…

传统金融机构加入代币化浪潮,新一轮加密周期的重要组成部分?

新加坡金融管理局 (MAS) 成立了由日本金融厅 (FSA)、英国金融行为监管局 (FCA) 和瑞士金融市场监管局 (FINMA) 组成“守护者计划”政策制定者组&#xff08;Project Guardian&#xff09;&#xff0c;正在计划对固定收益、外汇和资产管理产品进行资产代币化试点&#xff0c;以推…

Python 的 Web 自动化测试的实践

Web 测试是软件测试中比较重要的一个分支&#xff0c;而要实现 Web 自动化测试则要求测试人员能熟练掌握自动化测试工具和编程语言。介绍免费开源的 Web 测试工具 Selenium&#xff0c;以及流行的编程语言 Python。根据自动化测试的原理&#xff0c;对网页元素的常用定位方式&a…

smartLink HW-DP新版提供更多扩展功能——用于PROFIBUS和HART系统中物联网集成

Softing工业自动化的smartLink HW-DP网关可独立于控制器访问PROFIBUS DP网络&#xff0c;且新发布的1.30固件版本还提供了更多数据连接和传输的扩展功能。 smartLink HW-DP可无缝集成到PROFIBUS网络中&#xff0c;而不会影响现有设备的运行。该网关还可为新的和现有的PROFIBUS …

非常爆火的流量卡推广上线了

流量卡推广可以通过“聚量推文”申请&#xff0c;一手渠道 现在非常火的推广项目就是流量卡推广了&#xff0c;佣金价格高 普遍的价格是几十上百块&#xff0c;你一天推广10个收入就接近4位数&#xff0c;还是比较可观的 聚量推客专注于app拉新&#xff0c;网推项目&#xff…

博客系统-项目测试

自动化博客项目 用户注册登录验证效验个人博客列表页博客数量不为 0 博客系统主页写博客 我的博客列表页效验 刚发布的博客的标题和时间查看 文章详情页删除文章效验第一篇博客 不是 "自动化测试" 注销退出到登录页面,用户名密码为空 用户注册 Order(1)Parameterized…