Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the foxiz-core domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/posttrau/public_html/mdtWordpress/wp-includes/functions.php on line 6114
Upload to AWS S3 bucket from Java Spring Boot app - My Day To-Do

In this post, you will see code samples for how to upload a file to AWS S3 bucket from a Java Spring Boot app. The code you will see here is from one of my open-source repositories on Github, called document-sharing.

Problem

Let’s say you are building a document sharing app where you allow your users to upload the file to a public cloud solution. Now, let’s say you are building the API for your app with Spring Boot and you are using AWS S3 as your public cloud solution. How would you do that? This blog post contains the code that can help you achieve that.

Solution

First make sure you have added the following dependency to the AWS SDK in your repo,

  <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>bom</artifactId>
      <version>${aws.java.sdk.version}</version>
      <type>pom</type>
      <scope>import</scope>
  </dependency>

Then you can start by adding an endpoint in the controller of your app

    @RequestMapping("/upload")
    public ResponseEntity<ServiceResponse> handleFileUpload(@RequestParam("file") MultipartFile file,
                                                            @RequestParam("userId") String userId)
            throws IOException {
        InputStream is = file.getInputStream();
        String filename = file.getOriginalFilename();
        log.info("Request to upload file = " + filename);
        ServiceResponse response = storageService.uploadFile(file, userId);
        return new ResponseEntity<>(response, HttpStatus.valueOf(response.getStatus()));
    }

As you can see, your controller calls the uploadFile method from the StorageService, the code for which is below

 /**
     * 1. Get the filename along with userid
     * 2. Save all that info in the Document class
     * 3. Save the Document in the DocumentRepositoryImpl
     * 4. Move on to uploading the actual file to S3 via S3Repository
     */
    public ServiceResponse uploadFile(MultipartFile file, String userId) throws IOException {

        DocumentMetadataUploadRequest request = new DocumentMetadataUploadRequest();
        request.setName(file.getOriginalFilename());
        request.setAssetType("DOCUMENT");
        request.setUserId(userId);
        log.info("Set the documentMetaUploadRequest obje3ct");
        // ignore the part of documentService.saveDocumentMetadata for now
        ServiceResponse metadataUploadResp = documentService.saveDocumentMetadata(request);
        if (metadataUploadResp.getStatus() > 299) {
            return ServiceResponse.builder()
                    .message("Something went wrong, please try again later")
                    .status(HttpStatus.INTERNAL_SERVER_ERROR.value())
                    .build();
        }
        String filename = userId + "/" + file.getOriginalFilename();
        log.info(filename);
        return s3Repository.putS3Object(convertMultipartFile(file), filename);
    }

Source code for the DocumentMetadataUploadRequest is below,

package com.mydaytodo.sfa.asset.model;

import com.amazonaws.util.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
public class DocumentMetadataUploadRequest {

    private String name;
    private String path;
    private String assetType;
    private String id;
    private String userId;

    /**
     * @param uploadRequest
     * @return
     */
    public static Document convertRequest(DocumentMetadataUploadRequest uploadRequest) {
        return Document.builder()
                .keyStorePath(uploadRequest.getPath())
                .assetType(uploadRequest.getAssetType())
                .name(uploadRequest.getName())
                .id(StringUtils.isNullOrEmpty(uploadRequest.getId())? null: uploadRequest.getId())
                .userId(uploadRequest.getUserId())
                .build();
    }
}

Upload to AWS S3 bucket from Java Spring Boot

As you can see, this in-turn calls the putS3Object from the S3Repository class, the code for which is below,

    public ServiceResponse putS3Object(File file,
                                       String assetKey) throws IOException {
        log.info("About to upload a file to S3");

        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(awsConfig.getS3UploadBucketName()
                    , assetKey, file);

            PutObjectResult result = awsConfig.s3Client().putObject(putObjectRequest);
            log.info("Finished uploading..........");
            log.info(awsConfig.getS3UploadBucketName());
            return ServiceResponse.builder()
                    .data(null)
                    .message(result.getMetadata().toString())
                    .status(HttpStatus.CREATED.value())
                    .build();
        } catch (Exception e) {
            return ServiceResponse.builder()
                    .data(null)
                    .message(e.getMessage())
                    .status(HttpStatus.INTERNAL_SERVER_ERROR.value())
                    .build();
        }
    }

In case you are curious about the ServiceResponse class, it looks something like this

The idea of the ServiceResponse class is to provide a template for how the API responds to requests,

package com.mydaytodo.sfa.asset.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ServiceResponse {
    private Integer status;
    private Object data;
    private String message = "";
}

Conclusion

Hope you found this blogpost useful, and you can find the full source code for this entire app which includes the code for the dependencies can be found here on Github.

If you have any questions on this, feel free to leave a comment on this post or send me an email directly.

If you find any of my posts useful and want to support me, you can buy me a coffee 🙂

https://www.buymeacoffee.com/bhumansoni

While you are here, maybe try one of my apps for the iPhone.

Products – My Day To-Do (mydaytodo.com)

Here are some of my other bloposts on Java

How to build a full stack Spring boot API with ReactJS frontend – My Day To-Do (mydaytodo.com)

How to call REST API with WebClient – My Day To-Do (mydaytodo.com)

How to build a jokes client in Java Spring Boot with RestTemplate – My Day To-Do (mydaytodo.com)

Have a read of some of my other posts on AWS

Deploy NodeJS, Typescript app on AWS Elastic beanstalk – (mydaytodo.com)

How to deploy spring boot app to AWS & serve via https – My Day To-Do (mydaytodo.com)


3 Comments

How to build a blog engine with React & Spring Boot - Part 1 - My Day To-Do · September 21, 2024 at 12:39 am

[…] Upload to AWS S3 bucket from Java Spring Boot app – My Day To-Do (mydaytodo.com) […]

How to build a blog engine with React & Spring Boot – Part 3 CI/CD pipeline · October 7, 2024 at 6:27 am

[…] Upload to AWS S3 bucket from Java Spring Boot app – My Day To-Do (mydaytodo.com) […]

'Cron expression must consist of 6 fields (found 5 in */45 * * * *)' - My Day To-Do · October 7, 2024 at 6:28 am

[…] Upload to AWS S3 bucket from Java Spring Boot app – My Day To-Do (mydaytodo.com) […]

Leave a Reply

Avatar placeholder
Verified by MonsterInsights