minio 分布式对象存储

分布式文件系统应用

1.1、Minlo 介绍

Minlo 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几 kb到最大5T不等。

MinIo是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。

官网: https://min.io/ http://www.minio.org.cn/
对象存储服务 (Obiect Storage Servie,OSS) 是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。
对于中小型企业,如果不选择存诸上云,那么 Minio 是个不错的选择,麻雀虽小,五脏俱全。当然 Minio 除了直接作为对象存储使用,还可以作为云上对象存储服务的网关层,无缝对接到 Amazon S3、MicroSoft Azure。

在中国: 阿里巴巴、腾讯、百度、中国联通、华为、中国移动等等9000多家企业也都在使用MinlO产品。

Docker 部署minio

java 复制代码
1. 拉取minio镜像
docker pull minio/minio
2. 打包并运行容器
docker run -p 9000:9000 -p 9090:9090 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=admin" -e "MINIO_SECRET_KEY=admin123456" -v /usr/docker/minio/data:/data -v /usr/docker/minio/config:/root/.minio minio/minio  server /data --console-address ":9090" -address ":9000"
#解释 9090 端口是控制台端口,9000是api接口
# 账号:MINIO_ACCESS_KEY=admin
# 密码:MINIO_SECRET_KEY=admin123456
# -v 文件映射 宿主机路径 /usr/docker/minio/data 映射到 docker容器的/data
# 宿主机路径/usr/docker/minio/config  映射到 docker容器的 /root/.minio minio/minio
# --address ":9000" minio 对外提供服务的api端口
# --console-address ":9090" minio后台管理端的端口

http://ip:9090/login

账号: admin 密码:admin123456

java 复制代码
创建一个bucket 桶,命名为: mybucket
java 复制代码
创建一个用户,为了生成 accessKey  和 secretKey 
选项都打上对钩

整合 springboot 上传下载

java 复制代码
        <!--minio-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.2.0</version>
        </dependency>
java 复制代码
import io.minio.MinioClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MinioConfig {

    // #对象存储服务的URL
    public static  String url = "http://ip:9000";
    // #账户
    public  static  String accessKey = "root";
    // #密码
    public  static String secretKey = "root123456";;

    // #桶名称
    public  static String bucketName = "mybucket";;


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

}
java 复制代码
import io.minio.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

@Component
public class MinioUtil {
    @Autowired
    private MinioClient minioClient;
    /**
     * 捅名称
     */
    private String bucketName = MinioConfig.bucketName;

    /**
     * putObject上传文件
     *
     * @param file 文件
     * @return filePath
     */
    public String putObject(MultipartFile file) throws Exception{
        //文件名
        String originalFilename = null;
        //文件流
        InputStream inputStream = null;
        Long size = null;
        String filePath = null;
        try {
            originalFilename = file.getOriginalFilename();
            inputStream = file.getInputStream();
            //文件大小
            size = file.getSize();
            //文件路径
            filePath = createFilePath(originalFilename);
            System.out.println(filePath+"\t文件路径");
            //存储方法 putObject
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(filePath)
                    .stream(inputStream, size, -1)
                    .contentType(file.getContentType())
                    .build());
        }finally {
            inputStream.close();
        }
        return filePath;
    }


    /**
     * 下载文件
     *
     * @param filePath 文件路径
     */
    public void getObject(HttpServletResponse httpServletResponse, String filePath) throws  Exception {
        String fileName = getFileName(filePath);
        InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(filePath)
                .build());
        downloadFile(httpServletResponse, inputStream, fileName);
    }

    /**
     * 获取文件路径
     *
     * @param originalFilename 原始文件名称
     * @return FilePath
     */
    public String createFilePath(String originalFilename) {
       // 获取文件名后缀 ,如果没有后缀就获取全文件名
        int dotIndex = originalFilename.lastIndexOf(".");
        String fileExtension = "";
        if (dotIndex != -1) {
            fileExtension = UUID.randomUUID().toString().replace("-","")+"."+originalFilename.substring(dotIndex + 1);
        } else {
            fileExtension = originalFilename;
        }
        return new SimpleDateFormat("yyyy/MM/dd").format(new Date()) + "/" + fileExtension;
    }

    /**
     * 根据文件路径获取文件名称
     *
     * @param filePath 文件路径
     * @return 文件名
     */
    public String getFileName(String filePath) {
        String[] split = StringUtils.split(filePath, "/");
        return split[split.length - 1];
    }

    /**
     * 下载文件
     *
     * @param httpServletResponse httpServletResponse
     * @param inputStream         inputStream
     * @param fileName            文件名
     * @throws IOException IOException
     */
    public void downloadFile(HttpServletResponse httpServletResponse, InputStream inputStream, String fileName) throws IOException {
        //设置响应头信息,告诉前端浏览器下载文件
        httpServletResponse.setContentType("application/octet-stream;charset=UTF-8");
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        //获取输出流进行写入数据
        OutputStream outputStream = httpServletResponse.getOutputStream();
        // 将输入流复制到输出流
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        // 关闭流资源
        inputStream.close();
        outputStream.close();
    }

}
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping(value = "/file")
public class FileController {

    @Autowired
    MinioUtil minioUtil;

    @PostMapping("/upload")
    public String upload(@RequestPart MultipartFile file) {
        String filePath;
        try {
            filePath = minioUtil.putObject(file);
        } catch (Exception e) {
            e.printStackTrace();
            return ("上传失败");
        }
        return filePath;
    }

    @GetMapping("/download")
    public void download(HttpServletResponse response, @RequestParam(value = "filepath") String filepath)  {
        try {
            minioUtil.getObject(response, filepath);
        } catch (Exception e) {
           response.setStatus(500);
            e.printStackTrace();
        }
    }

}

测试,上传可以返回路径,桶内也有上传文件

nginx 指向静态文件夹,不预览,输入文件名全路径直接下载(docker 映射的文件存储位置),文件夹赋予 777 权限

kkfileview 可以查看


javascript 复制代码
<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/js-base64@3.7.2/base64.min.js"></script>
    </head>
 
    <script>
        var url = 'http://服务器IP/down/2023/12/22/ea5ed092c5be423da86ea5e5e5e6c2f4.html'; //文件地址
        window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(Base64.encode(url)));
    </script>
</html>
相关推荐
运维&陈同学2 小时前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列
时差9532 小时前
Flink Standalone集群模式安装部署
大数据·分布式·flink·部署
菠萝咕噜肉i2 小时前
超详细:Redis分布式锁
数据库·redis·分布式·缓存·分布式锁
只因在人海中多看了你一眼5 小时前
分布式缓存 + 数据存储 + 消息队列知识体系
分布式·缓存
zhixingheyi_tian8 小时前
Spark 之 Aggregate
大数据·分布式·spark
求积分不加C9 小时前
-bash: ./kafka-topics.sh: No such file or directory--解决方案
分布式·kafka
nathan05299 小时前
javaer快速上手kafka
分布式·kafka
谭震鸿13 小时前
Zookeeper集群搭建Centos环境下
分布式·zookeeper·centos
天冬忘忧18 小时前
Kafka 工作流程解析:从 Broker 工作原理、节点的服役、退役、副本的生成到数据存储与读写优化
大数据·分布式·kafka
IT枫斗者1 天前
如何解决Java EasyExcel 导出报内存溢出
java·服务器·开发语言·网络·分布式·物联网