AWS Open Source Blog

Getting started with Spring Boot on AWS: Part 1

This is a guest post from Björn Wilmsmann, Philip Riecks, and Tom Hombergs, authors of the upcoming book Stratospheric: From Zero to Production with Spring Boot and AWS.

Spring Boot is the leading framework for building applications in the Java Virtual Machine (JVM) ecosystem. In a nutshell, open source Spring Boot adds auto-configuration on top of the Spring framework by following convention over configuration. In this two-part tutorial, we’ll demonstrate how easy it is to get started with Spring Boot and Amazon Web Services (AWS) using Spring Cloud for AWS.

Introduction to Spring Cloud for AWS

At its core, the Spring framework enables Java developers (or those using any other JVM language, such as Kotlin) to write modern enterprise applications with ease by providing features like an infrastructure as code (IoC) container; an event framework; a Model, View, Controller (MVC) framework; common data access; and many more.

Spring Cloud for AWS is a sub-project of Spring supporting rapid development for cloud-native applications. When it comes to deploying applications, integration with the cloud provider is key. As AWS provides a Java SDK for connecting to services, there is some general bootstrapping involved that you need for each project: instantiating the AWS client with the correct region and credentials. Furthermore, you might not always want to work with the “low-level” API of the AWS clients but prefer integration with your tried-and-true development techniques: auto-configuration with convention over configuration.

Spring Cloud for AWS comes into play as an integrator of AWS services. In this tutorial, we’ll develop a demo application that integrates with the core services Amazon Simple Storage Service (Amazon S3) and Amazon Simple Queue Service (Amazon SQS). In part 1, we’ll show how to display content of an S3 bucket with Thymeleaf, and in part 2, we’ll cover subscribing to an SQS queue and externalizing the configuration of our application using the Parameter Store of AWS Systems Manager.

Prerequisites

As a prerequisite, you should be familiar with Java and have basic experience with Spring Boot. A general understanding of Amazon S3 and Amazon SQS is a plus.

On the AWS infrastructure side, we need the following: an S3 bucket with publicly accessible content and a notification configuration to send events on each file upload to a SQS queue that our application is subscribed to.

 

Diagram showing the infrastructure side of the S3 bucket, SQS queue, and Spring Boot application.

 

You can find the corresponding AWS CloudFormation setup on GitHub.

Setting up Spring Cloud for AWS

dependencies {
   implementation 'org.springframework.boot:spring-boot-starter-web'
   implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
   implementation 'org.springframework.cloud:spring-cloud-starter-aws'
   implementation 'org.springframework.cloud:spring-cloud-starter-aws-messaging'
   implementation 'org.springframework.cloud:spring-cloud-starter-aws-parameter-store-config'
}

The full build.gradle can be found on GitHub.

First, we need to configure the access to AWS. The AWS SDK for Java already offers several solutions for this, such as, using environment variables, a property file or loading them from the Amazon Elastic Compute Cloud (Amazon EC2) Instance Metadata Service.

Spring Cloud for AWS lets us configure the credentials the “Spring Boot way.” Therefore, we can store the credentials inside our application.yml by defining both cloud.aws.credentials.secret-key and cloud.aws.credentials.access-key:

cloud:
 aws:
   credentials:
     access-key: KEY
     secret-key: SECRET

Because we don’t want to store the credentials in plain text inside our application.yml, we can externalize them and pass them via command-line arguments or environment variable. For this demo, we’ll be using a mixed approach and define the AWS profile inside the application.yml and store the credentials for this profile inside ~/.aws/credentials:

cloud:
 aws:
   credentials:
     profile-name: stratospheric

Content of ~/.aws/credentials:

[stratospheric]
aws_access_key_id=KEY
aws_secret_access_key=SECRET

What’s left is to configure the AWS region. Spring Cloud for AWS can automatically detect this based on your environment or stack once you enable the Spring Boot property cloud.aws.region.auto.

You can also set the region in a static fashion for your application:

cloud:
 aws:
   region:
     static: eu-central-1
     auto: false

Feature 1: Displaying content of a S3 Bucket with Thymeleaf

For the first feature of our demo application, we want to display the content of a predefined S3 bucket.

 

Screenshot showing the Simple S3 File Viewer within Spring Boot.

 

Spring Cloud for AWS configures the AmazonS3Client for us out-of-the-box (using the correct credentials and region). Hence, we can inject it into our DashboardController and start using it:

@Controller
public class DashboardController {

   private final String bucketName;
   private final AmazonS3Client amazonS3Client;

   private String bucketLocation;

