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;
}

}

复制代码
相关推荐
这周也會开心12 分钟前
云服务器安装JDK、Tomcat、MySQL
java·服务器·tomcat
hrrrrb1 小时前
【Spring Security】Spring Security 概念
java·数据库·spring
小信丶1 小时前
Spring 中解决 “Could not autowire. There is more than one bean of type“ 错误
java·spring
周杰伦_Jay2 小时前
【Java虚拟机(JVM)全面解析】从原理到面试实战、JVM故障处理、类加载、内存区域、垃圾回收
java·jvm
摇滚侠3 小时前
Spring Boot 3零基础教程,IOC容器中组件的注册,笔记08
spring boot·笔记·后端
程序员小凯6 小时前
Spring Boot测试框架详解
java·spring boot·后端
豐儀麟阁贵6 小时前
基本数据类型
java·算法
_extraordinary_6 小时前
Java SpringMVC(二) --- 响应,综合性练习
java·开发语言
你的人类朋友6 小时前
什么是断言?
前端·后端·安全
程序员 Harry7 小时前
深度解析:使用ZIP流式读取大型PPTX文件的最佳实践
java