minIO安装教程及代码使用

如果您看着CSDN格式觉得不舒服,可以移步我的语雀该篇文章:

《minIO》https://www.yuque.com/docs/share/d9cd6a86-da8a-41b3-af56-6f357fad96cb?#%20%E3%80%8AminIO%E3%80%8B

目录

1、安装

1.1、Linux安装

1.2、Docker安装

1.3、Docker纠删码模式安装

1.4、分布式集群安装

2、代码实现

3、使用MinIO


1、安装

安装请按照英文官网,中文官网更新不及时。或者看我也可以!

1.1、Linux安装

1、先新建个你喜欢的目录,例如:mkdir -p /usr/local/minio

2、执行:wget https://dl.min.io/server/minio/release/darwin-amd64/minio

3、给文件夹赋权:chmod +x minio

PS:正常的目录应该是白色,赋权后应该是绿色,反正不是白色就对了

4、可以运行了:./minio /xxxxxxxxx/data

PS:启动minio server服务,指定数据存储目录/xxxxxxxxx/data

5、启动成功后,会出现红色Warning,不要慌

它的大概意思是告诉你:

一、这种方式启动,端口是随机的,下次再启动minIO端口就不一定是啥了

二、建议你用别的用户名,密码

解决:

一、添加用户名密码到环境变量:

export MINIO_ROOT_USER=admin

export MINIO_ROOT_PASSWORD=12345678

PS:长度要在8位以上,至于为啥,往后看

二、指定端口号启动:

./minio server --console-address ":50000" /xxxxxxxxx/data

PS:相较于第四步多了--console-address指定端口号启动

6、访问:http://xxxxx:50000/dashboard

1.2、Docker安装

1、新建挂载数据卷目录,例如:/mydata/minio/data/mydata/minio/config

2、拉取镜像:docker pull minio/minio

3、运行镜像

docker run -d -p 9000:9000 -p 50000:50000 --name minio \
  -v /mydata/minio/data:/data \
  -v /mydata/minio/config:/root/.minio \
  -e "MINIO_ROOT_USER=admin" \
  -e "MINIO_ROOT_PASSWORD=123456789" \
  minio/minio server --console-address ":50000" /data

解释为什么密码长度要最短8位,这里分享下我遇见的故障:

第一次运行的时候,也是使用-d后台运行,镜像启动之后,执行docker ps -a命令,看不到minio的运行端口号,执行docker ps命令查看镜像启动失败。

所以我使用控制台输出信息方式运行镜像(就是去掉-d命令)

它是告诉我,密码最少是8位。。。。

总结!!!以小窥大,告诉我们要养成看日志的习惯

4、访问:IP+端口号

1.3、Docker纠删码模式安装

docker run -d -p 9000:9000 -p 50000:50000 --name minio \
-v /mydata/minio/data1:/data1 \
-v /mydata/minio/data2:/data2 \
-v /mydata/minio/data3:/data3 \
-v /mydata/minio/data:/data4 \
-v /mydata/minio/data5:/data5 \
-v /mydata/minio/data:/data6 \
-v /mydata/minio/data7:/data7 \
-v /mydata/minio/data8:/data8 \
minio/minio server /data{1...8} --console-address ":50000"

1.4、分布式集群安装

自行百度吧,我买的腾讯云现成的。。。

2、代码实现

建议您呢,新建一个Spring Boot工程,复制下面我的代码,代码很简单,吸收了之后,再运用到你的项目

config:

