Spring - SpringBoot + Minio整合使用

MinIO 是在 Apache License v2.0 下发布的高性能对象存储。 它是与 Amazon S3 云存储服务兼容的 API。 使用 MinIO 构建 用于机器学习、分析和应用的高性能基础设施 数据工作负载。

什么是对象存储?

  1. An object 是二进制数据,有时也称为 Binary 大对象 (BLOB)。 Blob 可以是图像、音频文件、电子表格,甚至 二进制可执行代码。 像 MinIO 这样的对象存储平台提供了专用的 用于存储、检索和搜索 blob 的工具和功能。
  2. MinIO 对象存储使用 buckets 来组织对象。 存储桶类似于文件系统中的文件夹或目录,其中每个 桶可以容纳任意数量的对象。 MinIO 存储桶提供 与 AWS S3 存储桶相同的功能。

1.引入依赖

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.2.1</version>
</dependency>

2.配置applicaton.yml文件

minio:
  endPoint: http://ip地址:端口
  accessKey: 账号
  secretKey: 密码
  bucketName: 存储的桶名称

在这里插入图片描述

3.配置文件—MinioProperties

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

/**
 * MinIOProperties
 *
 * @author Chia-Hung Yeh
 * @version 1.0.0
 * @since 2022-09-06 11:30
 */
@Data
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {

    /**
     * 终端:服务器地址 + 端口
     */
    private String endPoint;

    /**
     * 账号
     */
    private String accessKey;

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

    /**
     * 桶名称
     */
    private String bucketName;
}

import io.minio.MinioClient;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

/**
 * MinIOConfig
 *
 * @author Chia-Hung Yeh
 * @version 1.0.0
 * @since 2022-09-06 11:32
 */
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinIOConfig {

    @Resource
    private MinioProperties minioProperties;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(minioProperties.getEndPoint())
                .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                .build();
    }
}

4.工具类—MinioUtils

import cn.hutool.core.codec.Base64;
import com.google.common.io.ByteStreams;
import com.space.wedding.enums.Base64PrefixEnum;
import io.minio.*;
import io.minio.http.Method;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.IOUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * MinioUtils
 *
 * @author Chia-Hung Yeh
 * @version 1.0.0
 * @since 2022-09-06 11:33
 */
@Component
public class MinioUtils {

    @Resource
    private MinioClient minioClient;

    /**
     * 创建桶
     *
     * @param bucketName 桶名称
     * @author Chia-Hung Yeh
     * @since 2022/9/7 11:52
     */
    public void createBucket(String bucketName) throws Exception {
        boolean flag = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        System.out.println(flag);
        if (!flag) {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        }
    }

