java 通过Minio上传文件

1.Minio介绍

MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。

2.Springboot 中添加操作依赖

java 复制代码
<dependency>
     <groupId>io.minio</groupId>
     <artifactId>minio</artifactId>
     <version>8.4.3</version>
</dependency>

3.yaml配置参数

java 复制代码
#minio
minio:
	endpoint:http://127.0.0.1:9000
	accessKey:1293781k1wk1
	secretKey:5oSbD@Z0yR1mm&NC8r*FeV!Htoxhd#O6f6h$JavDKuYQ
	bucketName:jz07

4.MinioConfigpe配置

java 复制代码
uration
@Getter
@RefreshScope
@Data
public class MinioConfig {
    /**
     * 连接url
     */
    @Value("${minio.endpoint}")
    private String endpoint;
    /**
     * 用户名
     */
    @Value("${minio.accessKey}")
    private String accessKey;
    /**
     * 密码
     */
    @Value("${minio.secretKey}")
    private String secretKey;
    /**
     * 存储桶
     */
    @Value("${minio.bucketName}")
    private String bucketName;


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

}

5.Minio工具类

java 复制代码
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Minio工具类
 *
 * @author smr
 */
@Component
@Data
@Slf4j
public class MinioUtils {

    private final MinioClient minioClient;

    private static final int BUFFER_SIZE = 1024 * 1024 * 4;

    @Resource
    private MinioConfig minioConfig;

    @Autowired
    public MinioUtils(MinioClient minioClient) {
        this.minioClient = minioClient;
    }

    /**
     * 检验桶
     */
    public Boolean bucketExists(String bucketName) {
        try {
            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            log.error("检验BucketName存在失败", e);
            return false;
        }
    }

    /**
     * 创建桶
     */
    public void makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            log.error("检验BucketName存在失败", e);
        }
    }

    /**
     * 上传Multipart文件
     */
    public void uploadFileMultipartFile(String objectName, MultipartFile file) throws Exception {
        // 使用 PutObjectArgs 进行文件上传
        minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(minioConfig.getBucketName())
                        .object(objectName)
                        .stream(file.getInputStream(), file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build());
    }

    /**
     * 上传流文件
     */
    public void uploadFileStream(String bucketName, String objectName, FileInputStream stream, String contentType) throws Exception {
        // 使用 PutObjectArgs 进行文件上传
        minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(stream, stream.getChannel().size(), -1)
                        .contentType(contentType)
                        .build());
    }

    /**
     * 上传本地文件
     */
    public void uploadLocalFile(String bucketName, String objectName, File file) throws Exception {
        UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .filename(file.getAbsolutePath())
                .build();

        minioClient.uploadObject(uploadObjectArgs);
    }

    /**
     * 下载文件
     */
    public void downloadFile(String bucketName, String objectName, String downloadPath) throws Exception {
        InputStream stream = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());

        // 使用缓冲流写入文件
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(downloadPath))) {
            byte[] buf = new byte[1024];
            int len;
            while ((len = stream.read(buf)) != -1) {
                bos.write(buf, 0, len);
            }
        }
        stream.close();
    }

    /**
     * 获取文件流
     */
    public InputStream getFileInputStream(String bucketName, String objectName) throws Exception {
        return minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());
    }

    public void downloadWithPar(String fileId, OutputStream outputStream) {
        log.info("downloadWithPar begin fileId [{}]", fileId);
        isFileExist(fileId);
        try {
            StopWatch downLoadStopWatch = new StopWatch();
            downLoadStopWatch.start();
            InputStream inputStream = minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket(minioConfig.getBucketName())
                            .object(fileId)
                            .build());
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;
            long fileSize = 0;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
                outputStream.flush();
                fileSize += bytesRead;
            }
            outputStream.flush();
            inputStream.close();
            downLoadStopWatch.stop();
            log.info("download finished. fileId: [{}], file size: [{}], download time: [{}] ms",
                    fileId, FileUtils.byteCountToDisplaySize(fileSize),
                    downLoadStopWatch.getTotalTimeMillis());

        } catch (Exception e) {
            log.error("Failed to download the file. fileId: [{}]", fileId, e);
             throw new RuntimeException("Failed to download the file from the Minio platform", e);
                    );
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 检查文件是否存在
     */
    public boolean isFileExist(String objectName) {
        try {
            minioClient.statObject(
                    StatObjectArgs.builder()
                            .bucket(minioConfig.getBucketName())
                            .object(objectName)
                            .build());
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 删除文件
     */
    public void deleteFile(String objectName) throws Exception {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(minioConfig.getBucketName())
                        .object(objectName)
                        .build());
    }

    /**
     * 列出存储桶中的所有文件
     */
    public List<String> listFiles(String bucketName) throws Exception {
        List<String> files = new ArrayList<>();
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .build());

        for (Result<Item> result : results) {
            files.add(result.get().objectName());
        }
        return files;
    }

    /**
     * 获取文件的下载URL
     */
    public String getPath(String objectName) throws Exception {
        return minioConfig.getBucketName() + "/" + objectName;
    }


    /**
     * 获取文件的下载URL
     */
    public String getDownloadUrl(String objectName) throws Exception {
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .bucket(minioConfig.getBucketName())
                        .object(objectName)
                        .method(Method.GET)
                        .build()
        );
    }

    /**
     * 下载文件的部分数据
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @param offset     起始字节位置
     * @param length     要下载的字节长度
     * @return 部分文件数据的字节数组
     */
    public byte[] downloadPartialData(String bucketName, String objectName, long offset, long length) throws Exception {
        try (InputStream stream = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .offset(offset)
                        .length(length)
                        .build())) {

            byte[] buffer = new byte[(int) length];
            stream.read(buffer);
            return buffer;
        }
    }

    /**
     * 文件转换
     *
     * @param file
     * @return MultipartFile
     */
    public MultipartFile convert(File file) {
        DiskFileItem fileItem = new DiskFileItem("file", "application/octet-stream", false, file.getName(), (int) file.length(), file.getParentFile());
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                fileItem.getOutputStream().write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            throw new RuntimeException("Error converting MultipartFile to File", e);
        }
        return new CommonsMultipartFile(fileItem);
    }
}

