This document provides a hands-on lab to integrate Spring Boot with MinIO. It includes step-by-step instructions for setting up MinIO using Docker, configuring a Spring Boot application, and testing it using Postman. Exercises are included to reinforce learning.
Lab Objectives
Set up MinIO using Docker.
Integrate MinIO with a Spring Boot application.
Implement CRUD operations for file management.
Test the implementation using Postman.
Prerequisites
Docker: Ensure Docker is installed and running.
Java: Install Java 17+.
Spring Boot: Use Spring Boot 3.x.
Postman: Install Postman for API testing.
Maven: Install Maven for dependency management.
Step 1: Set Up MinIO Using Docker
Pull the MinIO Docker image:
docker pull minio/minio
Run the MinIO container:
docker run -p 9000:9000 -p 9001:9001 \ -e "MINIO_ROOT_USER=YOUR_ACCESS_KEY" \ -e "MINIO_ROOT_PASSWORD=YOUR_SECRET_KEY" \ --name minio \ -v $(pwd)/data:/data \ -v $(pwd)/config:/root/.minio \ minio/minio server /data --console-address ":9001"
Access the MinIO web UI at
http://localhost:9001
.Login using the credentials provided as
MINIO_ROOT_USER
andMINIO_ROOT_PASSWORD
.Create a bucket named
mybucket
.
Step 2: Create Spring Boot Project
Generate a Spring Boot project from Spring Initializr with the following dependencies:
Spring Web
Spring Boot DevTools
Lombok
MinIO SDK (manually added as a dependency)
Add the MinIO SDK dependency in
pom.xml
:<dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.5.2</version> </dependency>
Step 3: Configure MinIO in Spring Boot
Add MinIO configuration properties in
application.properties
:minio.url=http://localhost:9000 minio.access-key=YOUR_ACCESS_KEY minio.secret-key=YOUR_SECRET_KEY minio.bucket.name=mybucket
Create a configuration class:
import io.minio.MinioClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MinioConfig { @Bean public MinioClient minioClient() { return MinioClient.builder() .endpoint("http://localhost:9000") .credentials("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY") .build(); } }
Step 4: Implement MinIO Features
1. File Upload
File Upload
@RestController @RequestMapping("/api/files") public class FileController { private final MinioClient minioClient; private final String bucketName = "mybucket"; public FileController(MinioClient minioClient) { this.minioClient = minioClient; } @PostMapping("/upload") public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) { try { String fileName = file.getOriginalFilename(); minioClient.putObject( PutObjectArgs.builder() .bucket(bucketName) .object(fileName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build() ); return ResponseEntity.ok("File uploaded successfully: " + fileName); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error: " + e.getMessage()); } } }
2. List Files
@GetMapping("/list") public ResponseEntity<List<String>> listFiles() { try { List<String> fileNames = new ArrayList<>(); Iterable<Result<Item>> items = minioClient.listObjects( ListObjectsArgs.builder().bucket(bucketName).build() ); for (Result<Item> item : items) { fileNames.add(item.get().objectName()); } return ResponseEntity.ok(fileNames); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); } }
3. Download File
@GetMapping("/download/{filename}") public ResponseEntity<Resource> downloadFile(@PathVariable String filename) { try { InputStream stream = minioClient.getObject( GetObjectArgs.builder().bucket(bucketName).object(filename).build() ); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(new InputStreamResource(stream)); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); } }
4. Delete File
@DeleteMapping("/delete/{filename}") public ResponseEntity<String> deleteFile(@PathVariable String filename) { try { minioClient.removeObject( RemoveObjectArgs.builder().bucket(bucketName).object(filename).build() ); return ResponseEntity.ok("File deleted successfully: " + filename); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error: " + e.getMessage()); } }
Step 5: Test with Postman
1. File Upload
Endpoint:
POST /api/files/upload
Headers:
Content-Type: multipart/form-data
Body: Form-data with key
file
and value as the file to upload.
2. List Files
Endpoint:
GET /api/files/list
Headers: None
3. Download File
Endpoint:
GET /api/files/download/{filename}
Headers: None
Response: Downloaded file.
4. Delete File
Endpoint:
DELETE /api/files/delete/{filename}
Headers: None
Response: Confirmation message.