CODE WITH SIBIN

Solving Real Problems with Real Code


Spring Boot with AWS DynamoDB Integration (CRUD)

This guide shows how to integrate AWS DynamoDB with Spring Boot using Spring Cloud AWS starter and implement CRUD operations.

Setup

1. Add Dependencies

<dependency>
    <groupId>io.awspring.cloud</groupId>
    <artifactId>spring-cloud-aws-starter-dynamodb</artifactId>
    <version>3.3.0</version>
</dependency>

<!-- Also include Spring Boot Starter Web if building a web app -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. Configure AWS Credentials

Add to application.properties or application.yml:

# AWS configuration
spring.cloud.aws.credentials.access-key=YOUR_ACCESS_KEY
spring.cloud.aws.credentials.secret-key=YOUR_SECRET_KEY
spring.cloud.aws.region.static=us-east-1

# Optional - if you want to use local DynamoDB for testing
spring.cloud.aws.dynamodb.endpoint=http://localhost:8000

Entity Class

Create a model class with DynamoDB annotations:

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;

@DynamoDbBean
public class Product {
    private String id;
    private String name;
    private Double price;
    private Integer stock;

    @DynamoDbPartitionKey
    public String getId() {
        return id;
    }

    // Standard getters and setters
    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }
}

Repository Layer

Create a repository class to handle DynamoDB operations:

import org.springframework.stereotype.Repository;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;

import java.util.List;
import java.util.stream.Collectors;

@Repository
public class ProductRepository {
    
    private final DynamoDbEnhancedClient enhancedClient;
    private final DynamoDbTable<Product> productTable;

    public ProductRepository(DynamoDbEnhancedClient enhancedClient) {
        this.enhancedClient = enhancedClient;
        this.productTable = enhancedClient.table("Product", TableSchema.fromBean(Product.class));
    }

    public Product save(Product product) {
        productTable.putItem(product);
        return product;
    }

    public Product findById(String id) {
        Key key = Key.builder().partitionValue(id).build();
        return productTable.getItem(key);
    }

    public List<Product> findAll() {
        return productTable.scan().items().stream().collect(Collectors.toList());
    }

    public Product update(Product product) {
        return productTable.updateItem(product);
    }

    public void deleteById(String id) {
        Key key = Key.builder().partitionValue(id).build();
        productTable.deleteItem(key);
    }
}

Service Layer

import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductService {
    
    private final ProductRepository productRepository;

    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public Product createProduct(Product product) {
        return productRepository.save(product);
    }

    public Product getProduct(String id) {
        return productRepository.findById(id);
    }

    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }

    public Product updateProduct(Product product) {
        return productRepository.update(product);
    }

    public void deleteProduct(String id) {
        productRepository.deleteById(id);
    }
}

Controller Layer

import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/products")
public class ProductController {
    
    private final ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @PostMapping
    public Product createProduct(@RequestBody Product product) {
        return productService.createProduct(product);
    }

    @GetMapping("/{id}")
    public Product getProduct(@PathVariable String id) {
        return productService.getProduct(id);
    }

    @GetMapping
    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }

    @PutMapping("/{id}")
    public Product updateProduct(@PathVariable String id, @RequestBody Product product) {
        product.setId(id);
        return productService.updateProduct(product);
    }

    @DeleteMapping("/{id}")
    public void deleteProduct(@PathVariable String id) {
        productService.deleteProduct(id);
    }
}

Main Application Class

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DynamoDbApplication {
    public static void main(String[] args) {
        SpringApplication.run(DynamoDbApplication.class, args);
    }
}

Additional Configuration (Optional)

If you need to customize the DynamoDB client:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;

@Configuration
public class DynamoDbConfig {
    
    @Bean
    public DynamoDbClient dynamoDbClient() {
        return DynamoDbClient.builder()
                .credentialsProvider(StaticCredentialsProvider.create(
                        AwsBasicCredentials.create("accessKey", "secretKey")))
                .region(Region.US_EAST_1)
                .build();
    }

    @Bean
    public DynamoDbEnhancedClient dynamoDbEnhancedClient(DynamoDbClient dynamoDbClient) {
        return DynamoDbEnhancedClient.builder()
                .dynamoDbClient(dynamoDbClient)
                .build();
    }
}

Testing with Local DynamoDB

For local development, you can use DynamoDB Local:

  1. Download DynamoDB Local from AWS
  2. Run it: java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
  3. Configure your application to use the local endpoint:
spring.cloud.aws.dynamodb.endpoint=http://localhost:8000

Creating Tables Programmatically

You can create tables at startup:

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;

@Component
public class DynamoDbInitializer implements CommandLineRunner {
    
    private final DynamoDbEnhancedClient enhancedClient;

    public DynamoDbInitializer(DynamoDbEnhancedClient enhancedClient) {
        this.enhancedClient = enhancedClient;
    }

    @Override
    public void run(String... args) throws Exception {
        DynamoDbTable<Product> productTable = enhancedClient.table("Product", 
            TableSchema.fromBean(Product.class));
        
        try {
            productTable.createTable(builder -> builder
                .provisionedThroughput(ProvisionedThroughput.builder()
                    .readCapacityUnits(10L)
                    .writeCapacityUnits(10L)
                    .build()));
        } catch (Exception e) {
            System.out.println("Table already exists");
        }
    }
}

This setup provides a complete Spring Boot application with CRUD operations for DynamoDB using Spring Cloud AWS.

Leave a Reply

Your email address will not be published. Required fields are marked *