Amazon S3 – SpringBoot RestAPIs Upload/Download File/Image to S3

Amazon Simple Storage Service (Amazon S3) is object storage built to store and retrieve any amount of data from web or mobile. Amazon S3 is designed to scale computing easier for developers. In the tutorial, we build SpringBoot RestAPIs to upload/download files/images to Amazon S3.

Next post:
Amazon S3 – SpringBoot RestAPIs List All Files in S3 Bucket
Amazon S3 – Delete File SpringBoot RestAPI

Technologies

  • Java 8
  • Maven 3.6.1
  • pring Tool Suite: 3.9.4.RELEASE
  • Spring Boot: 2.0.4.RELEASE
  • Amazon S3

Spring Amazon S3

– For init an AmazonS3 client, we use:


BasicAWSCredentials awsCreds = new BasicAWSCredentials(awsId, awsKey);
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
			.withRegion(Regions.fromName(region))
			.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
			.build();

– For upload S3 objects, we use:


public PutObjectResult putObject(
            String bucketName, String key, InputStream input, ObjectMetadata metadata)
            throws SdkClientException, AmazonServiceException;

– For download S3 objects, we use:


public S3Object getObject(GetObjectRequest getObjectRequest)
            throws SdkClientException, AmazonServiceException;

Practice

In the tutorial, we will setup an Amazon S3 bucket, an IAM user and create a SpringBoot RestAPIs to upload/download files/images to/from S3.

springboot-rest-api-upload-download-file-image-s3-aws + project-structure

Setup Amazon S3

Sign Up

Go to https://aws.amazon.com/s3/

springboot-rest-api-upload-download-file-image-s3-aws + sign-up

Choose Get started with Amazon S3.

Follow the instructions on the screen for sign up.
-> AWS will notify you by email when your account is active and available for you to use.

Create S3 Bucket

Now, your account is ready to use with AWS.
-> Sign in to AWS: https://console.aws.amazon.com/s3

springboot-rest-api-upload-download-file-image-s3-aws + create-bucket

Choose Create bucket, input information for creating bucket:

springboot-rest-api-upload-download-file-image-s3-aws + create bucket

Press Create -> result:

springboot-rest-api-upload-download-file-image-s3-aws + create bucket succeed

Create IAM user

Go to https://console.aws.amazon.com/iam/
In the navigation pane, choose Users and then choose Add user.

springboot-rest-api-upload-download-file-image-s3-aws + s3-add-user-step-0

Input User name, choose Programmatic access for Access type:

springboot-rest-api-upload-download-file-image-s3-aws + s3-add-user-step-1

Press Next: Permissions button -> go to Set permissions for ozenero-user screen.
Now, choose Attach existing policies directly -> filter policy type s3, then check AmazonS3FullAccess:

springboot-rest-api-upload-download-file-image-s3-aws + s3-add-user-step-2

Press Next: Review:

springboot-rest-api-upload-download-file-image-s3-aws + s3-add-user-step-3

Press Create user:

springboot-rest-api-upload-download-file-image-s3-aws + s3-add-user-step-4

Press Download.csv for {Access key ID, Secret access key}.

SpringBoot RestAPIs

Create SpringBoot project

Using SpringToolSuite to create a SpringBoot project. Then add needed dependency aws-java-sdk:

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk</artifactId>
    <version>1.11.379</version>
</dependency>

Configure Amazon Client

Create a S3Config.java file for setup AmazonS3 client:


package com.ozenero.s3.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.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
 
@Configuration
public class S3Config {
	@Value("${gkz.aws.access_key_id}")
	private String awsId;
 
	@Value("${gkz.aws.secret_access_key}")
	private String awsKey;
	
	@Value("${gkz.s3.region}")
	private String region;

	@Bean
	public AmazonS3 s3client() {
		
		BasicAWSCredentials awsCreds = new BasicAWSCredentials(awsId, awsKey);
		AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
								.withRegion(Regions.fromName(region))
		                        .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
		                        .build();
		
		return s3Client;
	}
}

Open ‘application.properties’, add aws configuration:


gkz.aws.access_key_id='add your access_key_id'
gkz.aws.secret_access_key='add your secret_access_key'
gkz.s3.bucket=ozenero-s3-bucket
gkz.s3.region=us-east-2

Note: Keep private for secret_access_key.

Implement S3 Upload/Download Service

Create S3Services.java interface:


package com.ozenero.s3.services;

import java.io.ByteArrayOutputStream;

import org.springframework.web.multipart.MultipartFile;

public interface S3Services {
	public ByteArrayOutputStream downloadFile(String keyName);
	public void uploadFile(String keyName, MultipartFile file);
}

Implement S3Services.java interface with S3ServicesImpl.java:


package com.ozenero.s3.services.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object;
import com.ozenero.s3.services.S3Services;
 
@Service
public class S3ServicesImpl implements S3Services {
	
	private Logger logger = LoggerFactory.getLogger(S3ServicesImpl.class);
	
