Upload Multiple Files to Amazon S3 Bucket in Spring Boot

Follow these steps to create a REST API for uploading multiple files to an Amazon S3 bucket in Spring Boot:

  1. Create a Spring Boot Project:
  2. We assume you have a Spring Boot project set up and ready. If not, you can create one using Spring Initializr or your preferred approach.

  3. Add Amazon SDK Dependencies:
  4. Add the AWS Java SDK For Amazon S3 dependency to your Spring Boot project:

    <dependency>
        <groupid>com.amazonaws</groupid>
        <artifactid>aws-java-sdk-s3</artifactid>
        <version>1.12.556</version>
    </dependency>
    implementation group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.12.556'
  5. Add Configurations:
  6. To access S3 bucket from a Spring Boot project, you'll need to configure your project with AWS credentials. You can do this by providing your AWS access key and secret key, which can be set in your application.properties or application.yml file or loaded from environment variables. For example, in your application.properties file:

    server.port=8080
    
    aws.access-key = your-access-key
    aws.access-secret-key = your-access-secret-key
    aws.region = us-east-1
  7. Create an AmazonS3Client:
  8. Create a bean for the AmazonS3 client in your Spring Boot application configuration class. You can use the @Configuration annotation to create a configuration class:

    package com.example.app.config;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import com.amazonaws.auth.AWSStaticCredentialsProvider;
    import com.amazonaws.auth.BasicAWSCredentials;
    import com.amazonaws.services.s3.AmazonS3;
    import com.amazonaws.services.s3.AmazonS3ClientBuilder;
    
    @Configuration
    public class AmazonS3Config {
    
      private String awsAccessKey;
      private String awsAccessSecretKey;
      private String awsRegion;
    
      public AmazonS3Config(@Value(value = "${aws.access-key}") String awsAccessKey,
          @Value(value = "${aws.access-secret-key}") String awsAccessSecretKey,
          @Value(value = "${aws.region}") String awsRegion) {
        this.awsAccessKey = awsAccessKey;
        this.awsAccessSecretKey = awsAccessSecretKey;
        this.awsRegion = awsRegion;
      }
    
      public AWSStaticCredentialsProvider getAwsCredentialsProvider() {
        BasicAWSCredentials awsCred =
            new BasicAWSCredentials(this.awsAccessKey, this.awsAccessSecretKey);
        return new AWSStaticCredentialsProvider(awsCred);
      }
    
      @Bean
      public AmazonS3 getAmazonS3Client() {
        return AmazonS3ClientBuilder.standard().withRegion(this.awsRegion)
            .withCredentials(getAwsCredentialsProvider()).build();
      }
    
    }
  9. Create a Service:
  10. Create a service interface named S3FilesUploadService with a method for uploading files to your S3 bucket:

    package com.example.app.service;
    
    import java.util.List;
    import java.util.Map;
    import org.springframework.web.multipart.MultipartFile;
    
    public interface S3FilesUploadService {
    
      Map<String, String> uploadMultipleFilesToS3(List<MultipartFile> multipartfiles);
    
    }
    

  11. Create a Service Implementation:
  12. Create an implementation class that implements the S3FilesUploadService interface and handles the business logic. Let's create a class called S3FilesUploadServiceImpl:

    package com.example.app.service.impl;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.multipart.MultipartFile;
    import com.amazonaws.services.s3.AmazonS3;
    import com.amazonaws.services.s3.model.CannedAccessControlList;
    import com.amazonaws.services.s3.model.PutObjectRequest;
    import com.example.app.service.S3FilesUploadService;
    
    @Service
    public class S3FilesUploadServiceImpl implements S3FilesUploadService {
    
      private String s3BaseUrl = "https://s3-us-east-1.s3.amazonaws.com/";
    
      private String bucketName = "my-test-bucket";
    
      private String folderName = "/myfolder/images/";
    
      @Autowired
      private AmazonS3 s3Client;
    
      @Override
      public Map<String, String> uploadMultipleFilesToS3(List<MultipartFile> multipartfiles) {
        Map<String, String> response = new HashMap<>();
        if (!multipartfiles.isEmpty()) {
          multipartfiles.forEach(multipartfile -> {
            String filePathName = multipartfile.getOriginalFilename();
            File file = new File(filePathName);
    
            try (FileOutputStream fos = new FileOutputStream(file)) {
    
              if (!file.exists()) {
                file.createNewFile();
              }
    
              fos.write(multipartfile.getBytes());
              fos.flush();
    
              /* uploading file to S3 */
              s3Client
                  .putObject(new PutObjectRequest(bucketName, folderName + "/" + file.getName(), file)
                      .withCannedAcl(CannedAccessControlList.PublicRead));
    
              /* Url location of the uploaded file in S3. You should save it in database */
              String s3FileAccessUrl = s3BaseUrl.concat(bucketName).concat(folderName)
                  .concat(file.getName()).replaceAll("\\s", "+");
    
              response.put("fileUrl", s3FileAccessUrl);
    
              file.delete();
    
            } catch (FileNotFoundException e) {
              e.printStackTrace();
            } catch (IOException e) {
              e.printStackTrace();
            }
          });
        }
        return response;
      }
    
    }
  13. Create a Web Controller:
  14. Create a controller class named S3FilesUploadController. It will handle HTTP requests and interact with the S3FilesUploadService to upload files to your S3 bucket:

    package com.example.app.controller;
    
    import java.util.List;
    import java.util.Map;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestPart;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.multipart.MultipartFile;
    import com.example.app.service.S3FilesUploadService;
    
    @RestController
    @RequestMapping(path = "/files")
    public class S3FilesUploadController {
    
      @Autowired
      private S3FilesUploadService s3FileUploadService;
    
      @PostMapping(value = "/upload-multiple")
      public ResponseEntity<Map<String, String>> uploadMultipleFiles(
          @RequestPart(name = "multipartfiles", required = true) List<MultipartFile> multipartfiles) {
    
        return ResponseEntity.ok(s3FileUploadService.uploadMultipleFilesToS3(multipartfiles));
      }
    }