Boot

Spring Boot and AWS S3: Delete file

Welcome readers, in this tutorial, we will show how to delete a file from an AWS S3 bucket using the spring boot framework.

1. Introduction

  • Spring boot is a module that provides rapid application development feature to the spring framework including auto-configuration, standalone-code, and production-ready code
  • It creates applications that are packaged as jar and are directly started using embedded servlet container (such as Tomcat, Jetty or Undertow). Thus, no need to deploy the war files
  • It simplifies the maven configuration by providing the starter template and helps to resolve the dependency conflicts. It automatically identifies the required dependencies and imports them in the application
  • It helps in removing the boilerplate code, extra annotations, and XML configurations
  • It provides a powerful batch processing and manages the rest endpoints
  • It provides an efficient jpa-starter library to effectively connect the application with the relational databases
  • It offers a Microservice architecture and cloud configuration that manages all the application related configuration properties in a centralized manner

1.1 AWS Storage Service

AWS Storage Service or simply known as AWS S3 is an online storage facility for the users. It cheap, easy to set up and the user only pays for what they utilize. It offers,

  • To host static web-content and data or even the dynamic pages
  • Data storage for analytics
  • Backup and archival of data
  • Disaster recovery solutions

1.1.1 S3 Bucket

Amazon S3 Bucket has two primary entities i.e. Object and Bucket, where objects are stored inside the buckets. It provides high availability and durability solutions by replicating the data of one bucket in multiple data centers. Each AWS account offers 100 buckets as free, however, this count can be increased on submitting a request to the support center. Amazon S3 features –

  • Each object in a bucket is given a unique id
  • S3 allows a developer to upload/delete or read an object via the REST API
  • S3 offers two read-after-write and eventual consistency models to ensure that every change command committed to a system should be visible to all the participants
  • Objects stored in a bucket never leave it’s location unless the user transfer it out
  • Objects can be made private or public and rights can be granted to specific users

1.1.2 Setting up AWS S3 bucket and IAM user

If someone needs to go through the process of creating an S3 bucket and attach it to an IAM user, please watch this video.

To start with this tutorial, we are hoping that users at present have their AWS account created and know how to set up an S3 bucket and attach it to an IAM user of their choice.

2. Spring boot and AWS S3: Delete file

Here is a systematic guide for implementing this tutorial.

2.1 Application pre-requisite

To start with this tutorial, I would recommend readers to go through Part 1 of Spring Boot and AWS S3 operations tutorial available at this link. The tutorial will help users to understand the code changes required to start up.

3. Creating a Spring Boot application

Since the Project structure, Maven dependencies, and Configuration level changes remain the same, so we’ll directly jump start with the changes required to delete the file from the S3 bucket.

3.3 Java Classes

Let us write the updated java classes involved in this application.

3.3.1 Service Class

Add the deleteFile(……) method in the AWSS3ServiceImpl.java class to delete the object from the S3 bucket.

AWSS3ServiceImpl.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package org.jcg.springboot.aws.s3.serv;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
 
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.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
 
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.DeleteObjectRequest;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;
import com.amazonaws.util.IOUtils;
 
@Service
public class AWSS3ServiceImpl implements AWSS3Service {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(AWSS3ServiceImpl.class);
 
    @Autowired
    private AmazonS3 amazonS3;
    @Value("${aws.s3.bucket}")
    private String bucketName;
 
    @Override
    // @Async annotation ensures that the method is executed in a different background thread
    // but not consume the main thread.
    @Async
    public void uploadFile(final MultipartFile multipartFile) {
        LOGGER.info("File upload in progress.");
        try {
            final File file = convertMultiPartFileToFile(multipartFile);
            uploadFileToS3Bucket(bucketName, file);
            LOGGER.info("File upload is completed.");
            file.delete();  // To remove the file locally created in the project folder.
        } catch (final AmazonServiceException ex) {
            LOGGER.info("File upload is failed.");
            LOGGER.error("Error= {} while uploading file.", ex.getMessage());
        }
    }
 
    private File convertMultiPartFileToFile(final MultipartFile multipartFile) {
        final File file = new File(multipartFile.getOriginalFilename());
        try (final FileOutputStream outputStream = new FileOutputStream(file)) {
            outputStream.write(multipartFile.getBytes());
        } catch (final IOException ex) {
            LOGGER.error("Error converting the multi-part file to file= ", ex.getMessage());
        }
        return file;
    }
 
