MinIO文件云存储的实现

  1、添加依赖

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


//如果添加的版本过高需要排除依赖
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.2.1</version>
    <exclusions>
        <exclusion>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.10.0</version>
</dependency>

  2、添加配置文件配置

minio:
  endpoint: http://localhost:9000
  access-key: 你的akey
  secret_key: 你的skey
  bucket-name: 你的桶名

  3、添加实体类

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * 文件信息
 * 
 * @author ruoyi
 */
public class SysFile
{
    /**
     * 文件名称
     */
    private String name;

    /**
     * 文件地址
     */
    private String url;

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public String getUrl()
    {
        return url;
    }

    public void setUrl(String url)
    {
        this.url = url;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
            .append("name", getName())
            .append("url", getUrl())
            .toString();
    }
}

  4、添加配置类 

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

@Configuration
//@ConfigurationProperties(prefix = "minio") //用于自动填充属性值
public class MinioConfig {

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

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

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

    @Value("${minio.bucket-name}")
    private String bucketName;


    public String getUrl()
    {
        return minioEndpoint;
    }

    public void setUrl(String url)
    {
        this.minioEndpoint = url;
    }

    public String getAccessKey()
    {
        return minioAccessKey;
    }

    public void setAccessKey(String accessKey)
    {
        this.minioAccessKey = accessKey;
    }

    public String getSecretKey()
    {
        return minioSecretKey;
    }

    public void setSecretKey(String secretKey)
    {
        this.minioSecretKey = secretKey;
    }

    public String getBucketName()
    {
        return bucketName;
    }

    public void setBucketName(String bucketName)
    {
        this.bucketName = bucketName;
    }

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(minioEndpoint)
                .credentials(minioAccessKey, minioSecretKey)
                .build();
    }
}

  5、添加service层代码 

import org.springframework.web.multipart.MultipartFile;

/**
 * 文件上传接口
 * 
 * @author ruoyi
 */
public interface ISysFileService
{
    /**
     * 文件上传接口
     * 
     * @param file 上传的文件
     * @return 访问地址
     * @throws Exception
     */
    public String uploadFile(MultipartFile file) throws Exception;
}

  6、添加Controller层代码 

@Api(tags="minIO")
@RestController
@RequestMapping("/minio")
@Slf4j
public class MinioController {

    @Autowired
    private MinioClient minioClient;

    @Value("${minio.bucket-name}")
    private String bucketName;

    @PostMapping("/upload")
    @ApiOperation(value = "minioUpload-minIO文件上传", notes = "minioUpload-minIO文件上传")
    public Result<String> uploadFile(@RequestParam("file") MultipartFile file) {
        try {
            InputStream inputStream = file.getInputStream();
            String newFileName = generateUniqueFileName(file.getOriginalFilename());
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(newFileName)
                            .stream(inputStream, inputStream.available(), -1)
                            .contentType(file.getContentType())
                            .build()
            );
            return Result.OK(newFileName);
        } catch (MinioException | IOException | NoSuchAlgorithmException | InvalidKeyException e) {
            e.printStackTrace();
            return Result.error("Error uploading file to MinIO: " + e.getMessage());
        }
    }

    private String generateUniqueFileName(String originalFileName) {
        // 生成一个随机字符串来作为唯一标识
        String randomString = UUID.randomUUID().toString().replace("-", "");
        // 获取文件后缀
        String fileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
        // 生成唯一文件名
        return originalFileName.replace(fileExtension, "") + randomString + fileExtension;
    }


    @Autowired
    private ISysFileService sysFileService;

    /**
     * 文件上传请求
     */
    @PostMapping("uploadReturnUrl")
    public R<SysFile> upload(MultipartFile file)
    {
        try
        {
            // 上传并返回访问地址
            String url = sysFileService.uploadFile(file);
            URI uri = URI.create(url);
            String path = uri.getPath();
            url = path;
            System.out.println(url);
            log.info(url);
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(url));
            sysFile.setUrl(url);
            return R.ok(sysFile);
        }
        catch (Exception e)
        {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

}

  7、按需添加工具类代码

import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;
import java.util.Optional;

/**
 * MinIO工具类
 *
 * @author william@StarImmortal
 * @date 2022/04/19
 */
@Slf4j
@Component
public class MinioUtil {

    private static MinioClient minioClient;

