SpringBoot后端开发常用工具详细介绍——Minio资源管理器

背景

在后端开发中,常常会涉及到各种静态资源的操作,比如上传图片、下载图片、上传下载PDF

那么我们在进行迁移开发和部署或者各种分布式开发时就会面对着这些资源的处理,以防止目录丢失或者其他异常。

Minio就是一个对象存储解决方案,一般都做min-io,顾名思义就是:最小输入输出

MinIO有能力在任何地方部署 - 公有云或私有云,裸金属基础设施,编排环境,以及边缘基础设施。所以可以更快速的解决上面提到的一系列问题。

操作

这里以我们常用的windows开发环境为例,开发环境熟练使用后,部署时也能很顺畅的使用了。

先简单说一下minio里的一个概念

bucket桶: 可以简单理解为文件夹,桶是 MinIO 中用于组织和管理对象的容器。每个桶都有一个唯一的名称,在同一个 MinIO 实例中,桶名称必须是唯一的。用户可以通过桶来对对象进行逻辑分组。

1.下载并启动minio

下载地址为:https://dl.minio.org.cn/server/minio/release/windows-amd64/minio.exe

启动命令:在minio.exe文件目录下打开cmd并执行minio.exe server minio,将会启动minio,并且打印访问的url和用户名、密码

访问minio的url地址,并输入上面的用户名密码:

2. 添加依赖与配置项

pom.xml

xml 复制代码
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.3.6</version>
</dependency>

application.yml

yaml 复制代码
spring:
  minio:
    access-key: minioadmin # 用户名
    secret-key: minioadmin #密码
    url: http://127.0.0.1:9000  #访问地址

3. 创建MinioConfig配置类信息

通过以下的配置,我们就可以创建一个适用于我们上面启动的minio的配置项,同时完成了MinioClient的注册

java 复制代码
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.minio")
public class MinioConfig {

    private String accessKey;
    private String secretKey;
    private String url;
	// 或者,主要目的是获取yml中的配置内容
    //@Value("${spring.minio.url}")
    //private String minioEndpoint;
    //@Value("${spring.minio.access-key}")
    //private String minioAccessKey;
    //@Value("${spring.minio.secret-key}")
    //private String minioSecretKey;
    @Bean
    public MinioClient minioClient(){
        return MinioClient.builder()
                .endpoint(url)
                .credentials(accessKey,secretKey)
                .build();
    }
}

4. 常用操作

我们可以进入自动注入的minioClient配置类查看常用操作

我们主要介绍常用的一些操作

4.0 创建单元测试

创建单元测试,并自动注入MinioClient

java 复制代码
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class test {
    @Resource
    private MinioClient minioClient;
   	// 以桶为test,文件为D:/test/test.jpg为案例
    private final String bucketName = "test";
    File file = new File("D:/test/test.jpg");
}
4.1 创建桶
java 复制代码
@Test
void createBucket() throws Exception {
    if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
    }
}

可以看到已经成功创建了桶

4.2 删除桶
java 复制代码
@Test
void deleteBucket() throws Exception {
    if (minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }
}

可以看到桶被删除了

4.3 检测桶是否存在
java 复制代码
@Test
void bucketExists() throws Exception {
    boolean exists = minioClient.bucketExists(
            BucketExistsArgs.builder().bucket(bucketName).build());
    System.out.println(exists);
}

当我们分别检测桶发现桶不存在

重新执行创建桶操作,可以看到桶返回存在

4.4 上传文件
java 复制代码
@Test
void fileUpload() throws Exception {
    FileInputStream inputStream = new FileInputStream(file);
    minioClient.putObject(PutObjectArgs.builder()
            .bucket(bucketName)
            .object(file.getName())
            .stream(inputStream, file.length(), -1)
            .contentType(MediaType.IMAGE_JPEG_VALUE)
            .build());
}

test桶中添加了新的文件

4.5 下载文件
java 复制代码
@Test
void fileDownload() throws Exception {
    try (InputStream stream = minioClient.getObject(
            GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(file.getName())
                    .build())) {
        // Save the file locally or process the stream as needed
        Files.copy(stream, Paths.get("D:/test/downloaded_" + file.getName()));
    }
}

文件按照路径和命名存储到了新的位置

4.6 检测文件是否存在
java 复制代码
@Test
void fileExists() throws Exception {
    try {
        StatObjectResponse response = minioClient.statObject(
            StatObjectArgs.builder()
            .bucket(bucketName)
            .object(file.getName())
            .build());
        System.out.println(response);
    } catch (MinioException e) {
        System.out.println(e.getMessage());
    }
}

如果存在,则文件信息被返回

如果不存在,则产生异常,我们可以捕获异常进行处理

