首页 > 其他分享 >Minio

Minio

时间:2024-02-20 22:00:32浏览次数:17  
标签:Minio minio fileName bucketName import data String

Minio

1 基于centos7,docker部署

# 直接使用centos7部署,但是只能通过私有ip访问本机,指定公网ip不行
cd /usr/local/
# 获取minio
wget -q http://dl.minio.org.cn/server/minio/release/linux-amd64/minio
# 授予文件权限
chmod +x minio
#启动minio server服务,指定数据存储目录/mnt/data,最好是指定控制台端口,这个方式创建的minio只能通过本机访问。
./minio server /mnt/data --console-address :9090

#docker 成功
#9090是console中控制台访问,9000是容器中api的端口,java代码用的是api的端口
docker run -d -p 9000:9000 -p 9090:9090 --name docker_minio 
-e "MINIO_ROOT_USER=fengpeng" 
-e "MINIO_ROOT_PASSWORD=fengpeng" 
-v /usr/local/minio/data:/data 
-v /usr/local/minio/config:/root/.minio 
#/data 目录设置为MinIO服务器要管理的对象存储数据的目录(-v /usr/local/minio/data:/data )
# minio/minio 是一个 Docker 镜像,用于启动 MinIO 服务器
minio/minio server /data  
--console-address ":9090"

# 如果有错误,通过docker logs 容器ip查看日志

完整语句

docker run -d -p 9000:9000 -p 9090:9090  --name docker_minio -e "MINIO_ROOT_USER=fengpeng" -e "MINIO_ROOT_PASSWORD=fengpeng" -v /usr/local/minio/data:/data -v /usr/local/minio/config:/root/.minio  minio/minio server /data  --console-address ":9090"

image-20240124213042170

2 springboot整合minio

pom.xml

<!--minio依赖-->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.1</version>
</dependency>
<!--minio相关依赖-->
<dependency>
    <groupId>me.tongfei</groupId>
    <artifactId>progressbar</artifactId>
    <version>0.9.5</version>
</dependency>
<!--minio相关依赖-->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>5.0.0-alpha.10</version>
</dependency>

image-20240220214243814

application.yml

#minio配置
minio:
  endpoint: http://8.137.103.17:9000
  accessKey: 
  secretKey: 
  bucketName: test

image-20240220214032257

MinioController

package com.feng.controller;

import com.alibaba.fastjson2.JSON;
import com.feng.utils.DataResult;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Item;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author fengpeng
 * @version V1.0
 * Copyright (c) 2024, [email protected] All Rights Reserved.
 * @ProjectName:big_event
 * @Title: MinioController
 * @Package com.feng.controller
 * @Description: minio控制类
 * @date 2024/1/25 9:35
 */

@RestController
@RequestMapping("/minio")
@Slf4j
public class MinioController {

    @Autowired
    private MinioClient minioClient;

    @Value("${minio.bucketName}")
    private String bucketName;

    @Value("${minio.endpoint}")
    private String endpoint;

