Spring Boot Coded Example with AWS DynamoDB
This article was originally published in https://www.borislam.com on 09 June 2023.
Introduction
In this article, I'll walk through the process of building a Spring Boot MVC web application that interacts with an Amazon DynamoDB table to display a game leaderboard. The application will allow users to view top scores for specific games, retrieve scores for individual users, and display all scores for a particular user. We’ll also explore how to use the AWS SDK for Java to interact with DynamoDB.
Prerequisites
Before diving into the Spring Boot project, ensure the following prerequisites are met:
1. DynamoDB Table Setup:
Create a DynamoDB table named leaderboard with the following schema:
2. AWS CLI Configuration:
Configure the AWS CLI to connect to your AWS account. This setup is necessary for the application to interact with DynamoDB.
3. Spring Boot Project Setup:
Use Spring Initializr to generate a Spring Boot project with the following dependencies:
Project Structure
The project follows the MVC (Model-View-Controller) architecture:
Code Walkthrough
1. pom.xml
The pom.xml file includes the necessary dependencies for the project:
Recommended by LinkedIn
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb-enhanced</artifactId>
</dependency>
</dependencies>
2. LeaderboardWebApplication.java
This is the entry point of the Spring Boot application. Here, we initialize the DynamoDB client:
@SpringBootApplication
public class LeaderboardWebApplication {
public static void main(String[] args) {
SpringApplication.run(LeaderboardWebApplication.class, args);
}
@Bean
public DynamoDbClient dynamoDbClient() {
return DynamoDbClient.builder()
.region(Region.US_EAST_1) // Specify your AWS region
.build();
}
}
3. MyController.java
The controller handles three main endpoints:
@Controller
public class MyController {
@Autowired
private DynamoDbClient dynamoDbClient;
@GetMapping("/")
public String getLeaderboard(@RequestParam(name = "game") String gameParam, Model model) {
// Set up mapping of the partition name with the value
HashMap attrValues =
new HashMap();
attrValues.put(":"+"v1", AttributeValue.builder()
.s(gameParam)
.build());
QueryRequest queryReq = QueryRequest.builder()
.tableName("Leaderboard")
.keyConditionExpression("sk" + " = :" + "v1")
.indexName("sk-top_score-index")
.scanIndexForward(false)
.expressionAttributeValues(attrValues)
.build();
List result= new ArrayList();
model.addAttribute("playerScore", result);
try {
QueryResponse response = dynamoDbClient.query(queryReq);
List> itemList = response.items();
//convert to POJO
for ( Map m: itemList) {
String userId = m.get("user_id") !=null ? m.get("user_id").s() : "";
String game =m.get("sk") !=null ? m.get("sk") .s() :"";
String userName = m.get("player_name") !=null ? m.get("player_name").s(): "";
String location = m.get("location") !=null ? m.get("location").s() : "" ;
Integer topScore = m.get("top_score") !=null ? Integer.parseInt(m.get("top_score").n()) : null ;
String scoreDate = m.get("top_score_date") !=null ? m.get("top_score_date").s() : "" ;
Leaderboard ps = new Leaderboard( userId, game, userName, location, topScore, scoreDate);
result.add(ps);
}
System.out.println(itemList.size());
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
}
return "main";
}
@GetMapping("/getone")
public String getDynamoDBItem(@RequestParam(name = "userId") String userIdParam,
@RequestParam(name = "game") String gameParam, Model model) {
HashMap keyToGet = new HashMap();
keyToGet.put("user_id", AttributeValue.builder()
.s(userIdParam).build());
keyToGet.put("sk", AttributeValue.builder()
.s(gameParam).build());
GetItemRequest request = GetItemRequest.builder()
.key(keyToGet)
.tableName("Leaderboard")
.build();
List result= new ArrayList();
try {
Map m = dynamoDbClient.getItem(request).item();
if (m != null) {
String userId = m.get("user_id") !=null ? m.get("user_id").s() : "";
String game =m.get("sk") !=null ? m.get("sk") .s() :"";
String userName = m.get("player_name") !=null ? m.get("player_name").s(): "";
String location = m.get("location") !=null ? m.get("location").s() : "" ;
Integer topScore = m.get("top_score") !=null ? Integer.parseInt(m.get("top_score").n()) : null ;
String scoreDate = m.get("top_score_date") !=null ? m.get("top_score_date").s() : "" ;
Leaderboard ps = new Leaderboard( userId, game, userName, location, topScore, scoreDate);
result.add(ps);
} else {
System.out.format("No item found with the key");
}
model.addAttribute("playerScore", result);
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
}
return "main";
}
@GetMapping("/playerscore")
public String queryPlayerScore(@RequestParam(name = "userId") String userIdParam, Model model) {
// Set up mapping of the partition name with the value
HashMap attrValues =
new HashMap();
attrValues.put(":"+"v1", AttributeValue.builder()
.s(userIdParam)
.build());
QueryRequest queryReq = QueryRequest.builder()
.tableName("Leaderboard")
.keyConditionExpression("user_id" + " = :" + "v1")
.expressionAttributeValues(attrValues)
.build();
List result= new ArrayList();
try {
QueryResponse response = dynamoDbClient.query(queryReq);
List> itemList = response.items();
//convert to POJO
for ( Map m: itemList) {
String userId = m.get("user_id") !=null ? m.get("user_id").s() : "";
String game =m.get("sk") !=null ? m.get("sk") .s() :"";
String userName = m.get("player_name") !=null ? m.get("player_name").s(): "";
String location = m.get("location") !=null ? m.get("location").s() : "" ;
Integer topScore = m.get("top_score") !=null ? Integer.parseInt(m.get("top_score").n()) : null ;
String scoreDate = m.get("top_score_date") !=null ? m.get("top_score_date").s() : "" ;
Leaderboard ps = new Leaderboard( userId, game, userName, location, topScore, scoreDate);
result.add(ps);
}
System.out.println(itemList.size());
//System.out.println(itemList);
model.addAttribute("playerScore", result);
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
}
return "main";
}
}
4. main.html
The Thymeleaf template displays the leaderboard data:
<html xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>My Leaderboard</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" data-stripped-integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
Game Leaderboard
<br/>
<table class="table table-bordered">
<tr th:each="player : ${playerScore}">
<td th:text="${player.userId}">User Id</td>
<td th:text="${player.game}">Game</td>
<td th:text="${player.topScore}">Top Score</td>
<td th:text="${player.scoreDate}">Top Score Date</td>
</tr>
</table>
</body>
</html>
5. Leaderboard.java
The model class represents the structure of the DynamoDB table:
public class Leaderboard {
private String userId;
private String game;
private String userName;
private String location;
private Integer topScore;
private String scoreDate;
public Leaderboard(String userId, String game, String userName, String location, Integer topScore, String scoreDate) {
this.userId = userId;
this.game = game;
this.userName = userName;
this.location = location;
this.topScore = topScore;
this.scoreDate = scoreDate;
}
// Getters and Setters
}
Running the Application
mvn spring-boot:run
Conclusion
In this article, we’ve built a Spring Boot MVC web application that interacts with DynamoDB to display a game leaderboard. We’ve covered how to set up the DynamoDB table, configure the Spring Boot project, and implement the MVC components. The application demonstrates how to query DynamoDB using the AWS SDK for Java and display the results using Thymeleaf.
You can find the complete source code on GitHub. Happy coding!
Video explain the table design:https://youtu.be/V0GtrBfY7XM
Prerequisite: Install the AWS CLI:https://youtu.be/pE-Q_4YXlR0
Video explain the how to create the table:https://youtu.be/sBZIVLlmpxY