场景

当后端项目需要进行文件存储时,一般会借助第三方的文件存储服务,Minio就是一个开源的文件存储服务,它自带前后端。

Minio安装

Minio可以借助docker进行安装,安装难度不高,详细看:Minio安装

SpringBoot继承Minio

Springboot上传文件到Minio容器

创建文件上传接口

// 以MultipartFile接收文件
@RequestMapping(value = "/minio", method = RequestMethod.POST)
    public Result<Map<String, String>> minioUpload(@RequestParam("file") MultipartFile file) throws Exception {
        String fileUrl = minio.upload(file);
        Map<String, String> map = new HashMap<>();
        map.put("fileUrl", fileUrl);
        return Result.ok(map);
    }

准备Minio所需要的参数

可以准备一个properties文件,将其与配置文件进行关联。

@Data
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {
    // Minio部署地址,端口默认为9000
    private String endPointUrl;
    // Minio登录账号
    private String accessKey;
    // Minio登陆密码
    private String secretKey;
    // Minio文件存储桶Name
    private String bucketName;
}

配置文件如下:

minio:
  end-point-url: http://120.46.189.171:9001
  access-key: admin
  secret-key: admin123456
  bucket-name: spzx-bucket

利用配置文件创建对象到IOC容器供后续使用,具体为MinioClient类,需要注入各种参数并且可以判断指定桶是否存在

@Slf4j
public class MinioConfig {

    @Autowired
    private MinioProperties minioProperties;

    @Bean
    public MinioClient minioClient() throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        // 创建一个Minio的客户端对象
        MinioClient minioClient = MinioClient.builder()
                .endpoint(minioProperties.getEndPointUrl())
                .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                .build();

        // 判断桶是否存在
        boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioProperties.getBucketName()).build());
        if (!found) {
            // 如果不存在,那么此时就创建一个新的桶
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioProperties.getBucketName()).build());
        } else {
            // 如果存在打印信息
            log.info("Bucket 'spzx-bucket' already exists.");
        }
        return minioClient;
    }
}

创建Minio工具类,封装具体的上传细节

@Slf4j
@EnableConfigurationProperties(value = MinioProperties.class)
public class Minio {

    @Autowired
    private MinioProperties minioProperties;

    @Autowired
    MinioClient minioClient;

    public String upload(MultipartFile multipartFile) throws Exception {
        try {
            // 设置存储对象名称,通过日期和uuid实现每日数据分开存储
            String dateDir = DateUtil.format(new Date(), "yyyyMMdd");
            String uuid = UUID.randomUUID().toString().replace("-", "");
            //20230801/443e1e772bef482c95be28704bec58a901.jpg
            String fileName = dateDir+"/"+uuid+multipartFile.getOriginalFilename();
            log.info("upload-filename:{}", fileName);
            // 以流的形式上传文件 stream参数为:文件流 文件大小 对象长度(-1表示未知)
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .stream(multipartFile.getInputStream(), multipartFile.getSize(), -1)
                    .object(fileName)
                    .build();
            minioClient.putObject(putObjectArgs);

            return minioProperties.getEndPointUrl() + "/" + minioProperties.getBucketName() + "/" + fileName ;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

通过一个自定义注解引入Minio服务

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(value = {Minio.class, MinioConfig.class})
public @interface EnableMinio {
}