   public DashboardController(
           @Value("${custom.bucket-name}") String bucketName,
           AmazonS3Client amazonS3Client) {
       this.bucketName = bucketName;
       this.amazonS3Client = amazonS3Client;
   }

   @PostConstruct
   public void postConstruct() {
       this.bucketLocation = String.format("https://%s.s3.%s.amazonaws.com",
               bucketName, this.amazonS3Client.getBucketLocation(bucketName));
   }

}

Apart from injecting the AmazonS3Client, we look up the property value (custom.bucket-name) of the S3 bucket for which we want to display the content.

Using @PostConstruct, because we want our Java constructor to be free of any side effects, we fetch the location of our bucket. We need this bucketLocation to construct the download links for the files later on.

For our Thymeleaf view, we are using Spring MVC to expose a controller endpoint that serves our view. As we render this view on the server side, we can pass data as part of the model to our view:

 @GetMapping("/")
public ModelAndView getDashboardView() {
   ModelAndView modelAndView = new ModelAndView("dashboard");
   modelAndView.addObject("message", "Spring Boot with AWS");
   modelAndView.addObject("bucketName", bucketName);
   modelAndView.addObject("bucketLocation", bucketLocation);
   modelAndView.addObject("availableFiles", amazonS3Client.listObjects(bucketName).getObjectSummaries());
   return modelAndView;
}

We can then access the model inside the view, to render a HTML table with a row for each file in the S3 bucket:

<div class="container">
   <h1 style="text-align: center; margin-top: 10px" th:text="'Welcome to ' + ${message} + '?'"></h1>
   <h3>Simple S3 File Viewer </h3>
   <p>These are the available files inside your S3 Bucket: <strong>[[${bucketName}]]</strong></p>
   <table class="table">
       <thead>
       <tr>
           <th scope="col"><i class="fas fa-file"></i></th>
           <th scope="col">Name</th>
           <th scope="col">Size</th>
           <th scope="col">Last modified</th>
           <th scope="col">Actions</th>
       </tr>
       </thead>
       <tr th:each="file, iteration : ${availableFiles}">
           <td scope="row">[[${iteration.count}]]</td>
           <td>[[${file.key}]]</td>
           <td>[[${file.size}]] Bytes</td>
           <td>[[${#dates.format(file.lastModified, 'd. MMM. yyyy HH:mm:ss Z')}]]</td>
           <td>
               <a download target="_blank" th:href="${bucketLocation} + '/' + ${file.key}">
                   <i class="fas fa-download"></i> Download
               </a>
           </td>
       </tr>
   </table>
</div>

We can now access the Simple S3 File Viewer, after starting our application with ./gradlew bootRun, at http://localhost:8080/.

In part 1 of this tutorial, we provided a brief introduction to Spring Cloud for AWS and began developing a demo application that integrates with core Amazon services. In part 2, we’ll continue our demonstration by incorporating additional features, including subscribing to an SQS queue and externalizing the application configuration.

Feature image via Pixabay.

 

Björn Wilmsmann width=”150″ height=”150″ />

Björn Wilmsmann

Björn Wilmsmann is an independent IT consultant who helps companies transform their business into a digital business. A longtime software entrepreneur, he’s interested in web apps and SaaS products. He designs and develops business solutions and enterprise applications for his clients. Apart from helping companies in matters of software quality and improving the availability of and access to information through APIs, Björn provides hands-on training in technologies such as Angular and Spring Boot.

Philip Riecks width=”150″ height=”150″ />

Philip Riecks

Under the slogan Testing Java Applications Made Simple, Philip provides recipes and tips & tricks to accelerate your testing success on both his blog and on YouTube. He is an independent IT consultant from Berlin and is working with Java, Kotlin, Spring Boot, and AWS on a daily basis.

Tom Hombergs width=”150″ height=”150″ />

Tom Hombergs

Tom is a senior software engineer at Atlassian in Sydney, working with AWS and Spring Boot at scale. He is running the successful software development blog reflectoring.io, regularly writing about Java, Spring, and AWS with the goal of explaining not only the “how” but the “why” of things. Tom is the author of Get Your Hands Dirty on Clean Architecture, which explores how to implement a hexagonal architecture with Spring Boot.

The content and opinions in this post are those of the third-party author and AWS is not responsible for the content or accuracy of this post.

Ricardo Sueiras

Ricardo Sueiras

Cloud Evangelist at AWS. Enjoy most things where technology, innovation and culture collide into sometimes brilliant outcomes. Passionate about diversity and education and helping to inspire the next generation of builders and inventors with Open Source.