当然使用Docker之前还是需要部署docker的 点这里查看

一、什么是Minio

中文官网 MinIO Container中文文档

1.1 minio简介

Minio是一个高性能、分布式对象存储系统,兼容Amazon S3 API。它可以通过搭建私有云来提供存储服务,也可以作为公共云中的对象存储服务。

Minio的实现原理是基于分布式的架构,数据被分割为多个部分并存储在不同的服务器上。这些服务器通过一个一致性哈希算法将数据划分为不同的分片,并且使用Erasure Coding来提供数据冗余和容错能力。客户端通过S3协议与Minio进行交互,可以像操作Amazon S3一样进行数据的上传、下载、删除等操作。Minio支持水平扩展,可以根据业务需求增加或减少服务器节点。

1.2 使用场景

Minio的使用场景非常广泛,包括但不限于以下几个方面:

  1. 对象存储服务:作为公共云服务提供商,Minio可以提供可靠的、低延迟的对象存储服务,适用于需要大规模数据存储和访问的应用。
  2. 备份和归档:Minio可以作为备份和归档的存储解决方案,确保数据的安全性和可靠性。
  3. 多媒体存储和处理:Minio可以存储和处理大规模的多媒体文件,如图片、视频等。
  4. 数据湖:利用Minio提供的数据存储和分析能力,可以构建数据湖,用于存储、分析和处理海量的结构化和非结构化数据。
  5. 私有云存储:通过搭建私有云,可以在本地环境中提供对象存储服务,提高数据隐私和安全性。

二、部署Minio

2.1 拉取镜像

docker pull minio/minio

在这里插入图片描述

2.2 创建数据持久化文件夹

mkdir -p /usr/local/minio/data

2.3 启动镜像

docker run -p 9000:9000 -p 9090:9090 \
 --name minio \
 -d --restart=always \
 -e "MINIO_ACCESS_KEY=WAkFL27XwGlOD7OA" \
 -e "MINIO_SECRET_KEY=Ubn7Zuojif1kbp8ASjJff2VEs0Ko5TVt" \
 -e "MINIO_ROOT_USER=WAkFL27XwGlOD7OA" \
 -e "MINIO_ROOT_PASSWORD=Ubn7Zuojif1kbp8ASjJff2VEs0Ko5TVt" \
 -v /usr/local/minio/data:/data \
 minio/minio server \
 /data --console-address ":9090" -address ":9000"

docker指令解析:

  1. docker run -p 9000:9000 -p 9090:9090 :
    -p 9000:9000 表示将容器内的 9000 端口映射到主机的 9000 端口,用于 Minio 对象存储服务。
    -p 9090:9090 表示将容器内的 9090 端口映射到主机的 9090 端口,用于 Minio 控制台。
  2. –name minio: 将容器命名为 “minio”。
  3. -d --restart=always: 在后台运行容器,并在容器退出后自动重启容器。
  4. -e “MINIO_ACCESS_KEY=WAkFL27XwGlOD7OA”: 设置 Minio 的访问密钥,这里设置为 “WAkFL27XwGlOD7OA”。
  5. -e “MINIO_SECRET_KEY=Ubn7Zuojif1kbp8ASjJff2VEs0Ko5TVt”: 设置 Minio 的私有密钥,这里设置为 “Ubn7Zuojif1kbp8ASjJff2VEs0Ko5TVt”。
  6. -e “MINIO_ROOT_USER=WAkFL27XwGlOD7OA”: 设置 Minio 控制台的根用户,这里设置为 “WAkFL27XwGlOD7OA”。
  7. -e “MINIO_ROOT_PASSWORD=Ubn7Zuojif1kbp8ASjJff2VEs0Ko5TVt”: 设置 Minio 控制台的根用户密码,这里设置为 “Ubn7Zuojif1kbp8ASjJff2VEs0Ko5TVt”。
  8. -v /usr/local/minio/data:/data: 将主机的 “/usr/local/minio/data” 目录挂载到容器的 “/data” 目录,用于持久化存储 Minio 数据。
  9. minio/minio server /data --console-address “:9090” -address “:9000”: 使用 Minio 镜像创建容器,并将 “/data” 目录作为存储目录。" --console-address “:9090” -address “:9000"” 是 Minio 镜像特定的参数,指定了 Minio 控制台和对象存储服务的端口。

执行完成后接着执行 docker ps 查看当前docker运行的镜像
在这里插入图片描述

2.4 防火墙端口开放

//防火墙开放 连接端口
firewall-cmd --zone=public --add-port=9000/tcp --permanent
//防火墙开放 客户端界面端口
firewall-cmd --zone=public --add-port=9090/tcp --permanent
//重启防火墙 使其配置生效
systemctl restart firewalld.service