6.FileService调用工具类

java 复制代码
@Service
@Slf4j
public class FieldService {
    @Resource
    private MinioUtils minioUtils;
    /**
     * 文件上传
     *
     * @param file
     * @return
     */
    public UploadFileRSP uploadPic(MultipartFile file) {
        log.info("文件上传开始:{}", file.getOriginalFilename());
        //首先判断文件是否存在
        if (minioUtils.isFileExist(file.getOriginalFilename())) {
            throw new ServiceException("该文件名已存在,请修改文件名后上传");
        }
        UploadFileRSP rsp = new UploadFileRSP();
        try {
            minioUtils.uploadFileMultipartFile(file.getOriginalFilename(), file);
            rsp.setFileName(file.getOriginalFilename());
            rsp.setFilePath(minioUtils.getPath(rsp.getFileName()));
            rsp.setFileUrl(minioUtils.getDownloadUrl(rsp.getFileName()));
            return rsp;
        } catch (Exception e) {
            log.error("出海咨询模块-文件上传失败", e);
            throw new ServiceException(ResultCode.INTERNAL_SERVER_ERROR, "文件上传失败。" + e.getMessage());
        }
    }

    /**
     * 文件下载
     */
    public void downloadPic(String fileName, HttpServletResponse response) {
        try {
            if(!minioUtils.isFileExist(fileName)){
                throw new ServiceException(ResultCode.INTERNAL_SERVER_ERROR, "文件不存在。");
            }
            response.reset();
            response.setContentType("application/octet-stream");
            String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition",
                "attachment; filename=" + encodedFileName + "; filename*=utf-8''" + encodedFileName);
            minioUtils.downloadWithPar(fileName, response.getOutputStream());
            log.info("下载附件成功。");
        } catch (Exception e) {
            log.error("附件下载失败。fileName,[{}]", fileName, e);
            throw new ServiceException(ResultCode.INTERNAL_SERVER_ERROR, "附件下载失败。" + e.getMessage());
        }
    }

    /**
     * 删除文件
     */
    public Boolean deleteFile(String fileName) {
        Assert.notNull(fileName, "文件名不能为空");
        try {
            if (minioUtils.isFileExist(fileName)) {
                minioUtils.deleteFile(fileName);
                return true;
            } else {
                throw new ServiceException(ResultCode.INTERNAL_SERVER_ERROR, "文件不存在无法删除。");
            }
        } catch (Exception e) {
            log.error("附件删除失败。fileName,[{}]", fileName, e);
            throw new ServiceException(ResultCode.INTERNAL_SERVER_ERROR, "附件删除失败。" + e.getMessage());
        }
    }

    /**
     * 创建桶
     */
    public void createBuk(String bucketName) {
        try {
            if(minioUtils.bucketExists(bucketName)){
                log.info("BucketName已存在。");
            } else {
                minioUtils.makeBucket(bucketName);
            }
        } catch (Exception e) {
            log.error("创建失败", e);
        }
    }
}
相关推荐
人道领域2 小时前
javaWeb从入门到进阶(SpringBoot事务管理及AOP)
java·数据库·mysql
m0_561359672 小时前
基于C++的机器学习库开发
开发语言·c++·算法
星空露珠2 小时前
速算24点所有题库公式
开发语言·数据库·算法·游戏·lua
2401_832402752 小时前
C++中的类型擦除技术
开发语言·c++·算法
努力学习的小廉2 小时前
我爱学算法之—— 递归回溯综合(二)
开发语言·算法
sheji52612 小时前
JSP基于信息安全的读书网站79f9s--程序+源码+数据库+调试部署+开发环境
java·开发语言·数据库·算法
2301_763472462 小时前
C++网络编程(Boost.Asio)
开发语言·c++·算法
毕设源码-邱学长2 小时前
【开题答辩全过程】以 基于Java Web的电子商务网站的用户行为分析与个性化推荐系统为例,包含答辩的问题和答案
java·开发语言
程序员清洒2 小时前
Flutter for OpenHarmony:Text — 文本显示与样式控制
开发语言·javascript·flutter