本文详细介绍了如何在 Spring Boot 项目中封装 MinIO 对象存储工具类,提供完整的配置和工具方法。
MinIO 是一款高性能、开源、兼容 Amazon S3 API 的分布式对象存储系统,专为云原生架构和大规模非结构化数据场景设计。其核心定位是成为私有云/混合云环境中的标准存储方案,适用于从数据湖到 AI/ML、容器化部署等多样化需求。
cdkj-minio
├── annotation # 注解
│ └── EnableAutoMinio # 启用自动 MinIO 配置
├── config # 配置类
│ ├── MinioAutoConfiguration # MinIO 自动配置
│ ├── MinioMarkerConfiguration # MinIO 标记配置
│ └── MinioProperties # MinIO 配置读取
├── connectivity # 连接库
│ └── MinioConfiguration # MinIO 连接配置
├── enums # 枚举库
│ └── ContentTypeEnums # 内容类型枚举
└── MinioUtils # MinIO 工具类核心
<dependencies>
<!-- MinIO -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<exclusions>
<exclusion>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
</dependencies>
EnableAutoMinio 注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({MinioMarkerConfiguration.class})
public @interface EnableAutoMinio {}
Spring Boot 项目引入:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableRetry
@EnableAsync
@Configuration
@EnableAutoMinio
@EnableAutoMongo
@EnableAutoCdkjJob
@EnableDiscoveryClient
@EnableTransactionManagement
@EnableFeignClients(basePackages = {"com.*.*.client"})
public @interface EnableAutoApi {}
MinioProperties 配置类:
@Data
@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "spring.minio")
public class MinioProperties {
private String domain; // 访问域名
private String endpoint; // 存储端点
private Integer port; // 端口
private String accessKey; // 访问密钥
private String secretKey; // 密钥
private String bucketName; // 存储桶名称
private Integer expiry; // 分片对象过期时间(天)
private Integer breakpointTime; // 断点续传有效时间(天)
}
public enum ContentTypeEnums {
DEFAULT("default", "application/octet-stream"),
JPG("jpg", "image/jpeg"),
PNG("png", "image/png"),
MP4("mp4", "video/mp4");
// ... 更多类型
public static String formContentType(String suffix) {
// 根据文件后缀获取 Content-Type
}
}
普通文件上传:
public static ObjectWriteResponse uploadFile(String bucketName,
MultipartFile file,
String fileName,
ContentTypeEnums contentType) throws Exception {
InputStream inputStream = file.getInputStream();
return client.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.contentType(contentType.getValue())
.stream(inputStream, inputStream.available(), -1)
.build());
}
分片上传:
public static ResponseBuilder uploadFileFragment(MultipartFile file,
Integer currIndex,
Integer totalPieces,
String md5) throws Exception {
// 分片上传实现,支持大文件断点续传
}
文件存在性检查:
public static boolean isFileExist(String bucketName, String fileName) {
try {
client.statObject(StatObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
return true;
} catch (Exception e) {
return false;
}
}
文件列表获取:
public static Iterable<Result<Item>> getFilesByPrefix(String bucketName,
String prefix,
boolean recursive) {
return client.listObjects(ListObjectsArgs.builder()
.bucket(bucketName)
.prefix(prefix)
.recursive(recursive)
.build());
}
获取文件流:
public InputStream getFileStream(String bucketName, String fileName) throws Exception {
return client.getObject(GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
}
断点下载:
public InputStream getFileStream(String bucketName, String fileName,
long offset, long length) throws Exception {
return client.getObject(GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.offset(offset)
.length(length)
.build());
}
批量删除:
public static Iterable<Result<DeleteError>> removeFiles(String bucketName,
List<String> filePaths) {
List<DeleteObject> objectPaths = filePaths.stream()
.map(DeleteObject::new)
.collect(Collectors.toList());
return client.removeObjects(RemoveObjectsArgs.builder()
.bucket(bucketName)
.objects(objectPaths)
.build());
}
生成临时访问链接:
public static String getPresignedObjectUrl(String bucketName, String fileName) throws Exception {
GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(fileName)
.method(Method.GET)
.build();
return client.getPresignedObjectUrl(args);
}
@Configuration(proxyBeanMethods = false)
public class MinioMarkerConfiguration {
@Bean
public Marker mybatisMarker() {
return new Marker();
}
public static class Marker {}
}
@Lazy(false)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({MinioProperties.class})
@AutoConfigureAfter({WebClientAutoConfiguration.class})
@ConditionalOnBean(MinioMarkerConfiguration.Marker.class)
public class MinioAutoConfiguration {
@Bean(initMethod = "start")
public MinioConfiguration minioConfiguration() {
return new MinioConfiguration(minioProperties);
}
}
public class MinioConfiguration {
public void start() {
MinioClient.Builder builder = MinioClient.builder();
if (minioProperties.getPort() == null) {
builder.endpoint(minioProperties.getEndpoint());
} else {
builder.endpoint(minioProperties.getEndpoint(),
minioProperties.getPort(), false);
}
MinioClient client = builder
.credentials(minioProperties.getAccessKey(),
minioProperties.getSecretKey())
.build();
new MinioUtils(client); // 实例化工具类
}
}
在 resources/META-INF/spring 目录下创建 org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件:
com.cdkjframework.minio.config.MinioAutoConfiguration
Spring Boot 封装 MinIO 工具的核心意义在于将分布式存储能力转化为可复用的基础设施,通过标准化、模块化的设计,显著降低开发复杂度,提升系统健壮性和可维护性。这种封装不仅是技术层面的优化,更是工程实践中的最佳选择,尤其适用于需要快速迭代、高并发处理及多云兼容的现代应用架构。
主要特性:
开源地址:
如果觉得项目对你有帮助,欢迎 Star 和 Fork!如有问题或建议,欢迎留言讨论。