Spring Boot SNS Lambda DynamoDB
Description
In this example we will publish messages to DynamoDB via SNS and Lambda from a Spring Boot application.

The example is based on Spring Boot SNS Lambda and Lambda Person Request DynamoDB.
Prerequisites
- JDK 21
- Maven 3.8.5+
- Spring Boot, version 3+
- LocalStack
- Docker - for running LocalStack
- AWS CLI and awslocal
Run LocalStack
version: '3.8'
services:
localstack:
image: localstack/localstack
container_name: localstack_main
ports:
- "4566-4599:4566-4599"
environment:
- SERVICES=sns,s3,sqs,dynamodb,ses,lambda,logs,stepfunctions
- DYNAMODB_SHARE_DB=1
- DEBUG=1
- DATA_DIR=/tmp/localstack/data
- DOCKER_HOST=unix:///var/run/docker.sock
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
Create Topic
awslocal sns create-topic --name localstack-topic --region us-east-1
Create a Subscription
awslocal sns subscribe \
--region us-east-1 \
--protocol lambda \
--topic-arn arn:aws:sns:us-east-1:000000000000:localstack-topic \
--notification-endpoint arn:aws:lambda:us-east-1:000000000000:function:localstack-lambda-sns
Create DynamoDB Table
awslocal dynamodb create-table \
--table-name person \
--key-schema AttributeName=id,KeyType=HASH \
--attribute-definitions AttributeName=id,AttributeType=N \
--billing-mode PAY_PER_REQUEST
Project Structure
-
Source Code: https://github.com/ZbCiok/zjc-examples/tree/main/aws/aws/dynamodb/spring-boot-sns-lambda-dynamodb
.
├── sns-lambda-dynamodb
│ ├── localstack.cmd
│ ├── pom.xml
│ ├── README.md
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ ├── Person.java
│ │ │ └── SnsRequestHandler.java
│ │ └── resources
│ └── test
│ └── java
└── spring-boot-sns-lambda
├── mvnw
├── mvnw.cmd
├── pom.xml
├── README.md
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── jreact
│ │ └── sns
│ │ ├── PersonRequest.java
│ │ ├── SNSAppConfig.java
│ │ └── SNSApp.java
│ └── resources
│ └── application.properties
└── test
└── java
-
Lambda
-
Source Code: sns-lambda-dynamodb
-
SnsRequestHandler.java
package com.example;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SNSEvent;
import com.fasterxml.jackson.databind.ObjectMapper;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import java.net.URI;
import java.text.ParseException;
import java.util.List;
import com.amazonaws.services.lambda.runtime.events.SNSEvent.SNSRecord;
import lombok.extern.java.Log;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import java.util.Iterator;
@Log
public class SnsRequestHandler implements RequestHandler<SNSEvent, Boolean> {
LambdaLogger logger;
private SNSEvent event;
//----- DynamoDB
private static final String ACCESS_KEY = "test";
private static final String SECRET_KEY = "test";
private static String TABLE_NAME = "person";
private static AwsCredentialsProvider credentials = StaticCredentialsProvider.create(
AwsBasicCredentials.create(ACCESS_KEY, SECRET_KEY));
private static Region region = Region.US_EAST_1;
private static DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
.region(region)
.credentialsProvider(credentials)
.endpointOverride(URI.create("https://localhost.localstack.cloud:4566"))
.build();
// -----
@Override
public Boolean handleRequest(SNSEvent event, Context context) {
log.info(">>> start handleRequest...");
logger = context.getLogger();
List<SNSRecord> records = event.getRecords();
if (!records.isEmpty()) {
Iterator<SNSRecord> recordsIter = records.iterator();
while (recordsIter.hasNext()) {
processRecord(recordsIter.next());
}
}
return Boolean.TRUE;
}
public void processRecord(SNSRecord record) {
try {
String message = record.getSNS().getMessage();
logger.log(">>> message: " + message);
//--- message to DynamoDB
ObjectMapper objectMapper = new ObjectMapper();
Person person = objectMapper.readValue(message, Person.class);
log.info("JSON to POJO >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> " + person.getFirstName());
String personId = "000000001";
person.setId(Integer.parseInt(personId));
addEntryToDynamoDB(person);
//---
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void addEntryToDynamoDB(Person person) throws ParseException {
try {
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(dynamoDbClient)
.build();
// use the enhanced client to interact with the table
DynamoDbTable<Person> table = enhancedClient.table(TABLE_NAME,
TableSchema.fromBean(Person.class));
table.putItem(person);
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Add Entry successfully");
} catch (DynamoDbException exception) {
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Add Entry an error occurred: " + exception.getMessage());
}
}
} -
Create Lambda Function
awslocal lambda create-function \
--region us-east-1 \
--function-name localstack-lambda-sns \
--runtime java21 \
--zip-file fileb://sns-trigger-lambda-0.0.1.jar \
--handler com.example.SnsRequestHandler \
--role arn:aws:iam::000000000000:role/example-lambda-noop-role \
--timeout 120
-
-
Spring-Boot to SNS Lambda
-
Source Code: spring-boot-sns-lambda
-
Running
mvn clean package
mvn spring-boot:run
//...
2024-10-10T19:12:44.688+02:00 INFO 236375 --- [ main] com.jreact.sns.SNSApp : Started SNSApp in 0.553 seconds (process running for 0.674)
2024-10-10T19:12:44.692+02:00 INFO 236375 --- [ main] com.jreact.sns.SNSApp : snsTopicARN: arn:aws:sns:us-east-1:000000000000:localstack-topic
2024-10-10T19:12:44.692+02:00 INFO 236375 --- [ main] com.jreact.sns.SNSApp : Publishing SNS message: {"id":0,"firstName":"John","lastName":"Doe","age":26,"address":"Address01"}
2024-10-10T19:12:44.793+02:00 INFO 236375 --- [ main] com.jreact.sns.SNSApp : SNS Message ID: 1ffa52b9-3f36-4b84-a296-137e6ad4f244
2024-10-10T19:12:44.794+02:00 INFO 236375 --- [ main] com.jreact.sns.SNSApp : snsTopicARN: arn:aws:sns:us-east-1:000000000000:localstack-topic
2024-10-10T19:12:44.794+02:00 INFO 236375 --- [ main] com.jreact.sns.SNSApp : Publishing SNS message: {"id":0,"firstName":"Jack","lastName":"Smith","age":30,"address":"Address02"}
2024-10-10T19:12:44.799+02:00 INFO 236375 --- [ main] com.jreact.sns.SNSApp : SNS Message ID: 951c11fb-af8b-4191-91ce-2927491ceece
//...
-
Output
-
Docker Log
localstack_main | 2024-10-10T14:02:12.500 DEBUG --- [ns:$LATEST_0] l.s.l.i.version_manager : [localstack-lambda-sns-6a0ec8a6-756a-4de7-8b66-b11b5bd4a7c4] INFO: >>> start handleRequest...
localstack_main | 2024-10-10T14:02:12.500 DEBUG --- [ns:$LATEST_0] l.s.l.i.version_manager : [localstack-lambda-sns-6a0ec8a6-756a-4de7-8b66-b11b5bd4a7c4] >>> message: {"id":0,"firstName":"John","lastName":"Doe","age":26,"address":"Address01"}Oct 10, 2024 2:02:12 PM com.example.SnsRequestHandler processRecord
localstack_main | 2024-10-10T14:02:12.500 DEBUG --- [ns:$LATEST_0] l.s.l.i.version_manager : [localstack-lambda-sns-6a0ec8a6-756a-4de7-8b66-b11b5bd4a7c4] INFO: JSON to POJO >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> John
localstack_main | 2024-10-10T14:02:12.500 DEBUG --- [ns:$LATEST_0] l.s.l.i.version_manager : [localstack-lambda-sns-6a0ec8a6-756a-4de7-8b66-b11b5bd4a7c4] Oct 10, 2024 2:02:12 PM com.example.SnsRequestHandler addEntryToDynamoDB
localstack_main | 2024-10-10T14:02:12.500 DEBUG --- [ns:$LATEST_0] l.s.l.i.version_manager : [localstack-lambda-sns-6a0ec8a6-756a-4de7-8b66-b11b5bd4a7c4] INFO: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Add Entry successfully -
DynamoDB table:
awslocal dynamodb query \
--table-name person \
--key-condition-expression "id = :id" \
--expression-attribute-values '{":id":{"N":"000000001"}}'{
"Items": [
{
"firstName": {
"S": "John"
},
"lastName": {
"S": "Doe"
},
"address": {
"S": "Address01"
},
"id": {
"N": "1"
},
"age": {
"N": "26"
}
}
],
"Count": 1,
"ScannedCount": 1,
"ConsumedCapacity": null
}
📄️ ddb-create-table-example-01
Description
📄️ ddb-write-read-example-01
Description
📄️ ddb-delete-table-example-01
Description
📄️ ddb-enh-client-spring-boot-1
We will describe two ways for accessing DynamoDB from Spring applications:
📄️ ddb-spring-data-1
We will describe two ways for accessing DynamoDB from Spring applications:
📄️ Spring Boot SNS Lambda DynamoDB
Description