    /**
     * 上传文件
     *
     * @param file       文件
     * @param bucketName 桶名称
     * @param filePrefix 保存的目录使用的目录
     * @param fileName   文件名称
     * @return String
     * @author Chia-Hung Yeh
     * @since 2022/9/7 12:01
     */
    public String uploadFile(MultipartFile file, String bucketName, String filePrefix, String fileName) throws Exception {
        //判断文件是否为空
        if (null == file || 0 == file.getSize()) {
            return null;
        }
        //判断存储桶是否存在  不存在则创建
        createBucket(bucketName);
        // 对象处理
        String objectName = filePrefix + fileName + Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf("."));
        //开始上传
        PutObjectArgs build = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        return minioClient.putObject(build).object();
    }

    /**
     * 上传文件
     *
     * @param file       文件
     * @param bucketName 桶名称
     * @param objectName 文件名称
     * @return String
     * @author Chia-Hung Yeh
     * @since 2022/9/7 12:01
     */
    public String reuploadFile(MultipartFile file, String bucketName, String objectName) throws Exception {
        //判断文件是否为空
        if (null == file || 0 == file.getSize()) {
            return null;
        }
        //开始上传
        PutObjectArgs build = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        return minioClient.putObject(build).object();
    }

    /**
     * 上传⽂件
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @param stream     ⽂件流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     * @author Chia-Hung Yeh
     * @since 2022/9/7 12:04
     */
    public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .stream(stream, stream.available(), -1)
                .contentType(objectName.substring(objectName.lastIndexOf(".")))
                .build());
    }

    /**
     * 上传
     *
     * @param bucketName  bucket名称
     * @param objectName  ⽂件名称
     * @param stream      ⽂件流
     * @param size        ⼤⼩
     * @param contextType 类型
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     * @author Chia-Hung Yeh
     * @since 2022/9/7 12:04
     */
    public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws Exception {
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .stream(stream, size, -1)
                .contentType(contextType)
                .build());
    }


    /**
     * 获取⽂件(下载)
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @return ⼆进制流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#getObject
     * @author Chia-Hung Yeh
     * @since 2022/9/7 12:04
     */
    public InputStream getObject(String bucketName, String objectName) throws Exception {
        return minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
    }

    /**
     * 获取⽂件信息
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#getObjectInfo
     * @author Chia-Hung Yeh
     * @since 2022/9/7 12:04
     */
    public void getObjectInfo(String bucketName, String objectName, HttpServletResponse response) throws Exception {
        StatObjectResponse statObjectResponse = minioClient.statObject(StatObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
        byte[] buffer = new byte[1024];
        int length = (int) statObjectResponse.size();
        try (InputStream inputStream = getObject(bucketName, objectName);
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream(length)) {
            ByteStreams.copy(inputStream, outputStream);
            buffer = outputStream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        response.setHeader("Content-Disposition",
                "attachment; filename=" + new String(objectName.getBytes(StandardCharsets.UTF_8), "ISO8859-1"));
        response.getOutputStream().write(buffer);
        response.flushBuffer();
        response.getOutputStream().close();
    }

    /**
     * 获取⽂件信息(Base64)
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @author Chia-Hung Yeh
     * @since 2022/9/7 12:04
     */
    public String getBase64(String bucketName, String objectName) {
        String suffix = objectName.substring(objectName.indexOf("."));
        String prefixByType = Base64PrefixEnum.getPrefixByType(suffix);
        try {
            InputStream object = getObject(bucketName, objectName);
            byte[] bytes = IOUtils.toByteArray(object);
            return prefixByType + Base64.encode(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取预览地址
     *
     * @param bucketName bucket名称
     * @param fileName   ⽂件名称
     * @return String
     * @author Chia-Hung Yeh
     * @since 2022/9/7 12:04
     */
    public String getPreviewUrl(String bucketName, String fileName) {
        if (StringUtils.isNotBlank(fileName)) {
            try {
                minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
                return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(fileName)
                        .build());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 删除⽂件
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @throws Exception https://docs.minio.io/cn/java-client-apireference.html#removeObject
     * @author Chia-Hung Yeh
     * @since 2022/9/7 12:04
     */
    public void removeObject(String bucketName, String objectName) throws Exception {
        minioClient.removeObject(RemoveObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
    }
}

5.使用案例—多文件上传(可调整)、删除

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.space.wedding.config.minio.MinioProperties;
import com.space.wedding.dao.ApplicationResourceDao;
import com.space.wedding.entity.ApplicationResource;
import com.space.wedding.exception.MyCustomException;
import com.space.wedding.response.StatusCodeEnum;
import com.space.wedding.service.ApplicationResourceService;
import com.space.wedding.utils.MinioUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ApplicationResourceServiceImpl extends ServiceImpl<ApplicationResourceDao, ApplicationResource> implements ApplicationResourceService {	
	@Resource
    private MinioUtils minioUtils;
    @Resource
    private MinioProperties minioProperties;

    /**
     * 上传文件信息
     *
     * @param fileList   文件列表
     * @param resourceId 来源id
     * @param dir        文件夹目录
     * @param type       文件类型:1.图片,2.视频,3.文档
     * @author Chia-Hung Yeh
     * @since 2022/9/7 13:51
     */
    @Override
    public void insertResource(MultipartFile[] fileList, String resourceId, String dir, int type) {
        // 文件名称的前缀
        String filePrefix = type == 1 ? "IMG" : (type == 2 ? "VIDEO" : "DOC");
        // 时间格式化
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        if (fileList == null || fileList.length == 0) {
            return;
        }
        // 删除以前的图片
        deleteResource(resourceId, type);
        try {
            List<String> fileUrlList = new ArrayList<>();
            for (MultipartFile file : fileList) {
                // 存放在MinIO里的文件名
                String finalFileName = filePrefix + dateFormat.format(new Date());
                String uploadFileUrl = minioUtils.uploadFile(file, minioProperties.getBucketName(), dir, finalFileName);
                fileUrlList.add(uploadFileUrl);
            }
            // 业务处理
            List<ApplicationResource> insertList = fileUrlList.stream().map(item -> {
                ApplicationResource resource = new ApplicationResource();
                resource.setResourceId(resourceId);
                resource.setResourceType(type);
                resource.setResourceUrl(item);
                return resource;
            }).collect(Collectors.toList());
            if (!insertList.isEmpty()) {
                this.saveBatch(insertList);
            }
        } catch (Exception e) {
        	// StatusCodeEnum.UPLOAD_FILE_EXCEPTION 自己定义的返回码枚举类 
        	// MyCustomException() 自己定义的异常类
            throw new MyCustomException(StatusCodeEnum.UPLOAD_FILE_EXCEPTION);
        }
    }


	/**
     * 删除资源文件
     *
     * @param resourceId 来源id
     * @param type 		 文件类型:0.全部,1.图片,2.视频,3.文档
     * @author Chia-Hung Yeh
     * @since 2022/9/7 13:45
     */
    @Override
    public void deleteResource(String resourceId, int type) {
        // 先把以前的图片进行删除
        try {
            LambdaQueryWrapper<ApplicationResource> queryWrapper = new LambdaQueryWrapper<ApplicationResource>()
                    .eq(ApplicationResource::getResourceId, resourceId);
            if (type > 0) {
                queryWrapper.eq(ApplicationResource::getResourceType, type);
            }
            // 删除文件存储中的图片、视频等信息
            List<ApplicationResource> list = baseMapper.selectList(queryWrapper);
            List<String> collect = list.stream().map(ApplicationResource::getResourceUrl).collect(Collectors.toList());
            for (String url : collect) {
                minioUtils.removeObject(minioProperties.getBucketName(), url);
            }
        } catch (Exception e) {
            throw new MyCustomException(StatusCodeEnum.DELETE_FILE_EXCEPTION);
        }
    }
}

5.Minio服务器搭建

Docker - 安装Minio

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于Spring Boot和MyBatis整合MinIO使用阿里云引入MinIO相关的问题,以下是一些建议: 1. 引入MinIO依赖:在您的Spring Boot项目中,可以通过在pom.xml文件中添加MinIO的依赖来引入MinIO的相关功能。例如: ```xml <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.4.0</version> </dependency> ``` 2. 配置MinIO连接信息:在您的Spring Boot项目的配置文件(如application.properties或application.yml)中,配置MinIO的连接信息,包括Endpoint、Access Key和Secret Key。示例: ```properties minio.endpoint=http://your-minio-endpoint minio.accessKey=your-access-key minio.secretKey=your-secret-key ``` 3. 使用MinIO客户端:通过创建MinioClient对象,您可以使用MinIO的各种功能,例如创建存储桶、上传文件、下载文件等。示例: ```java import io.minio.MinioClient; import io.minio.errors.*; public class MinioExample { public static void main(String[] args) { try { // 创建MinIO客户端对象 MinioClient minioClient = new MinioClient("http://your-minio-endpoint", "your-access-key", "your-secret-key"); // 创建存储桶 minioClient.makeBucket("your-bucket-name"); // 上传文件 minioClient.putObject("your-bucket-name", "your-object-name", "path-to-local-file"); // 下载文件 minioClient.getObject("your-bucket-name", "your-object-name", "path-to-local-file"); } catch (InvalidEndpointException | InvalidPortException | InvalidKeyException | IOException | NoSuchAlgorithmException | InsufficientDataException | InvalidResponseException | XmlParserException | ErrorResponseException | InternalException e) { e.printStackTrace(); } } } ``` 4. 阿里云引入MinIO相关:如果您希望在阿里云上使用MinIO,您需要确保网络访问控制(如防火墙、安全组)允许与MinIO的Endpoint通信,并且您的阿里云账号拥有访问MinIO的权限。 以上是一些建议,希望能对您有所帮助!如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值