AWS S3 + Spring Boot - File Upload, Download, List, and Delete Example
Here’s how you can implement AWS S3 file upload, download, list, and delete functionalities in a Spring Boot application step-by-step.
1. Setting Up AWS S3
1. Create an AWS Account: If you don't have one, sign up for an AWS account.
2. Create an S3 Bucket:
- Log in to the AWS Management Console.
- Navigate to the S3 service.
- Click "Create bucket."
- Provide a unique bucket name and choose an appropriate region.
- Configure access permissions as needed (e.g., public or private).
2. Spring Boot Project Setup
Add the following dependency in your pom.xml (for Maven) or build.gradle (for Gradle).
Maven:
<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3</artifactId> <version>2.20.35</version> <!-- Latest version --> </dependency>
Gradle:
implementation 'software.amazon.awssdk:s3:2.20.35'
3. Configure AWS S3
application.properties
aws.s3.access-key=your-access-key aws.s3.secret-key=your-secret-key aws.s3.region=your-region aws.s3.bucket-name=your-bucket-name
4. Create AWS S3 Configuration
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; @Configuration public class S3Config { @Value("${aws.s3.access-key}") private String accessKey; @Value("${aws.s3.secret-key}") private String secretKey; @Value("${aws.s3.region}") private String region; @Bean public S3Client s3Client() { return S3Client.builder() .region(Region.of(region)) .credentialsProvider(StaticCredentialsProvider.create( AwsBasicCredentials.create(accessKey, secretKey))) .build(); } }
5. Implement the S3 Service
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.*; import java.io.IOException; import java.util.List; import java.util.stream.Collectors; @Service public class S3Service { @Value("${aws.s3.bucket-name}") private String bucketName; private final S3Client s3Client; public S3Service(S3Client s3Client) { this.s3Client = s3Client; } public String uploadFile(MultipartFile file) throws IOException { String fileName = file.getOriginalFilename(); s3Client.putObject( PutObjectRequest.builder() .bucket(bucketName) .key(fileName) .build(), RequestBody.fromBytes(file.getBytes()) ); return fileName; } public byte[] downloadFile(String fileName) { return s3Client.getObject( GetObjectRequest.builder() .bucket(bucketName) .key(fileName) .build(), software.amazon.awssdk.core.sync.ResponseTransformer.toBytes() ).asByteArray(); } public List<String> listFiles() { ListObjectsV2Response response = s3Client.listObjectsV2( ListObjectsV2Request.builder() .bucket(bucketName) .build() ); return response.contents().stream() .map(S3Object::key) .collect(Collectors.toList()); } public void deleteFile(String fileName) { s3Client.deleteObject( DeleteObjectRequest.builder() .bucket(bucketName) .key(fileName) .build() ); } }
6. Create a Controller
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.List; @RestController @RequestMapping("/api/s3") public class S3Controller { private final S3Service s3Service; public S3Controller(S3Service s3Service) { this.s3Service = s3Service; } @PostMapping("/upload") public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) { try { String fileName = s3Service.uploadFile(file); return ResponseEntity.status(HttpStatus.CREATED).body("File uploaded successfully: " + fileName); } catch (IOException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("File upload failed"); } } @GetMapping("/download/{fileName}") public ResponseEntity<byte[]> downloadFile(@PathVariable String fileName) { byte[] data = s3Service.downloadFile(fileName); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"") .body(data); } @GetMapping("/list") public ResponseEntity<List<String>> listFiles() { List<String> files = s3Service.listFiles(); return ResponseEntity.ok(files); } @DeleteMapping("/delete/{fileName}") public ResponseEntity<String> deleteFile(@PathVariable String fileName) { s3Service.deleteFile(fileName); return ResponseEntity.ok("File deleted successfully: " + fileName); } }
7. Test Endpoints
1. Upload File
Endpoint: POST /api/s3/upload
Body: Form-data (key: file, value: file to upload)
2. Download File
Endpoint: GET /api/s3/download/{fileName}
Response: File content as application/octet-stream.
3. List Files
Endpoint: GET /api/s3/list
Response: List of file names in the bucket.
4. Delete File
Endpoint: DELETE /api/s3/delete/{fileName}
Response: Confirmation message.
8. Key Notes
- Security: Use environment variables or AWS Secrets Manager for sensitive credentials.
- File Validation: Validate file size, type, and content before upload.
- Exception Handling: Add proper exception handling to gracefully handle AWS SDK exceptions.
- CORS: Configure CORS if accessing these endpoints from a front-end application.