Uploading a File to S3 Java Code
Amazon simple storage (Amazon S3) is a service offered by Amazon web services that offers scalable, secure, and well performing object storage. This article volition become over how to upload files into Amazon S3 using Spring Boot.
Prerequisites
- Some knowledge in Java and Spring Kick.
- Java development kit installed on your figurer.
- Your favourite IDE. I use Intellij customs edition which is free.
Amazon web services account
Before we start creating our application, head over to Amazon panel, and create an account. You will be given 12 months of costless admission to various Amazon web services that you can use to test various Amazon services.
Later signing up, head over to Amazon console and search for Amazon S3 in the search box provided in the console.
Amazon S3 bucket
Later selecting Amazon S3 from the step in a higher place, create a new S3 bucket that nosotros volition use to store the files we will be uploading from our awarding.
Name the bucket equally spring-amazon-storage
and get out all other settings as default then create the saucepan.
Admission and surreptitious keys
Create a new access key from My Security Credentials
navigation menu as shown in the prototype below. Copy the admission and the hugger-mugger primal generated as we will be using them to admission the bucket from the application nosotros will be creating.
Creating the awarding
We will exist using spring initializr to create our application. Head over to spring initializr and create a new Bound Kick application calculation h2
, leap boot dev tools
, spring data jpa
and spring web
as dependencies then generate the project.
Unzip the downloaded project and open information technology in your favorite IDE.
Calculation Amazon SDK dependency
Amazon SDK makes it possible to interact with various Amazon services from our applications. In the pom.xml
file add the Amazon SDK dependency as shown beneath.
<!-- https://mvnrepository.com/antiquity/com.amazonaws/aws-coffee-sdk --> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> <version>one.11.931</version> </dependency>
Project structure
config/ |--- AmazonConfig.java |--- BucketName.java controllers/ |--- TodoController.java domain/ |--- Todo.java repositories/ |--- TodoRepository.java service/ |--- FileStore.java |--- TodoService.java |--- TodoServiceImpl.java SpringAmazonApplication.coffee
Configuration bundle
In the configuration packet, we take two Java files, 1 that authenticates with Amazon S3 and the other which contains the bucket proper noun.
import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public form AmazonConfig { @Edible bean public AmazonS3 s3 () { AWSCredentials awsCredentials = new BasicAWSCredentials( "accessKey" , "secretKey" ); return AmazonS3ClientBuilder . standard () . withRegion ( "ap-due south-1" ) . withCredentials ( new AWSStaticCredentialsProvider(awsCredentials)) . build (); } }
The AmazonConfig
course above is annotated with @Configuration
annotation to brand it available to the Jump context as a configuration class. With the Amazon credentials we got from the Amazon console earlier we will authenticate to S3 using the AmazonS3ClientBuilder
available in the Amazon-SDK that we added to our pom.xml
ealier.
import lombok.AllArgsConstructor; import lombok.Getter; @AllArgsConstructor @Getter public enum BucketName { TODO_IMAGE( "spring-amazon-storage" ); private last Cord bucketName; }
In the BucketName
enum above we laissez passer in the bucket proper noun that nosotros created in the Amazon console earlier. The saucepan will be used to store all of our file uploads.
-
@AllArgsConstructor
annotation generates a constructor with thebucketName
variable in the enum. -
@Getter
annotation generates a getter for thebucketName
variable in the enum.
Domain packet
In this package nosotros have the Todo
model that represents our Todo
in the database.
@Information @AllArgsConstructor @NoArgsConstructor @Builder @Entity public course Todo { @Id @GeneratedValue private Long id; private String title; individual String description; private String imagePath; individual Cord imageFileName; }
-
@Information
annotation generatesgetters
,setters
,toString
andequals
methods for theTodo
class. -
@AllArgsConstructor
notation generates a constructor with all the arguments for theTodo
grade. -
@NoArgsConstructor
annotation generates a constructor with no arguments for theTodo
class. -
@Builder
annotation creates a architect pattern for theTodo
class. -
@Entity
annotation makes theTodo
course a database entity. -
@Id
annotation marks theid
field as a primary key in the database. -
@GeneratedValue
annotation makes theid
field motorcar-increment whenever a newtodo
is saved into the database.
Repository package
In this bundle, we have the repository form that extends the JPA CrudRepository
interface that makes it possible to perform various database queries.
public interface TodoRepository extends CrudRepository<Todo, Long> { Todo findByTitle (String title); }
Service package
@AllArgsConstructor @Service public class FileStore { individual final AmazonS3 amazonS3; public void upload (Cord path, Cord fileName, Optional<Map<Cord, String>> optionalMetaData, InputStream inputStream) { ObjectMetadata objectMetadata = new ObjectMetadata(); optionalMetaData. ifPresent (map -> { if (!map. isEmpty ()) { map. forEach (objectMetadata::addUserMetadata); } }); try { amazonS3. putObject (path, fileName, inputStream, objectMetadata); } catch (AmazonServiceException east) { throw new IllegalStateException( "Failed to upload the file" , e); } } public byte [] download (String path, String key) { try { S3Object object = amazonS3. getObject (path, key); S3ObjectInputStream objectContent = object. getObjectContent (); return IOUtils. toByteArray (objectContent); } catch (AmazonServiceException | IOException due east) { throw new IllegalStateException( "Failed to download the file" , e); } } }
In the FileStore
class to a higher place, we take the logic used to upload and download files from Amazon S3.
In the upload
method nosotros laissez passer in:
-
path
is the path on the Amazon S3 bucket where the file will be stored. -
fileName
is the actual proper noun of the file beingness uploaded. It will be used every bit the fundamental when downloading the file from S3. -
optionalMetaData
map contains the details of the file i.e file blazon and file size. -
inputStream
contains the bodily file that should be saved to Amazon S3.
ObjectMetadata objectMetadata = new ObjectMetadata(); optionalMetaData. ifPresent (map -> { if (!map. isEmpty ()) { map. forEach (objectMetadata::addUserMetadata); } });
The above code block loops through the optionalMetaData
map adding all of the file information to the S3 objectMetaData
.
-
amazonS3.putObject(path, fileName, inputStream, objectMetadata);
saves the file to Amazon S3 bucket.
In the download
method:
-
S3Object object = amazonS3.getObject(path, cardinal);
downloads the file from the path passed in and with the file name like to the key passed in thegetObject
method. -
S3ObjectInputStream objectContent = object.getObjectContent();
gets an inputStream from the object returned from Amazon S3. -
IOUtils.toByteArray(objectContent)
converts the input stream tobyteArray
that can be sent over Restful APIs.
public interface TodoService { Todo saveTodo (Cord title, String description, MultipartFile file); byte [] downloadTodoImage (Long id); Listing<Todo> getAllTodos (); }
The TodoService
interface above contains various methods that we will implement to be able to save and get todos
.
@Service @AllArgsConstructor public class TodoServiceImpl implements TodoService { private final FileStore fileStore; private final TodoRepository repository; @Override public Todo saveTodo (String title, String description, MultipartFile file) { //bank check if the file is empty if (file. isEmpty ()) { throw new IllegalStateException( "Cannot upload empty file" ); } //Check if the file is an image if (!Arrays. asList (IMAGE_PNG. getMimeType (), IMAGE_BMP. getMimeType (), IMAGE_GIF. getMimeType (), IMAGE_JPEG. getMimeType ()). contains (file. getContentType ())) { throw new IllegalStateException( "FIle uploaded is not an image" ); } //become file metadata Map<String, String> metadata = new HashMap<>(); metadata. put ( "Content-Type" , file. getContentType ()); metadata. put ( "Content-Length" , String. valueOf (file. getSize ())); //Save Image in S3 then salvage Todo in the database String path = String. format ( "%south/%s" , BucketName. TODO_IMAGE . getBucketName (), UUID. randomUUID ()); String fileName = String. format ( "%southward" , file. getOriginalFilename ()); try { fileStore. upload (path, fileName, Optional. of (metadata), file. getInputStream ()); } take hold of (IOException e) { throw new IllegalStateException( "Failed to upload file" , east); } Todo todo = Todo. builder () . description (description) . title (championship) . imagePath (path) . imageFileName (fileName) . build (); repository. salvage (todo); return repository. findByTitle (todo. getTitle ()); } @Override public byte [] downloadTodoImage (Long id) { Todo todo = repository. findById (id). go (); render fileStore. download (todo. getImagePath (), todo. getImageFileName ()); } @Override public List<Todo> getAllTodos () { List<Todo> todos = new ArrayList<>(); repository. findAll (). forEach (todos::add); return todos; } }
In the TodoServiceImpl
above, nosotros provide the implementation for the methods for saving and getting all todos
.
Controllers parcel
In this bundle, we have TodoController
course which handles the incoming HTTP requests.
@RestController @RequestMapping ( "api/v1/todo" ) @AllArgsConstructor @CrossOrigin ( "*" ) public class TodoController { TodoService service; @GetMapping public ResponseEntity<List<Todo>> getTodos () { return new ResponseEntity<>(service. getAllTodos (), HttpStatus. OK ); } @PostMapping ( path = "" , consumes = MediaType. MULTIPART_FORM_DATA_VALUE , produces = MediaType. APPLICATION_JSON_VALUE ) public ResponseEntity<Todo> saveTodo ( @RequestParam ( "title" ) Cord title, @RequestParam ( "description" ) String clarification, @RequestParam ( "file" ) MultipartFile file) { return new ResponseEntity<>(service. saveTodo (championship, description, file), HttpStatus. OK ); } @GetMapping (value = "{id}/image/download" ) public byte [] downloadTodoImage ( @PathVariable ( "id" ) Long id) { return service. downloadTodoImage (id); } }
Testing our uploads and downloads from the S3 saucepan
Conclusion
Congratulations! Now that you lot learned how to upload and download files from Amazon S3, go ahead and implement the logic for uploading multiple files to Amazon S3.
Find the source code here.
Happy Coding!
Peer Review Contributions by: Linus Muema
Source: https://www.section.io/engineering-education/spring-boot-amazon-s3/
0 Response to "Uploading a File to S3 Java Code"
Post a Comment