	@Autowired
	private AmazonS3 s3client;
 
	@Value("${gkz.s3.bucket}")
	private String bucketName;
 
	@Override
	public ByteArrayOutputStream downloadFile(String keyName) {
		try {
            S3Object s3object = s3client.getObject(new GetObjectRequest(bucketName, keyName));
            
            InputStream is = s3object.getObjectContent();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int len;
            byte[] buffer = new byte[4096];
            while ((len = is.read(buffer, 0, buffer.length)) != -1) {
                baos.write(buffer, 0, len);
            }
            
            return baos;
		} catch (IOException ioe) {
			logger.error("IOException: " + ioe.getMessage());
        } catch (AmazonServiceException ase) {
        	logger.info("sCaught an AmazonServiceException from GET requests, rejected reasons:");
			logger.info("Error Message:    " + ase.getMessage());
			logger.info("HTTP Status Code: " + ase.getStatusCode());
			logger.info("AWS Error Code:   " + ase.getErrorCode());
			logger.info("Error Type:       " + ase.getErrorType());
			logger.info("Request ID:       " + ase.getRequestId());
			throw ase;
        } catch (AmazonClientException ace) {
        	logger.info("Caught an AmazonClientException: ");
            logger.info("Error Message: " + ace.getMessage());
            throw ace;
        }
		
		return null;
	}
 
	@Override
	public void uploadFile(String keyName, MultipartFile file) {
		try {
			ObjectMetadata metadata = new ObjectMetadata();
			metadata.setContentLength(file.getSize());
			s3client.putObject(bucketName, keyName, file.getInputStream(), metadata);
		} catch(IOException ioe) {
			logger.error("IOException: " + ioe.getMessage());
		} catch (AmazonServiceException ase) {
			logger.info("Caught an AmazonServiceException from PUT requests, rejected reasons:");
			logger.info("Error Message:    " + ase.getMessage());
			logger.info("HTTP Status Code: " + ase.getStatusCode());
			logger.info("AWS Error Code:   " + ase.getErrorCode());
			logger.info("Error Type:       " + ase.getErrorType());
			logger.info("Request ID:       " + ase.getRequestId());
			throw ase;
        } catch (AmazonClientException ace) {
            logger.info("Caught an AmazonClientException: ");
            logger.info("Error Message: " + ace.getMessage());
            throw ace;
        }
	}
}

Implement Upload/Download RestAPIs

– Expose Upload RestAPI in controller UploadFileController.java:


package com.ozenero.s3.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.ozenero.s3.services.S3Services;
 
@RestController
public class UploadFileController {
	
	@Autowired
	S3Services s3Services;
	
    @PostMapping("/api/file/upload")
    public String uploadMultipartFile(@RequestParam("keyname") String keyName, @RequestParam("uploadfile") MultipartFile file) {
		s3Services.uploadFile(keyName, file);
		return "Upload Successfully. -> KeyName = " + keyName;
    }    
}

– Expose Download RestAPI in controller DownloadFileController.java:


package com.ozenero.s3.controller;

import java.io.ByteArrayOutputStream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.ozenero.s3.services.S3Services;
  
@RestController
public class DownloadFileController {
 	
	@Autowired
	S3Services s3Services;
	 	
    /*
     * Download Files
     */
	@GetMapping("/api/file/{keyname}")
	public ResponseEntity downloadFile(@PathVariable String keyname) {
		ByteArrayOutputStream downloadInputStream = s3Services.downloadFile(keyname);
	
		return ResponseEntity.ok()
					.contentType(contentType(keyname))
					.header(HttpHeaders.CONTENT_DISPOSITION,"attachment; filename=\"" + keyname + "\"")
					.body(downloadInputStream.toByteArray());	
	}
	
	private MediaType contentType(String keyname) {
		String[] arr = keyname.split("\\.");
		String type = arr[arr.length-1];
		switch(type) {
			case "txt": return MediaType.TEXT_PLAIN;
			case "png": return MediaType.IMAGE_PNG;
			case "jpg": return MediaType.IMAGE_JPEG;
			default: return MediaType.APPLICATION_OCTET_STREAM;
		}
	}
}

Run & Check results

– Build and Run the SpringBoot project with commandlines {mvn clean install, mvn spring-boot:run}.

-> Upload File:

springboot-rest-api-upload-download-file-image-s3-aws + upload-files

springboot-rest-api-upload-download-file-image-s3-aws + upload-file-on-s3-bucket

-> Download File:

springboot-rest-api-upload-download-file-image-s3-aws + download-files

SourceCode

– In application.properties file, change gkz.aws.access_key_id & gkz.aws.secret_access_key to yours

– Sourcecode ->

SpringRestAPIsS3Amazon

4 thoughts on “Amazon S3 – SpringBoot RestAPIs Upload/Download File/Image to S3”

Leave a Reply

Your email address will not be published. Required fields are marked *