    private void uploadFileToS3Bucket(final String bucketName, final File file) {
        final String uniqueFileName = LocalDateTime.now() + "_" + file.getName();
        LOGGER.info("Uploading file with name= " + uniqueFileName);
        final PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, uniqueFileName, file);
        amazonS3.putObject(putObjectRequest);
    }
 
    @Override
    // @Async annotation ensures that the method is executed in a different background thread
    // but not consume the main thread.
    @Async
    public byte[] downloadFile(final String keyName) {
        byte[] content = null;
        LOGGER.info("Downloading an object with key= " + keyName);
        final S3Object s3Object = amazonS3.getObject(bucketName, keyName);
        final S3ObjectInputStream stream = s3Object.getObjectContent();
        try {
            content = IOUtils.toByteArray(stream);
            LOGGER.info("File downloaded successfully.");
            s3Object.close();
        } catch(final IOException ex) {
            LOGGER.info("IO Error Message= " + ex.getMessage());
        }
        return content;
    }
 
    @Override
    // @Async annotation ensures that the method is executed in a different background thread
    // but not consume the main thread.
    @Async
    public void deleteFile(final String keyName) {
        LOGGER.info("Deleting file with name= " + keyName);
        final DeleteObjectRequest deleteObjectRequest = new DeleteObjectRequest(bucketName, keyName);
        amazonS3.deleteObject(deleteObjectRequest);
        LOGGER.info("File deleted successfully.");
    }
}

3.3.2 Controller Class

Add the deleteFile(……) method in the AWSS3Ctrl.java class to delete the file from the S3 bucket and return the response back to the user. This method reads the filename query parameter coming in the DELETE request.

AWSS3Ctrl.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package org.jcg.springboot.aws.s3.ctrl;
 
import org.jcg.springboot.aws.s3.serv.AWSS3Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
 
@RestController
@RequestMapping(value= "/s3")
public class AWSS3Ctrl {
 
    @Autowired
    private AWSS3Service service;
 
    @PostMapping(value= "/upload")
    public ResponseEntity<String> uploadFile(@RequestPart(value= "file") final MultipartFile multipartFile) {
        service.uploadFile(multipartFile);
        final String response = "[" + multipartFile.getOriginalFilename() + "] uploaded successfully.";
        return new ResponseEntity<>(response, HttpStatus.OK);
    }
 
    @GetMapping(value= "/download")
    public ResponseEntity<ByteArrayResource> downloadFile(@RequestParam(value= "fileName") final String keyName) {
        final byte[] data = service.downloadFile(keyName);
        final ByteArrayResource resource = new ByteArrayResource(data);
        return ResponseEntity
                .ok()
                .contentLength(data.length)
                .header("Content-type", "application/octet-stream")
                .header("Content-disposition", "attachment; filename=\"" + keyName + "\"")
                .body(resource);
    }
     
    @DeleteMapping(value= "/delete")
    public ResponseEntity<String> deleteFile(@RequestParam(value= "fileName") final String keyName) {
        service.deleteFile(keyName);
        final String response = "[" + keyName + "] deleted successfully.";
        return new ResponseEntity<>(response, HttpStatus.OK);
    }
}

4. Run the Application

To execute the application, compile the project and right-click on the SpringbootS3tutorial.java class, Run As -> Java Application.

AWS S3 Delete file - Run the Application
Fig. 1: Run the Application

5. Project Demo

Once the application is started successfully, open the Postman tool. Hit the following URL (HTTP DELETE request) to delete the file from the S3 bucket.

http://localhost:9098//s3/delete?fileName=2020-03-26T21:29:41.957_Some text.txt
AWS S3 Delete file - HTTP DELETE request
Fig. 2: HTTP DELETE request

Once the file is deleted successfully from the S3 bucket, the API will return the 200 OK response as shown in Fig. 3.

AWS S3 Delete file - HTTP DELETE response
Fig. 3: HTTP DELETE response

And the users can navigate to the AWS console to validate that the same file is now deleted in the S3 bucket.

Fig. 4: S3 bucket (post file deletion)

That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!

6. Conclusion

In the above sections, developers learned how to delete a file from an S3 bucket via a spring boot application. Developers can download the sample application from the Download section.

7. Download the Project

This was an example of deleting a file from the AWS S3 bucket via a spring boot application.

Download
You can download the full source code of this example here: Spring boot and AWS S3: Delete file

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button