package com.greedy.minio.config;

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: Greedy
 * @Date: Created in:2022-09-15
 * Description:
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {

    /**
     * 对象存储服务的 URL
     */
    private String endpoint;

    /**
     * 用户名
     */
    private String accessKey;

    /**
     * 密码
     */
    private String secretKey;

    /**
     * 存储桶名称
     */
    private String bucketName;

    /**
     * 预览到期时间(小时)
     */
    private Integer previewExpiry;

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

controller:

package com.greedy.minio.controller;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.greedy.minio.pojo.FileUploadBody;
import com.greedy.minio.service.MinioService;
import com.greedy.minio.utils.Msg;
import com.greedy.minio.vo.FileVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.List;


/**
 * @Author: Greedy
 * @Date: Created in:2022-09-15
 * Description:
 */
@RestController
@Slf4j
public class MinioController {

    private final MinioService minioService;

    public MinioController(MinioService minioService) {
        this.minioService = minioService;
    }

    /**
     * 上传文件
     *
     * @param body
     * @return
     */
    @PostMapping("/upload")
    public Msg upload(FileUploadBody body) {
        List<FileVo> list = null;
        if (ObjUtil.isNull(body.getFiles())) {
            return Msg.ERROR.setNewMsg("上传文件不能为空");
        }
        try {
            list = minioService.uploadFile(body);
            log.info("文件上传成功,文件名称:{},bucket名称:{}", body.getFileName(), body.getBucket());
        } catch (Exception e) {
            log.error("文件上传失败,文件名称:{},bucket名称:{},错误信息:", body.getFileName(), body.getBucket(), e);
            return Msg.UPLOAD_ERROR;
        }
        return Msg.UPLOAD_SUCCESS.setNewData(list);
    }

    /**
     * 获取预览地址
     *
     * @param fileName   文件名
     * @param bucketName 桶名
     * @return
     */
    @GetMapping("/getPreviewUrl")
    public Msg getPreviewUrl(@RequestParam("fileName") String fileName, @RequestParam("bucketName") String bucketName) {
        String url = minioService.getPreviewUrl(fileName, bucketName);
        String previewUrl = null;
        try {
            if (url == null || StrUtil.isBlank(url)) {
                return Msg.SUCCESS.setNewMsg("不好意思,没查着该文件");
            }
            // 前端返回格式:ip:端口/桶名/文件名
            previewUrl = url.substring(0, url.indexOf("?"));
        } catch (Exception e) {
            log.error("预览文件地址错误,文件名为:{},bucket名为:{},错误信息为:", fileName, bucketName, e);
        }
        log.info("文件查找成功,文件预览地址为:{},文件名:{},bucket:{}", previewUrl, fileName, bucketName);
        return Msg.SUCCESS.setNewData(previewUrl);
    }

    /**
     * 下载文件
     *
     * @param response
     * @param fileName   文件名
     * @param bucketName 桶名
     * @return
     */
    @PostMapping("/download")
    public Msg download(HttpServletResponse response, @RequestParam("fileName") String fileName, @RequestParam("bucketName") String bucketName) {
        try {
            minioService.downloadFile(response, fileName, bucketName);
            log.info("文件下载成功,文件名称:{},bucket名为:{}", fileName, bucketName);
            return Msg.DOWNLOAD_SUCCESS;
        } catch (Exception e) {
            log.error("文件下载失败,文件名称:{},错误信息:", fileName, e);
            return Msg.DOWNLOAD_ERROR;
        }
    }

    /**
     * 删除文件
     *
     * @param fileName   文件名
     * @param bucketName 桶名
     * @return
     */
    @DeleteMapping("/delFile")
    public Msg delFile(@RequestParam("fileName") String fileName, @RequestParam("bucketName") String bucketName) {
        try {
            minioService.delFile(fileName, bucketName);
            log.info("文件删除成功,文件名称为:{},bucket为:{}", fileName, bucketName);
            return Msg.DELETE_SUCCESS.setNewData("删除文件:" + fileName + "成功!");
        } catch (Exception e) {
            log.error("删除文件失败,文件名称为:{},bucket为:{},错误信息:", bucketName, fileName, e);
            return Msg.DELETE_ERROR.setNewData("删除文件:" + fileName + "失败!");
        }
    }
}

pojo:

package com.greedy.minio.pojo;

import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

import java.io.Serializable;

/**
 * @Author: Greedy
 * @Date: Created in:2022-09-15
 * Description: 文件上传入参实体类
 */
@Data
public class FileUploadBody implements Serializable {

    /**
     * 自定义文件名
     */
    private String fileName;

    /**
     * 多文件
     */
    private MultipartFile[] files;
    /**
     * 所属模块
     */
    private String bucket;

}

serviceImpl:

package com.greedy.minio.service.impl;

import cn.hutool.core.util.StrUtil;
import com.greedy.minio.config.MinioConfig;
import com.greedy.minio.pojo.FileUploadBody;
import com.greedy.minio.service.MinioService;
import com.greedy.minio.vo.FileVo;
import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.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.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Author: Greedy
 * @Date: Created in:2022-09-15
 * Description:
 */
@Service
@Slf4j
public class MinioServiceImpl implements MinioService {

    @Autowired
    private MinioConfig minioConfig;

    @Autowired
    private MinioClient minioClient;

    /**
     * 上传文件
     * @param body
     * @return
     */
    @Override
    public List<FileVo> uploadFile(FileUploadBody body) {
        MultipartFile[] files=body.getFiles();
        if (Objects.nonNull(files) && files.length > 0) {
            String bucketName = StrUtil.isNotBlank(body.getBucket()) ? body.getBucket().replaceAll(",", "") : minioConfig.getBucketName();
            List<FileVo> resultList = new ArrayList<>();
            String fileName = null;
            for (MultipartFile file : files) {
                try {
                    if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                    }
                    fileName = file.getOriginalFilename();
                    if (StrUtil.isNotBlank(body.getFileName())){
                        fileName = body.getFileName();
                    }
                    StringBuffer fileNameSB = new StringBuffer();
                    fileNameSB.append(System.currentTimeMillis()).append("_").append(bucketName).append("_");
                    if (StrUtil.isNotBlank(fileName)){
                        fileNameSB.append(fileName.replaceAll(",", ""));
                    }
                    fileName = fileNameSB.toString();
                    PutObjectArgs args = PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build();
                    minioClient.putObject(args);
                    FileVo fileVo=new FileVo();
                    fileVo.setFileName(fileName);
                    fileVo.setBucket(bucketName);
                    fileVo.setPreviewUrl(getPreviewUrl(fileName,bucketName));
                    resultList.add(fileVo);
                    log.info("文件上传成功,文件名称:{},bucket名称:{}", fileName, bucketName);
                }catch (Exception e){
                    log.error("文件上传失败,文件名称:{},bucket名称:{},错误信息:", fileName, bucketName, e);
                }
            }
            return resultList;
        }
        return Collections.emptyList();
    }

    /**
     * 获取预览地址
     * @param fileName
     * @param bucketName
     * @return
     */
    @Override
    public String getPreviewUrl(String fileName, String bucketName) {
        if (StrUtil.isNotBlank(fileName)) {
            bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
                if (null != minioConfig.getPreviewExpiry()){
                    String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET).bucket(bucketName).object(fileName)
                            .expiry(minioConfig.getPreviewExpiry(), TimeUnit.HOURS).build());
                    log.info("有时限文件预览地址为:{},文件名:{},bucket名:{},有效时间为:{}", presignedObjectUrl, fileName, bucketName, minioConfig.getPreviewExpiry());
                    return presignedObjectUrl;
                }else {
                    String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET).bucket(bucketName).object(fileName).build());
                    log.info("文件预览地址为:{},文件名:{},bucket名:{},有效时间为:永久", presignedObjectUrl, fileName, bucketName);
                    return presignedObjectUrl;
                }
            } catch (Exception e) {
                log.error("预览文件地址错误,文件名为:{},bucket名为:{},错误信息为:", fileName, bucketName, e);
            }
        }
        return null;
    }

    /**
     * 下载文件
     * @param response
     * @param fileName
     * @param bucketName
     */
    @Override
    public void downloadFile(HttpServletResponse response, String fileName, String bucketName) {
        InputStream inputStream = null;
        if (StrUtil.isNotBlank(fileName)) {
            bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                StatObjectResponse objectStat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
                response.setContentType(objectStat.contentType());
                response.setCharacterEncoding("UTF-8");
                inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
                IOUtils.copy(inputStream, response.getOutputStream());
                log.info("文件下载成功,文件名称:{},bucket名为:{}", fileName, bucketName);
            } catch (Exception e) {
                log.error("文件下载失败,文件名称:{},错误信息:", fileName, e);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        log.error("输入流关闭失败,文件名:{},错误信息:", fileName, e);
                    }
                }
            }
        }
    }

    /**
     * 删除文件
     * @param fileName
     * @param bucketName
     * @return
     */
    @Override
    public String delFile(String fileName, String bucketName) {
        if (StrUtil.isNotBlank(fileName)) {
            bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
                log.info("文件删除成功,文件名称为:{},bucket为:{}", fileName, bucketName);
                return "success";
            }catch (Exception e) {
                log.error("删除文件失败,文件名称为:{},bucket为:{},错误信息:", bucketName, fileName, e);
                return "删除文件失败,请刷新后重试";
            }
        }
        return "文件不能为空";
    }
}