    /**
     * setter注入
     *
     * @param minioClient 客户端
     */
    @Autowired
    public void setMinioClient(MinioClient minioClient) {
        MinioUtil.minioClient = minioClient;
    }

    /**
     * 启动SpringBoot容器的时候初始化Bucket,如果没有Bucket则创建
     */
    public static void createBucket(String bucketName) throws Exception {
        if (!bucketExists(bucketName)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 判断Bucket是否存在
     *
     * @return true:存在,false:不存在
     */
    public static boolean bucketExists(String bucketName) throws Exception {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    /**
     * 获得Bucket策略
     *
     * @param bucketName 存储桶名称
     * @return Bucket策略
     */
    public static String getBucketPolicy(String bucketName) throws Exception {
        return minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build());
    }

    /**
     * 获得所有Bucket列表
     *
     * @return Bucket列表
     */
    public static List<Bucket> getAllBuckets(MinioClient minioClient) throws Exception {
        return minioClient.listBuckets();
    }

    /**
     * 根据存储桶名称获取其相关信息
     *
     * @param bucketName 存储桶名称
     * @return 相关信息
     */
    public static Optional<Bucket> getBucket(String bucketName) throws Exception {
        return getAllBuckets(minioClient)
                .stream()
                .filter(b -> b.name().equals(bucketName))
                .findFirst();
    }

    /**
     * 根据存储桶名称删除Bucket,true:删除成功;false:删除失败,文件或已不存在
     *
     * @param bucketName 存储桶名称
     */
    public static void removeBucket(String bucketName) throws Exception {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /**
     * 判断文件是否存在
     *
     * @param bucketName 存储桶名称
     * @param objectName 文件名
     * @return true:存在;false:不存在
     */
    public static boolean isObjectExist(String bucketName, String objectName) {
        boolean exist = true;
        try {
            minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (Exception e) {
            exist = false;
        }
        return exist;
    }

//    /**
//     * 判断文件夹是否存在
//     *
//     * @param bucketName 存储桶名称
//     * @param objectName 文件夹名称
//     * @return true:存在;false:不存在
//     */
//    public static boolean isFolderExist(String bucketName, String objectName) {
//        boolean exist = false;
//        try {
//            ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder()
//                    .bucket(bucketName)
//                    .prefix(objectName)
//                    .recursive(false)
//                    .build();
//            Iterable<Result<Item>> results = minioClient.listObjects(listObjectsArgs);
//            for (Result<Item> result : results) {
//                Item item = result.get();
//                if (item.isDir() && objectName.equals(item.objectName())) {
//                    exist = true;
//                }
//            }
//        } catch (Exception e) {
//            exist = false;
//        }
//        return exist;
//    }

//    /**
//     * 根据文件前缀查询文件
//     *
//     * @param bucketName 存储桶名称
//     * @param prefix     前缀
//     * @param recursive  是否使用递归查询
//     * @return MinioItem列表
//     */
//    public static List<Item> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) throws Exception {
//        List<Item> list = new ArrayList<>();
//        ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder()
//                .bucket(bucketName)
//                .prefix(prefix)
//                .recursive(recursive)
//                .build();
//        Iterable<Result<Item>> objectsIterator = minioClient.listObjects(listObjectsArgs);
//        if (objectsIterator != null) {
//            for (Result<Item> o : objectsIterator) {
//                Item item = o.get();
//                list.add(item);
//            }
//        }
//        return list;
//    }

    /**
     * 获取文件流
     *
     * @param bucketName 存储桶名称
     * @param objectName 文件名
     * @return 二进制流
     */
    public static InputStream getObject(String bucketName, String objectName) throws Exception {
        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        return minioClient.getObject(getObjectArgs);
    }

    /**
     * 断点下载
     *
     * @param bucketName 存储桶名称
     * @param objectName 文件名称
     * @param offset     起始字节的位置
     * @param length     要读取的长度
     * @return 二进制流
     */
    public InputStream getObject(String bucketName, String objectName, long offset, long length) throws Exception {
        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .offset(offset)
                .length(length)
                .build();
        return minioClient.getObject(getObjectArgs);
    }

//    /**
//     * 获取路径下文件列表
//     *
//     * @param bucketName 存储桶名称
//     * @param prefix     文件名称
//     * @param recursive  是否递归查找,false:模拟文件夹结构查找
//     * @return 二进制流
//     */
//    public static Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) {
//        ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder()
//                .bucket(bucketName)
//                .prefix(prefix)
//                .recursive(recursive)
//                .build();
//        return minioClient.listObjects(listObjectsArgs);
//    }

    /**
     * 使用MultipartFile进行文件上传
     *
     * @param bucketName  存储桶名称
     * @param file        文件名
     * @param objectName  对象名
     * @return ObjectWriteResponse对象
     */
    public static ObjectWriteResponse uploadFile(String bucketName, MultipartFile file, String objectName) throws Exception {
        InputStream inputStream = file.getInputStream();
        Optional<MediaType> optional = MediaTypeFactory.getMediaType(objectName);
        String mediaType = optional.orElseThrow(() -> new RuntimeException("文件类型暂不支持")).toString();
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .contentType(mediaType)
                .stream(inputStream, inputStream.available(), -1)
                .build();
        return minioClient.putObject(putObjectArgs);
    }

    /**
     * 上传本地文件
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @param fileName   本地文件路径
     */
    public static ObjectWriteResponse uploadFile(String bucketName, String objectName, String fileName) throws Exception {
        UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .filename(fileName)
                .build();
        return minioClient.uploadObject(uploadObjectArgs);
    }

    /**
     * 通过流上传文件
     *
     * @param bucketName  存储桶名称
     * @param objectName  文件对象
     * @param inputStream 文件流
     */
    public static ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) throws Exception {
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .stream(inputStream, inputStream.available(), -1)
                .build();
        return minioClient.putObject(putObjectArgs);
    }

    /**
     * 创建文件夹或目录
     *
     * @param bucketName 存储桶名称
     * @param objectName 目录路径
     */
    public static ObjectWriteResponse createDir(String bucketName, String objectName) throws Exception {
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
                .build();
        return minioClient.putObject(putObjectArgs);
    }

    /**
     * 获取文件信息, 如果抛出异常则说明文件不存在
     *
     * @param bucketName 存储桶名称
     * @param objectName 文件名称
     */
    public static String getFileStatusInfo(String bucketName, String objectName) throws Exception {
        StatObjectArgs statObjectArgs = StatObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        return minioClient.statObject(statObjectArgs).toString();
    }

    /**
     * 拷贝文件
     *
     * @param bucketName    存储桶名称
     * @param objectName    文件名
     * @param srcBucketName 目标存储桶
     * @param srcObjectName 目标文件名
     */
    public static ObjectWriteResponse copyFile(String bucketName, String objectName, String srcBucketName, String srcObjectName) throws Exception {
        return minioClient.copyObject(CopyObjectArgs.builder()
                .source(CopySource.builder()
                        .bucket(bucketName)
                        .object(objectName).build())
                .bucket(srcBucketName)
                .object(srcObjectName).build());
    }

    /**
     * 删除文件
     *
     * @param bucketName 存储桶名称
     * @param objectName 文件名称
     */
    public static void removeFile(String bucketName, String objectName) throws Exception {
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        minioClient.removeObject(removeObjectArgs);
    }

    /**
     * 批量删除文件
     *
     * @param bucketName 存储桶名称
     * @param keys       需要删除的文件列表
     */
    public static void removeFiles(String bucketName, List<String> keys) {
        keys.forEach(key -> {
            try {
                removeFile(bucketName, key);
            } catch (Exception e) {
                log.error("批量删除失败!error:{0}", e);
            }
        });
    }

    /**
     * 获取文件外链
     *
     * @param bucketName 存储桶名称
     * @param objectName 文件名
     * @param expires    过期时间 <=7 秒 (外链有效时间(单位:秒))
     * @return 文件外链
     */
    public static String getPreSignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .expiry(expires)
                .bucket(bucketName)
                .object(objectName)
                .build();
        return minioClient.getPresignedObjectUrl(args);
    }

    /**
     * 获得文件外链
     *
     * @param bucketName 存储桶名称
     * @param objectName 文件名
     * @return 文件外链
     */
    public static String getPreSignedObjectUrl(String bucketName, String objectName) throws Exception {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .method(Method.GET)
                .build();
        return minioClient.getPresignedObjectUrl(args);
    }

    /**
     * 将URLDecoder编码转成UTF8
     *
     * @param str 字符串
     * @return 编码
     */
    public static String getUtf8ByDecoder(String str) throws UnsupportedEncodingException {
        String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
        return URLDecoder.decode(url, "UTF-8");
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

点赞

当前页面评论已关闭。

隐藏
变装