Add Metadata to File Upload S3 Android
Amazon simple storage (Amazon S3) is a service offered past Amazon spider web services that offers scalable, secure, and well performing object storage. This article will become over how to upload files into Amazon S3 using Leap Boot.
Prerequisites
- Some knowledge in Java and Spring Boot.
- Java development kit installed on your figurer.
- Your favourite IDE. I use Intellij community edition which is gratuitous.
Amazon web services account
Before we start creating our application, head over to Amazon console, and create an business relationship. Yous will exist given 12 months of gratis access to diverse Amazon web services that you lot can use to test diverse Amazon services.
Afterward signing upwardly, head over to Amazon console and search for Amazon S3 in the search box provided in the console.
Amazon S3 bucket
After selecting Amazon S3 from the step above, create a new S3 saucepan that we volition use to store the files we will be uploading from our application.
Proper name the bucket as spring-amazon-storage and leave all other settings as default so create the saucepan.
Access and secret keys
Create a new access key from My Security Credentials navigation carte as shown in the paradigm below. Copy the admission and the secret key generated as we volition exist using them to access the bucket from the application we will be creating.
Creating the application
We will be using leap initializr to create our application. Head over to spring initializr and create a new Leap Boot application calculation h2, spring kicking dev tools, spring data jpa and spring spider web as dependencies then generate the projection.
Unzip the downloaded projection and open up it in your favorite IDE.
Calculation Amazon SDK dependency
Amazon SDK makes it possible to collaborate with various Amazon services from our applications. In the pom.xml file add the Amazon SDK dependency as shown below.
<!-- https://mvnrepository.com/antiquity/com.amazonaws/aws-java-sdk --> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> <version>i.11.931</version> </dependency> Project construction
config/ |--- AmazonConfig.java |--- BucketName.java controllers/ |--- TodoController.java domain/ |--- Todo.java repositories/ |--- TodoRepository.java service/ |--- FileStore.java |--- TodoService.java |--- TodoServiceImpl.java SpringAmazonApplication.java Configuration package
In the configuration package, nosotros accept two Java files, one that authenticates with Amazon S3 and the other which contains the bucket proper name.
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.notation.Configuration; @Configuration public class AmazonConfig { @Bean public AmazonS3 s3 () { AWSCredentials awsCredentials = new BasicAWSCredentials( "accessKey" , "secretKey" ); return AmazonS3ClientBuilder . standard () . withRegion ( "ap-south-1" ) . withCredentials ( new AWSStaticCredentialsProvider(awsCredentials)) . build (); } } The AmazonConfig class above is annotated with @Configuration annotation to make it available to the Leap context equally a configuration grade. With the Amazon credentials we got from the Amazon panel before 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( "bound-amazon-storage" ); private final String bucketName; } In the BucketName enum in a higher place nosotros laissez passer in the bucket name that we created in the Amazon console earlier. The bucket will be used to store all of our file uploads.
-
@AllArgsConstructorannotation generates a constructor with thebucketNamevariable in the enum. -
@Getterannotation generates a getter for thebucketNamevariable in the enum.
Domain package
In this package we have the Todo model that represents our Todo in the database.
@Data @AllArgsConstructor @NoArgsConstructor @Builder @Entity public class Todo { @Id @GeneratedValue private Long id; individual String championship; private Cord description; individual String imagePath; private Cord imageFileName; } -
@Informationannotation generatesgetters,setters,toStringandequalsmethods for theTodoclass. -
@AllArgsConstructornote generates a constructor with all the arguments for theTodocourse. -
@NoArgsConstructornotation generates a constructor with no arguments for theTodoclass. -
@Builderannotation creates a builder pattern for theTodograde. -
@Entityannotation makes theTodoclass a database entity. -
@Idnotation marks theidfield as a master fundamental in the database. -
@GeneratedValueannotation makes theidfield auto-increment whenever a newtodois saved into the database.
Repository package
In this bundle, nosotros have the repository grade 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 bundle
@AllArgsConstructor @Service public class FileStore { individual final AmazonS3 amazonS3; public void upload (String path, Cord fileName, Optional<Map<String, 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 eastward) { 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); } take hold of (AmazonServiceException | IOException eastward) { throw new IllegalStateException( "Failed to download the file" , eastward); } } } In the FileStore class above, we have the logic used to upload and download files from Amazon S3.
In the upload method we pass in:
-
pathis the path on the Amazon S3 bucket where the file volition exist stored. -
fileNameis the bodily name of the file being uploaded. Information technology will be used every bit the key when downloading the file from S3. -
optionalMetaDatamap contains the details of the file i.due east file type and file size. -
inputStreamcontains the actual 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 calculation 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, fundamental);downloads the file from the path passed in and with the file name like to the key passed in thegetObjectmethod. -
S3ObjectInputStream objectContent = object.getObjectContent();gets an inputStream from the object returned from Amazon S3. -
IOUtils.toByteArray(objectContent)converts the input stream tobyteArraythat can be sent over Restful APIs.
public interface TodoService { Todo saveTodo (String title, Cord clarification, MultipartFile file); byte [] downloadTodoImage (Long id); List<Todo> getAllTodos (); } The TodoService interface above contains various methods that we will implement to be able to save and become todos.
@Service @AllArgsConstructor public class TodoServiceImpl implements TodoService { private last FileStore fileStore; individual 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" ); } //Bank 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" ); } //get 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 and then relieve Todo in the database Cord path = String. format ( "%southward/%s" , BucketName. TODO_IMAGE . getBucketName (), UUID. randomUUID ()); String fileName = String. format ( "%southward" , file. getOriginalFilename ()); effort { fileStore. upload (path, fileName, Optional. of (metadata), file. getInputStream ()); } grab (IOException e) { throw new IllegalStateException( "Failed to upload file" , due east); } Todo todo = Todo. builder () . description (description) . championship (title) . 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 (); return fileStore. download (todo. getImagePath (), todo. getImageFileName ()); } @Override public Listing<Todo> getAllTodos () { Listing<Todo> todos = new ArrayList<>(); repository. findAll (). forEach (todos::add); render todos; } } In the TodoServiceImpl to a higher place, we provide the implementation for the methods for saving and getting all todos.
Controllers packet
In this bundle, we accept TodoController class 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 ( "championship" ) String championship, @RequestParam ( "description" ) Cord description, @RequestParam ( "file" ) MultipartFile file) { return new ResponseEntity<>(service. saveTodo (title, description, file), HttpStatus. OK ); } @GetMapping (value = "{id}/image/download" ) public byte [] downloadTodoImage ( @PathVariable ( "id" ) Long id) { render service. downloadTodoImage (id); } } Testing our uploads and downloads from the S3 bucket
Determination
Congratulations! At present that you learned how to upload and download files from Amazon S3, go ahead and implement the logic for uploading multiple files to Amazon S3.
Detect 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 "Add Metadata to File Upload S3 Android"
Post a Comment