service:

package com.greedy.minio.service;

import com.greedy.minio.pojo.FileUploadBody;
import com.greedy.minio.vo.FileVo;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * @Author: Greedy
 * @Date: Created in:2022/09/15
 * Description:
 */
public interface MinioService {

    /**
     * 上传文件
     * @param body
     * @return
     */
    List<FileVo> uploadFile(FileUploadBody body);

    /**
     * 获取预览地址
     * @param fileName
     * @param bucketName
     * @return
     */
    String getPreviewUrl(String fileName, String bucketName);

    /**
     * 下载文件
     * @param response
     * @param fileName
     * @param bucketName
     */
    void downloadFile(HttpServletResponse response, String fileName, String bucketName);

    /**
     * 删除文件
     * @param fileName
     * @param bucketName
     * @return
     */
    String delFile(String fileName, String bucketName);
}

utils:这个统一结果返回实体类,在代码里换成你寄几的就行( •̀ ω •́ )✧

package com.greedy.minio.utils;

import lombok.Data;

/**
 * 统一返回结果集实体类
 * @param <T> 返回数据对象
 */
@Data
public class Msg<T> {

    /**
     * 错误码
     */
    private Integer Code;

    /**
     * 错误信息,一般为前端提示信息
     */
    private String Msg;

    /**
     * 返回值,一般为成功后返回的数据
     */
    private T data;