ps:如果是云服务器开了安全组的需要在安全组开放对应端口,建议只给自己的ip开放。

2.5 访问Minio

ip:9090
在这里插入图片描述
在这里插入图片描述

三、SpringBoot整合Minio

3.1 引入Maven依赖

这里使用的是 AWS S3(Amazon Simple Storage Service)的依赖,它是亚马逊提供的一种可扩展的对象存储服务。aws-s3 通用存储操作 支持所有兼容s3协议的云存储: {阿里云OSS,腾讯云COS,七牛云,京东云,minio 等。

<!--aws-s3-->
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-s3</artifactId>
    <version>1.11.803</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-sts</artifactId>
    <version>1.11.803</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-core</artifactId>
    <version>1.11.803</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3.2 配置类

application.yml 配置文件添加

#aws-s3
file:
  bucketName: tallytool # 桶名称
  oss:
    endpoint: http://部署的服务器ip:9000
    accessKey: WAkFL27XwGlOD7OA
    secretKey: Ubn7Zuojif1kbp8ASjJff2VEs0Ko5TVt

配置类

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

/**
 * oss 配置信息
 */
@Data
@Component
@ConfigurationProperties(prefix = "file")
public class FileProperties {

    /**
     * 默认的存储桶名称
     */
    private String bucketName = "local";

    /**
     * oss 文件配置信息
     */
    private OssProperties oss;

}

3.3 文件抽象类

package com.itbanana.tallytool.template;

import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import org.springframework.beans.factory.InitializingBean;

import java.io.InputStream;
import java.util.List;

/**
 * 文件操作模板
 */
public interface FileTemplate extends InitializingBean {

    /**
     * 创建bucket
     * @param bucketName bucket名称
     */
    void createBucket(String bucketName);

    /**
     * 获取全部bucket
     * <p>
     *
     * API Documentation</a>
     */
    List<Bucket> getAllBuckets();

    /**
     * @param bucketName bucket名称
     * @see <a href= Documentation</a>
     */
    void removeBucket(String bucketName);

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * @param contextType 文件类型
     * @throws Exception
     */
    void putObject(String bucketName, String objectName, InputStream stream, String contextType) throws Exception;

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * @throws Exception
     */
    void putObject(String bucketName, String objectName, InputStream stream) throws Exception;

    /**
     * 获取文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流 API Documentation</a>
     */
    S3Object getObject(String bucketName, String objectName);

    void removeObject(String bucketName, String objectName) throws Exception;

    /**
     * @throws Exception
     */
    @Override
    default void afterPropertiesSet() throws Exception {
    }

    /**
     * 根据文件前置查询文件
     * @param bucketName bucket名称
     * @param prefix 前缀
     * @param recursive 是否递归查询
     * @return S3ObjectSummary 列表
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects">AWS
     * API Documentation</a>
     */
    List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive);

}

3.4 oss操作实现类


import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.util.IOUtils;
import lombok.Cleanup;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.*;

/**
 * aws-s3 通用存储操作 支持所有兼容s3协议的云存储: {阿里云OSS,腾讯云COS,七牛云,京东云,minio 等}
 *
 */
@Component
@RequiredArgsConstructor
public class OssTemplate implements InitializingBean, FileTemplate {

    private final FileProperties properties;

    private AmazonS3 amazonS3;

    /**
     * 创建bucket
     * @param bucketName bucket名称
     */
    @SneakyThrows
    @Override
    public void createBucket(String bucketName) {
       if (!amazonS3.doesBucketExistV2(bucketName)) {
          amazonS3.createBucket((bucketName));
       }
    }

    /**
     * 获取全部bucket
     * <p>
     *
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets">AWS
     * API Documentation</a>
     */
    @SneakyThrows
    @Override
    public List<Bucket> getAllBuckets() {
       return amazonS3.listBuckets();
    }

    /**
     * @param bucketName bucket名称
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets">AWS
     * API Documentation</a>
     */
    @SneakyThrows
    public Optional<Bucket> getBucket(String bucketName) {
       return amazonS3.listBuckets().stream().filter(b -> b.getName().equals(bucketName)).findFirst();
    }

    /**
     * @param bucketName bucket名称
     * @see <a href=
     * "http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket">AWS API
     * Documentation</a>
     */
    @SneakyThrows
    @Override
    public void removeBucket(String bucketName) {
       amazonS3.deleteBucket(bucketName);
    }