    @GetMapping("/list")
    public List<Object> list() throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        //获取bucket列表
        Iterable<Result<Item>> myObjects = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).build());
        Iterator<Result<Item>> iterator = myObjects.iterator();
        List<Object> items = new ArrayList<>();
        String format = "{'fileName':'%s', 'fileSize':'%s'}";
        while (iterator.hasNext()){
            Item item = iterator.next().get();
            items.add(JSON.parse(String.format(format, item.objectName(), formatFileSize(item.size()))));
        }
        return items;
    }

    @PostMapping("/upload")
    public DataResult upload(@RequestParam(name = "file",required = false) MultipartFile[] files) throws Exception {
        if (Objects.isNull(files) || files.length == 0){
            return DataResult.error("请选择文件");
        }

        List<String> orgFileNameList = new ArrayList<>(files.length);
        for (MultipartFile multipartFile : files) {
            //获取文件名
            String orgFileName = multipartFile.getOriginalFilename();
            //用时间作为不重复的名字
            Date date = new Date(System.currentTimeMillis());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
            String fileName = sdf.format(date) + orgFileName.substring(orgFileName.lastIndexOf("."));
            orgFileNameList.add(fileName);
            try {
                InputStream in = multipartFile.getInputStream();
                minioClient.putObject(
                            PutObjectArgs.builder().bucket(bucketName)
                                    .object(fileName)
                                    .stream(in, multipartFile.getSize(),-1)
                                    .contentType(multipartFile.getContentType())
                                    .build());
                in.close();
            } catch (Exception e) {
                log.error(e.getMessage());
                return DataResult.error("上传失败");
            }
        }

        /*Map<String, Object> data = new HashMap<>();
        data.put("bucketName", bucketName);
        //默认获取第一个文件
        data.put("fileName", orgFileNameList.get(0));*/
        /*记得将minio的console的bucket权限设置为public*/
        String fileUrl = endpoint + "/" + bucketName + "/" + orgFileNameList.get(0);
        return DataResult.success(fileUrl);
    }

    @GetMapping("/download")
    public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) throws Exception {
        InputStream in = null;
        try {
            //获取对象信息
            StatObjectResponse stat = minioClient.statObject
                    (StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
            //设置响应头
            response.setContentType(stat.contentType());
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            //文件下载
            in =  minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
            IOUtils.copy(in, response.getOutputStream());
        }catch (Exception e){
            log.error(e.getMessage());
        }finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
    }

    @DeleteMapping("/delete/{fileName}")
    public DataResult delete(@PathVariable("fileName") String fileName) throws Exception {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
        }catch (Exception e){
            log.error(e.getMessage());
            return DataResult.error("删除文件失败");
        }
        return DataResult.success();
    }

    private static String formatFileSize(long fileS) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        String wrongSize = "0B";
        if (fileS == 0) {
            return wrongSize;
        }
        if (fileS < 1024) {
            fileSizeString = df.format((double) fileS) + " B";
        } else if (fileS < 1048576) {
            fileSizeString = df.format((double) fileS / 1024) + " KB";
        } else if (fileS < 1073741824) {
            fileSizeString = df.format((double) fileS / 1048576) + " MB";
        } else {
            fileSizeString = df.format((double) fileS / 1073741824) + " GB";
        }
        return fileSizeString;
    }
}

前端代码

image-20240220214542932

UserAvatar.vue

<script setup>
    import { Plus, Upload } from '@element-plus/icons-vue'
    import {ref} from 'vue'
    import avatar from '@/assets/default.png'
    const uploadRef = ref()
    import {useTokenStore} from '@/stores/token.js'
    const tokenStore = useTokenStore()
    
    import useUserInfoStore from '@/stores/userInfo.js'
    const userInfoStore = useUserInfoStore()
    //用户头像地址
    const imgUrl= ref(userInfoStore.info.userPic)

    //图片上传成功的回调函数
    const uploadSuccess = (res) => {
        imgUrl.value = res.data
    }

    import {updateAvatarUpdateService} from '@/api/user.js'
    import {ElMessage} from 'element-plus'
    //头像修改
    const updateAvatar = async() => {
        //调用接口
        let url = imgUrl.value
        let res = await updateAvatarUpdateService(url.slice(url.lastIndexOf('/') + 1))
        ElMessage.success(res.message ? res.message : '修改成功')

        //修改pinia中的数据
        userInfoStore.info.userPic = imgUrl.value
    }
    
    </script>
    
    <template>
        <el-card class="page-container">
            <template #header>
                <div class="header">
                    <span>更换头像</span>
                </div>
            </template>
            <el-row>
                <el-col :span="12">
                    <el-upload 
                        ref="uploadRef"
                        class="avatar-uploader" 
                        :show-file-list="false"
                        :auto-upload="true"
                        action="/api/minio/upload"
                        name="file"
                        :headers="{'Authorization': tokenStore.token}"
                        :on-success="uploadSuccess"
                        >
                        <!-- 选择图片后,自动上传到服务器,返回图片在服务器上的地址 -->
                        <img v-if="imgUrl" :src="imgUrl" class="avatar" />
                        <!-- 默认图片 -->
                        <img v-else :src="avatar" width="278" />
                    </el-upload>
                    <br />
                    <el-button type="primary" :icon="Plus" size="large"  @click="uploadRef.$el.querySelector('input').click()">
                        选择图片
                    </el-button>
                    <el-button type="success" :icon="Upload" size="large" @click="updateAvatar">
                        上传头像
                    </el-button>
                </el-col>
            </el-row>
        </el-card>
    </template>
    
    <style lang="scss" scoped>
    .avatar-uploader {
        :deep() {
            .avatar {
                width: 278px;
                height: 278px;
                display: block;
            }
    
            .el-upload {
                border: 1px dashed var(--el-border-color);
                border-radius: 6px;
                cursor: pointer;
                position: relative;
                overflow: hidden;
                transition: var(--el-transition-duration-fast);
            }
    
            .el-upload:hover {
                border-color: var(--el-color-primary);
            }
    
            .el-icon.avatar-uploader-icon {
                font-size: 28px;
                color: #8c939d;
                width: 278px;
                height: 278px;
                text-align: center;
            }
        }
    }
    </style>