    /**
     * 错误详情,一般为失败后的详细原因,如空指针之类的
     */
    private String Detail;

    public Msg() {}

    public Msg(Integer Code, String Msg) {
        this.Code = Code;
        this.Msg = Msg;
    }

    public Msg(Integer Code, String Msg, T data) {
        this.Code = Code;
        this.Msg = Msg;
        this.data = data;
    }

    /**
     * 配合静态对象直接设置 data 参数
     * @param data
     * @return
     */
    public Msg setNewData(T data) {
        Msg error = new Msg();
        error.setCode(this.Code);
        error.setMsg(this.Msg);
        error.setDetail(this.Detail);
        error.setData(data);
        return error;
    }

    /**
     * 配合静态对象直接设置 errorMsg 参数
     * @param
     * @return
     */
    public Msg setNewMsg(String Msg) {
        Msg error = new Msg();
        error.setCode(this.Code);
        error.setMsg(Msg);
        error.setDetail(this.Detail);
        error.setData(this.data);
        return error;
    }

    public static final Msg SUCCESS = new Msg(200, "成功");

    public static final Msg ERROR = new Msg(405, "失败");

    public static final Msg INSERT_SUCCESS = new Msg(200, "新增成功");

    public static final Msg UPDATE_SUCCESS = new Msg(200, "更新成功");

    public static final Msg DELETE_SUCCESS = new Msg(200, "删除成功");

    public static final Msg UPLOAD_SUCCESS = new Msg(200, "上传成功");

    public static final Msg DOWNLOAD_SUCCESS = new Msg(200, "下载成功");

    public static final Msg LOGIN_SUCCESS = new Msg(200, "登陆成功");

    public static final Msg LOGOUT_SUCCESS = new Msg(200, "登出成功");

    public static final Msg LOGIN_ERROR = new Msg(201, "登陆错误");

    public static final Msg LOGIN_EXPIRE = new Msg(202, "登陆过期");

    public static final Msg ACCESS_LIMITED = new Msg(301, "访问受限");

    public static final Msg ARGS_ERROR = new Msg(501, "参数错误");

    public static final Msg UNKOWN_ERROR = new Msg(502, "系统异常");

    public static final Msg INSERT_ERROR = new Msg(503, "新增错误");

    public static final Msg UPDATE_ERROR = new Msg(504, "更新错误");

    public static final Msg DELETE_ERROR = new Msg(506, "删除错误");

    public static final Msg UPLOAD_ERROR = new Msg(507, "上传错误");

    public static final Msg DOWNLOAD_ERROR = new Msg(508, "下载错误");

    public static final Msg OTHER_SYSTEM_ERROR = new Msg(509, "调用系统异常");

//    return ErrorMsg.SUCCESS; 成功返回
//    return ErrorMsg.SUCCESS.setNewData(list); 成功带参返回
//    return ErrorMsg.LOGIN_ERROR.setNewErrorMsg("用户名或密码不正确"); 错误返回并设定自定义错误信息

}

vo:

package com.greedy.minio.vo;

import lombok.Data;

import java.io.Serializable;

/**
 * @Author: Greedy
 * @Date: Created in:2022-09-15
 * Description: 展示给前端的具体信息
 */
@Data
public class FileVo implements Serializable {

    /**
     * 文件名称
     */
    private String fileName;

    /**
     * 预览地址
     */
    private String previewUrl;

    /**
     * 所属模块
     */
    private String bucket;
}

MinioApp:主启动类省略。。。

application.yaml:

pom:

<dependencies>
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>去mvn中央仓库自己找</version>
        </dependency>
      <!-- 工具类依赖 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.6</version>
        </dependency>
  <!-- 可以自行扩展,例如显示进度条等依赖 -->
</dependencies>

3、使用MinIO

代码Controller里面几个方法注释写的都很详细了,就不用说了吧。。。

如果您坚持到了这里了都,不给个赞可说不过去熬

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值