4.7 删除文件
java 复制代码
@Test
void fileDelete() throws Exception {
    minioClient.removeObject(
            RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(file.getName())
                    .build());
}

文件被删除了

5. 自定义我们自己的Minio工具类

java 复制代码
@Component
public class MinioUtils {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfig configuration;

    /**
     * @param name 名字
     * @Description description: 判断bucket是否存在,不存在则创建
     */
    public boolean existBucket(String name) {
        boolean exists;
        try {
            exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
            if (!exists) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
                exists = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            exists = false;
        }
        return exists;
    }

    /**
     * @param bucketName 存储bucket名称
     * @Description 创建存储bucket
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * @param bucketName 存储bucket名称
     * @Description 删除存储bucket
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * @param fileName 文件名称
     * @param time     时间
     * @Description 获取上传临时签名
     */
    @SneakyThrows
    public Map getPolicy(String fileName, ZonedDateTime time,String bucketName) {
        PostPolicy postPolicy = new PostPolicy(bucketName, time);
        postPolicy.addEqualsCondition("key", fileName);
        try {
            Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
            HashMap<String, String> map1 = new HashMap<>();
            map.forEach((k, v) -> {
                map1.put(k.replaceAll("-", ""), v);
            });
            map1.put("host", configuration.getUrl() + "/" + bucketName);
            return map1;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param objectName 对象名称
     * @param method     方法
     * @param time       时间
     * @param timeUnit   时间单位
     * @Description 获取上传文件的url
     */
    public String getPolicyUrl(String objectName, Method method,String bucketName, int time, TimeUnit timeUnit) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(method)
                    .bucket(bucketName)
                    .object(objectName)
                    .expiry(time, timeUnit).build());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * @param file     文件
     * @param fileName 文件名称
     * @Description 上传文件
     */
    public void upload(MultipartFile file, String fileName,String bucketName) {
        // is deviceImg bucket exist ?
        boolean b = existBucket(bucketName);
        if (!b) {
            makeBucket(bucketName);
        }
        // 使用putObject上传一个文件到存储桶中。
        try {
            InputStream inputStream = file.getInputStream();
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param objectName 对象名称
     * @param time       时间
     * @param timeUnit   时间单位
     * @Description 根据filename获取文件访问地址
     */
    public String getUrl(String objectName,String bucketName, int time, TimeUnit timeUnit) {
        String url = null;
        try {
            url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(objectName)
                    .expiry(time, timeUnit).build());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return url;
    }

    /**
     * @Description description: 下载文件
     */
    public ResponseEntity<byte[]> download(String fileName,String bucketName) {
        ResponseEntity<byte[]> responseEntity = null;
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
            out = new ByteArrayOutputStream();
            IOUtils.copy(in, out);
            //封装返回值
            byte[] bytes = out.toByteArray();
            HttpHeaders headers = new HttpHeaders();
            try {
                headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            headers.setContentLength(bytes.length);
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setAccessControlExposeHeaders(Arrays.asList("*"));
            responseEntity = new ResponseEntity<byte[]>(bytes, headers, ResultCode.SUCCESS.code);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return responseEntity;
    }

    /**
     * @param objectFile 对象文件
     */
    public String getFileUrl(String objectFile,String bucketName) {
        try {

            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(objectFile)
                    .build()
            );
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

public String getFileUrl(String objectFile,String bucketName) {

try {

        return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(bucketName)
                .object(objectFile)
                .build()
        );
    } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

}

复制代码
相关推荐
真的想不出名儿3 分钟前
苍穹外卖-day07(Spring Cache & 购物车业务逻辑)
java·后端
雾喔10 分钟前
Java-08
java·开发语言
小河vlog14 分钟前
.NET 8 获取CPU序列号和主板序列号异常问题
java·服务器·.net
yuanManGan15 分钟前
数据结构漫游记:初识vector
java·开发语言·数据结构
Nijika...27 分钟前
libilibi项目总结(17)Elasticsearch 的使用
java·后端·spring·elasticsearch
恩爸编程30 分钟前
探秘 Maven 依赖范围:你的项目“魔法圈”
java·maven·maven开发·maven多模块开发·maven依赖范围·maven依赖范围概念·maven依赖范围使用
shine_du1 小时前
架构师之路--springboot核心类SpringApplication方法run的源码启动流程
java·spring boot·后端
毒丐1 小时前
VirtualBox使用教程
java·服务器·c++
Easy_Company1 小时前
Hadoop实验:关于MapReduce词频统计的实验步骤
java·大数据·hadoop·mapreduce
数据小爬虫@1 小时前
如何利用Java爬虫获得淘宝买家秀
java·开发语言·爬虫