SpringBoot 整合 Minio

MinIO 是一个基于 Go 实现的高性能、兼容 S3 协议的对象存储。它采用 GNU AGPL v3 开源协议,项目地址是 https://github.com/minio/minio 。

它适合存储海量的非结构化的数据,例如说图片、音频、视频等常见文件,备份数据、容器、虚拟机镜像等等,小到 1 KB,大到 5 TB 都可以支持。

SpringBoot 整合 Minio

第一步:添加依赖

<properties>
    <java.version>1.8</java.version>
    <minio.version>8.4.3</minio.version>
</properties>

<dependencies>
    <dependency>
        <groupId>io.minio</groupId>
        <artifactId>minio</artifactId>
        <version>${minio.version}</version>
    </dependency>
</dependencies>

第二步:Minio配置类

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

@Configuration
public class MinioConfig {

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

    @Value("${minio.access-key}")
    private String accessKey;

    @Value("${minio.secret-key}")
    private String secretKey;

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

application.yml 配置文件

minio:
  url: http://xxx.xx.x.x:9000
  accessKey: Y73Ixxxxx******
  secretKey: xxx**************

第三步:MinioTemplate.java 封装方法

封装常用的上传(多文件上传、单文件上传)、获取链接、删除、下载方法,方便使用

import com.ym.mall.model.FileVo;
import io.minio.*;
import io.minio.http.Method;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName:MinioTemplate.java
 * @Description:MinioTemplate
 **/
@Slf4j
@Component
public class MinioTemplate {

    @Autowired
    private MinioClient client;

    /**
     * @Description: 上传文件
     * @Param: [file, bucketName]
     * @return:void
     **/
    public FileVo upload(MultipartFile file, String bucketName) {
        try {
            createBucket(bucketName);

            String oldName = file.getOriginalFilename();
            String fileName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + UuidUtil.getRandomPwd(15) + oldName.substring(oldName.lastIndexOf("."));

            client.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .stream(file.getInputStream(), file.getSize(), 0)
                            .contentType(file.getContentType()).build()
            );

            String url = this.getObjUrl(bucketName, fileName);
            return FileVo.builder()
                    .oldFileName(oldName)
                    .newFileName(fileName)
                    .fileUrl(url.substring(0, url.indexOf("?")))
                    .build();
        } catch (Exception e) {
            log.error("上传文件出错:{}", e);
            return null;
        }
    }

    /**
     * @Description: 上传多个文件
     * @Param: [file, bucketName]
     * @return:void
     **/
    public List<FileVo> uploads(List<MultipartFile> files, String bucketName) {
        try {
            List<FileVo> list = new ArrayList<>();
            createBucket(bucketName);

            for (MultipartFile file : files) {
                String oldName = file.getOriginalFilename();
                String fileName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + UuidUtil.getRandomPwd(15) + oldName.substring(oldName.lastIndexOf("."));

                client.putObject(
                        PutObjectArgs.builder()
                                .bucket(bucketName)
                                .object(fileName)
                                .stream(file.getInputStream(), file.getSize(), 0)
                                .contentType(file.getContentType()).build()
                );

                String url = this.getObjUrl(bucketName, fileName);
                list.add(
                        FileVo.builder()
                                .oldFileName(oldName)
                                .newFileName(fileName)
                                .fileUrl(url.substring(0, url.indexOf("?")))
                                .build()
                );
            }
            return list;
        } catch (Exception e) {
            log.error("上传文件出错:{}", e);
            return null;
        }
    }

    /**
     * @Description: 下载文件
     * @Param: [bucketName, fileName]
     * @return:void
     **/
    public void download(String bucketName, String fileName) throws Exception {
        client.downloadObject(DownloadObjectArgs.builder().bucket(bucketName).filename(fileName).build());
    }

    /**
     * @Description: 获取文件链接
     * @Param: [bucketName, fileName]
     * @return:java.lang.String
     **/
    public String getObjUrl(String bucketName, String fileName) throws Exception {
        return client.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .bucket(bucketName)
                        .object(fileName)
                        .method(Method.GET)
                        .expiry(30, TimeUnit.SECONDS)
                        .build()
        );
    }

    /**
     * @Description: 删除文件
     * @Param: [bucketName, fileName]
     * @return:void
     **/
    public void delete(String bucketName, String fileName) throws Exception {
        client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
    }

    @SneakyThrows
    public void createBucket(String bucketName) {
        if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            String sb = "{\"Version\": \"2012-10-17\",\"Statement\": [{\"Effect\": \"Allow\",\"Principal\": {\"AWS\": [\"*\"]},\"Action\": [\"s3:GetBucketLocation\"],\"Resource\": [\"arn:aws:s3:::" + bucketName + "\"]},{\"Effect\": \"Allow\",\"Principal\": {\"AWS\": [\"*\"]},\"Action\": [\"s3:ListBucket\"],\"Resource\": [\"arn:aws:s3:::" + bucketName + "\"],\"Condition\": {\"StringEquals\": {\"s3:prefix\": [\"*\"]}}},{\"Effect\": \"Allow\",\"Principal\": {\"AWS\": [\"*\"]},\"Action\": [\"s3:GetObject\"],\"Resource\": [\"arn:aws:s3:::" + bucketName + "/**\"]}]}";
            client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(sb).build());
        }
    }

}

FileVo.java 实体类

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FileVo {

    /**
     * 原文件名
     */
    private String oldFileName;

    /**
     * 新文件名
     */
    private String newFileName;

    /**
     * 文件路径
     */
    private String fileUrl;

}

动态创建 Bucket

如何设置桶的权限?

在MinIO中,可以通过设置桶策略来控制桶的访问权限。桶策略是一个JSON格式的文本文件,用于指定哪些实体(用户、组或IP地址)可以执行哪些操作(读、写、列举等)。

MinIO桶策略的基本结构如下所示:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": ["action1", "action2", ...],
            "Effect": "Allow|Deny",
            "Principal": {"AWS": ["arn:aws:iam::account-id:user/user-name"]},
            "Resource": ["arn:aws:s3:::bucket-name/object-prefix", ...]
        },
        ...
    ]
}



说明如下:
Version:指定策略语法版本(必需)。

Statement:指定一个或多个声明,每个声明包含一个或多个条件,用于定义访问规则。

Action:指定允许或拒绝的操作列表,如"s3:GetObject"表示允许读取对象。

Effect:指定允许或拒绝操作的结果(必需)。

Principal:指定允许或拒绝操作的主体,如IAM用户、组或角色。

Resource:指定允许或拒绝操作的资源(必需)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晒干的老咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值