注意

image-20240220214707372

不设置成Public,无法直接通过返回的图片url访问bucket中的图片

标签:Minio,minio,fileName,bucketName,import,data,String
From: https://www.cnblogs.com/fengpeng123/p/18024146

相关文章

  • docker 搭建最新minio访问不了页面解决
    一.搭建过程#可以查找minio的版本,找到下载次数最多的dockersearchminio#拉取minio镜像dockerpullminio/minio#创建容器,两个key分别是登录的账号和密码,密码必须为8位dockerrun-d-p9000:9000--name=minio--restart=always-e"MINIO_ROOT_USER=admin"-e"M......
  • 集群版 Minio 的部署和使用
    单机版的Minio虽然有纠删码的部署方式,可以防止磁盘损坏导致文件丢失,但是单机毕竟性能有限。集群版Minio必须使用纠删码的部署方式,至少使用4块硬盘进行部署。最简单的部署方式是使用2个docker容器,每个容器使用2个磁盘或目录。本篇博客使用docker-compose在单台虚拟机......
  • 单机版 Minio 的部署和使用
    MinIO基于ApacheLicensev2.0开源协议的对象存储服务,兼容亚马逊S3(SimpleStorageService简单存储服务)云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、静态页面等,一个对象文件可以是任意大小,文件大小最大支持5T。由于采用Golang实现,服务端可以工作在......
  • 分布式文件系统---Minio
    什么是分布式文件系统​ 分布式文件系统(DistributedFileSystem,DFS)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点(可简单的理解为一台计算机)相连;或是若干不同的逻辑磁盘分区或卷标组合在一起而形成的完整的有层次的文件系统。DFS为分......
  • SpringBoot中集成Minio高性能分布式存储文件服务入门
    场景若依前后端分离版手把手教你本地搭建环境并运行项目:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662参考上面搭建项目。MinioMinio是基于Go语言编写的对象存储服务,适合于存储大容量非结构化的数据,例如图片、音频、视频、日志文件、备份数据和容器/......
  • .Net Framework:MinIO objectname异常
     minio-dotnetgithub地址:github.com/minio/minio-dotnet1.异常现象:在调用PutObjectAsync/FileExist/FGetObject等方法操作MinIO时,objectname同时包含汉字、英文括号,MinIO内部throw异常:AuthorizationException:Therequestsignaturewecalculateddoesnotmatchthes......
  • Java中的MinIO应用类--版本2
    1.配置类importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importio.minio.MinioClient;@Configuration@Configuratio......
  • MinIO应用类
    1.配置类importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importio.minio.MinioClient;@Configuration@Configuration......
  • minio 支持基于yaml 的配置管理
    minio23年底的一个版本中,支持了基于yaml的配置参数,以前基于环境变量的模式还是支持的,只是yaml成为一个首选模式参考配置yaml配置version:v1address:':9000'rootUser:'minioadmin'rootPassword:'pBU94AGAY85e'console-address:':9001'certs......
  • playedu存储配置minio
    minio配置新建一个桶Buckets点击管理,Summary,AccessPolicy:复制代码{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{&quo......