    /**
     * 根据文件前置查询文件
     * @param bucketName bucket名称
     * @param prefix 前缀
     * @param recursive 是否递归查询
     * @return S3ObjectSummary 列表
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects">AWS
     * API Documentation</a>
     */
    @SneakyThrows
    @Override
    public List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {
       ObjectListing objectListing = amazonS3.listObjects(bucketName, prefix);
       return new ArrayList<>(objectListing.getObjectSummaries());
    }

    /**
     * 获取文件外链
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires 过期时间 <=7
     * @return url
     * @see AmazonS3#generatePresignedUrl(String bucketName, String key, Date expiration)
     */
    @SneakyThrows
    public String getObjectURL(String bucketName, String objectName, Integer expires) {
       Date date = new Date();
       Calendar calendar = new GregorianCalendar();
       calendar.setTime(date);
       calendar.add(Calendar.DAY_OF_MONTH, expires);
       URL url = amazonS3.generatePresignedUrl(bucketName, objectName, calendar.getTime());
       return url.toString();
    }

    /**
     * 获取文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject">AWS
     * API Documentation</a>
     */
    @SneakyThrows
    @Override
    public S3Object getObject(String bucketName, String objectName) {
       return amazonS3.getObject(bucketName, objectName);
    }

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * @throws Exception
     */
    @Override
    public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {
       putObject(bucketName, objectName, stream, stream.available(), "application/octet-stream");
    }

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * @param contextType 文件类型
     * @throws Exception
     */
    @Override
    public void putObject(String bucketName, String objectName, InputStream stream, String contextType)
          throws Exception {
       putObject(bucketName, objectName, stream, stream.available(), contextType);
    }

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream 文件流
     * @param size 大小
     * @param contextType 类型
     * @throws Exception
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject">AWS
     * API Documentation</a>
     */
    public PutObjectResult putObject(String bucketName, String objectName, InputStream stream, long size,
                                     String contextType) throws Exception {
       // String fileName = getFileName(objectName);
       byte[] bytes = IOUtils.toByteArray(stream);
       ObjectMetadata objectMetadata = new ObjectMetadata();
       objectMetadata.setContentLength(size);
       objectMetadata.setContentType(contextType);
       ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
       // 上传
       return amazonS3.putObject(bucketName, objectName, byteArrayInputStream, objectMetadata);

    }

    /**
     * 获取文件信息
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject">AWS
     * API Documentation</a>
     */
    public S3Object getObjectInfo(String bucketName, String objectName) throws Exception {
       @Cleanup
       S3Object object = amazonS3.getObject(bucketName, objectName);
       return object;
    }

    /**
     * 删除文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception
     * @see <a href=
     * "http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject">AWS API
     * Documentation</a>
     */
    @Override
    public void removeObject(String bucketName, String objectName) throws Exception {
       amazonS3.deleteObject(bucketName, objectName);
    }

    @Override
    public void afterPropertiesSet() {
       ClientConfiguration clientConfiguration = new ClientConfiguration();
       clientConfiguration.setMaxConnections(properties.getOss().getMaxConnections());

       AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(
             properties.getOss().getEndpoint(), properties.getOss().getRegion());
       AWSCredentials awsCredentials = new BasicAWSCredentials(properties.getOss().getAccessKey(),
             properties.getOss().getSecretKey());
       AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials);
       this.amazonS3 = AmazonS3Client.builder().withEndpointConfiguration(endpointConfiguration)
             .withClientConfiguration(clientConfiguration).withCredentials(awsCredentialsProvider)
             .disableChunkedEncoding().withPathStyleAccessEnabled(properties.getOss().getPathStyleAccess()).build();
    }

}

3.5 使用示例 (这里直接展示service层了,controller层在尝试试再自己补上吧)

@Service
@RequiredArgsConstructor
public class OssServiceImpl implements OssService {

    private final FileProperties fileProperties;

    private final OssTemplate ossTemplate;


    @Override
    public R upload(MultipartFile file) {
        if (Objects.isNull(file)){
            throw new BusinessException("上传文件不能为空");
        }
        String fileName = UUID.randomUUID()+ "." + FileUtil.extName(file.getOriginalFilename());

        try(
                InputStream inputStream = file.getInputStream()
        ) {
            ossTemplate.putObject(fileProperties.getBucketName(),fileName,inputStream,file.getSize(),"application/octet-stream");
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("上传文件失败:"+e.getMessage());
        }

        return R.ok("上传成功",fileName);
    }
}

四、结尾

在这里插入图片描述

感谢您的观看! 如果本文对您有帮助,麻烦用您发财的小手点个三连吧!

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