下面是在 Spring Boot 项目中集成 MinIO,并提供上传、下载和生成免密下载链接的功能。
1. 添加依赖
首先,在 pom.xml
文件中添加 Spring Boot 和 MinIO 的相关依赖。
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MinIO Java SDK -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.5</version>
</dependency>
<!-- Lombok for getter/setter/toString/etc. -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. 配置 MinIO 连接
在 application.properties
或 application.yml
文件中配置 MinIO 连接信息。
application.properties
minio.endpoint=http://localhost:9000
minio.access-key=minioadmin
minio.secret-key=minioadmin
minio.bucket-name=my-bucket
application.yml
minio:
endpoint: http://localhost:9000
access-key: minioadmin
secret-key: minioadmin
bucket-name: my-bucket
3. 创建 MinIO 配置类
创建一个配置类来初始化 MinIO 客户端。
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MinioConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.access-key}")
private String accessKey;
@Value("${minio.secret-key}")
private String secretKey;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}
4. 创建 MinIO 操作工具类
为了方便使用 MinIO,可以创建一个工具类来封装常用的操作。
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.MinioException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.util.Date;
@Component
public class MinioUtil {
@Autowired
private MinioClient minioClient;
@Value("${minio.bucket-name}")
private String bucketName;
// 初始化桶
public void initBucket() throws MinioException {
if (!minioClient.bucketExists(bucketName)) {
minioClient.makeBucket(bucketName);
}
}
// 上传文件
public String uploadFile(String objectName, InputStream inputStream, String contentType) throws MinioException {
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(inputStream, inputStream.available(), -1)
.contentType(contentType)
.build()
);
return getObjectUrl(objectName);
}
// 下载文件
public InputStream downloadFile(String objectName) throws MinioException {
return minioClient.getObject(
io.minio.GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build()
);
}
// 生成免密下载链接
public String generatePresignedUrl(String objectName, long expirationInSeconds) throws MinioException {
return minioClient.getPresignedObjectUrl(
io.minio.GetPresignedObjectUrlArgs.builder()
.method(io.minio.http.Method.GET)
.bucket(bucketName)
.object(objectName)
.expiry(expirationInSeconds)
.build()
);
}
// 获取对象的 URL
public String getObjectUrl(String objectName) {
return minioClient.getObjectUrl(bucketName, objectName);
}
}
5. 创建 Controller 层
创建控制器层来处理 HTTP 请求,并使用 MinIO 工具类进行操作。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.Date;
@RestController
@RequestMapping("/minio")
public class MinioController {
@Autowired
private MinioUtil minioUtil;
// 初始化桶
@GetMapping("/init-bucket")
public String initBucket() {
try {
minioUtil.initBucket();
return "Bucket initialized successfully";
} catch (Exception e) {
return "Failed to initialize bucket: " + e.getMessage();
}
}
// 上传文件
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
try {
InputStream inputStream = file.getInputStream();
String objectName = file.getOriginalFilename();
String url = minioUtil.uploadFile(objectName, inputStream, file.getContentType());
return "File uploaded successfully: " + url;
} catch (Exception e) {
return "Failed to upload file: " + e.getMessage();
}
}
// 下载文件
@GetMapping("/download/{objectName}")
public ResponseEntity<InputStream> downloadFile(@PathVariable String objectName) {
try {
InputStream inputStream = minioUtil.downloadFile(objectName);
return ResponseEntity.ok()
.header("Content-Disposition", "attachment; filename=\"" + objectName + "\"")
.body(inputStream);
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}
// 生成免密下载链接
@GetMapping("/presigned-url/{objectName}")
public String generatePresignedUrl(@PathVariable String objectName, @RequestParam long expirationInSeconds) {
try {
String url = minioUtil.generatePresignedUrl(objectName, expirationInSeconds);
return "Presigned URL: " + url;
} catch (Exception e) {
return "Failed to generate presigned URL: " + e.getMessage();
}
}
}
6. 启动类
确保启动类位于正确的包路径下,以便 Spring Boot 自动扫描到所有组件。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
7. 测试
启动应用并测试各个接口是否正常工作。
mvn spring-boot:run
可以使用 Postman 或其他 HTTP 客户端来测试这些接口。
快捷方式和最佳实践
-
Lombok:使用 Lombok 可以大大减少样板代码,如
getter
、setter
、toString
等。 -
全局异常处理:使用
@ControllerAdvice
注解创建全局异常处理器,统一处理异常。 -
日志记录:使用
logback
或log4j2
配置日志记录,方便调试和监控。 - 安全性:确保 MinIO 服务器的安全性,如设置访问密钥、限制访问 IP 等。
- 性能优化:合理设置 MinIO 的存储策略和网络配置,避免性能瓶颈。