Desacoplando a camada de domínio de uma aplicação das outras camadas - parte 2
Tags: java, simplesoftwarearchitecture, dynamodb, ddd
Published: 2022-04-19 00:29:10

Ferramentas necessárias:
* [Java SDK](https://www.oracle.com/java/technologies/downloads/)
* [Docker](https://docs.docker.com/desktop/windows/install/#:~:text=%20Install%20Docker%20Desktop%20on%20Windows%20%F0%9F%94%97%20,to%20authorize%20the%20installer%20and%20proceed...%20More%20)
* [Postman](https://www.postman.com/downloads/)
* Ide de sua preferencia
* [Ter concluído a Parte 1](https://dev.to/2020nani/desacoplando-a-camada-de-dominio-de-uma-aplicacao-das-outras-camadas-2b0b)

Vamos agora fazer a transição da nossa aplicação do banco de dados Postgres para DynamoDb, para isso precisamos adicionar as dependências referente ao DynamoDb e retirar as dependências referente ao Postgres em nosso arquivo pom.xml que devera ficar assim.
`pom.xml`
```
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.6</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>ddd</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>ddd</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>com.amazonaws</groupId>
				<artifactId>aws-java-sdk-bom</artifactId>
				<version>1.11.614</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.github.derjust</groupId>
			<artifactId>spring-data-dynamodb</artifactId>
			<version>5.1.0</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>
```
Vamos modificar também nosso arquivo `application.properties` para deixar apenas o endpoint de acesso ao nosso banco de dados DynamoDb.
`application.properties`
```
server.error.include-message=always
aws.amazonDynamoDBEndpoint=http://localhost:8000
```
Rode o seguinte comando em seu terminal CMD para criar um banco de dados AWS/DynamoDb dentro de um container docker.
```docker run -p 8000:8000 amazon/dynamodb-local -jar DynamoDBLocal.jar -inMemory -sharedDb```
Vamos agora fazer a transição do armazenamento da nossa aplicação de Postgres para DynamoDb, para isso só precisaremos alterar nossa classe `UsuarioAbstractRepositoryDB`,mapear nossa tabela dynamoDb na classe `Usuario` e criar uma classe de configuração de acesso ao Aws/DynamoDb.
Dentro do package `infrastructure` crie um pakage `config` e dentro dele um package `dynamodb`, dentro do package dynamodb crie a classe de configuração `DynamoDbConfig`.
`DynamoDbConfig`
```
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.util.TableUtils;
import com.example.ddd.core.usuario.Usuario;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DynamoDbConfig {

    @Value(("${aws.amazonDynamoDBEndpoint}"))
    private String amazonDynamoDBEndpoint;

    @Bean
    public DynamoDBMapper dynamoDBMapper() {
        AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
                .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(amazonDynamoDBEndpoint, "us-west-2"))
                .build();
        DynamoDBMapperConfig mapperConfig = DynamoDBMapperConfig.builder()
                .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER)
                .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT)
                .withTableNameOverride(null)
                .withPaginationLoadingStrategy(DynamoDBMapperConfig.PaginationLoadingStrategy.EAGER_LOADING)
                .build();
        DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(client, mapperConfig);
        init(dynamoDBMapper, client);
        return dynamoDBMapper;
    }
    

    public void init(DynamoDBMapper dynamoDBMapper, AmazonDynamoDB client) {

        CreateTableRequest tableRequest = dynamoDBMapper.generateCreateTableRequest(Usuario.class);
        tableRequest.setProvisionedThroughput(new ProvisionedThroughput(1L, 1L));

        if (TableUtils.createTableIfNotExists(client, tableRequest)) {
            System.out.println("Table created");
        }

    }

}
```
Altere a classe `UsuarioAbstractRepositoryDB` para métodos que irão acessar o dynamoDb e armazenar ou retornar os dados que precisamos.
`UsuarioAbstractRepositoryDB`
```
import java.util.List;

@Repository
public class UsuarioAbstractRepositoryDB {

    private DynamoDBMapper dynamoDBMapper;


    @Autowired
    public UsuarioAbstractRepositoryDB(DynamoDBMapper dynamoDBMapper) {
        this.dynamoDBMapper = dynamoDBMapper;
    }

    public Usuario buscaUsuarioPorId(String usuarioId) {
        return dynamoDBMapper.load(Usuario.class, usuarioId);
    }

   public List<Usuario> buscaUsuarios() {

       final DynamoDBScanExpression paginatedScanListExpression = new DynamoDBScanExpression();
       final PaginatedScanList<Usuario> usuarioList = dynamoDBMapper.scan(Usuario.class, paginatedScanListExpression);
       return usuarioList;
   }

    public String deletaUsuario(String usuarioId){
        Usuario usuario = dynamoDBMapper.load(Usuario.class,usuarioId);
        dynamoDBMapper.delete(usuario);
        return "Usuario deletado com sucesso";
    }

    public Usuario criaUsuario(Usuario usuario) {
        dynamoDBMapper.save(usuario);
        return usuario;
    }

    public Usuario updateUsuario(String usuarioId, Usuario usuario) {

        dynamoDBMapper.save(usuario,
                new DynamoDBSaveExpression()
                        .withExpectedEntry("usuarioId",
                                new ExpectedAttributeValue(
                                        new AttributeValue().withS(usuarioId)
                                )));
        Usuario usuarioAtualizado = buscaUsuarioPorId(usuarioId);
        return usuarioAtualizado;
    }
}
```
Agora so precisamos mapear a criação da nossa entidade usuario dentro do banco de dados dynamoDb, para isso altere a classe `Usuario` da seguinte forma.
`Usuario`
```
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;

@DynamoDBTable(tableName = "usuario")
public class Usuario {

    @DynamoDBHashKey(attributeName = "usuarioId")
    @DynamoDBAutoGeneratedKey
    private String userId;

    @DynamoDBAttribute(attributeName = "name")
    private String name;

    @DynamoDBAttribute(attributeName = "email")
    private String email;

    @DynamoDBAttribute(attributeName = "cpf")
    private String cpf;

    @Deprecated
    public Usuario() {
    }

    public Usuario(String name, String email, String cpf) {
        this.name = name;
        this.email = email;
        this.cpf = cpf;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

    public String getCpf() {
        return cpf;
    }

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

    public void setEmail(String email) {
        this.email = email;
    }

    public void setCpf(String cpf) {
        this.cpf = cpf;
    }
    
}
```
E pronto, transição realizada sem precisar mexer na camada de domínio ou na camada de acesso externo de nossa aplicação, podemos rodar nossa aplicação e testar via `Postman`.

**Usuario criado**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s8565m4nlmdb06e7c5qf.png) 

**Lista Usuario**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3f9gxshakl2071w32d4i.png)
 
**Usuario Armazenado DynamoDB**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swlr1ibypu315zx51zrz.png)

E isso ai galera, essa ultima parte deixarei no meu [github](https://github.com/2020nani/ArtigoDEV.TO) para quem quiser acessar
Deixo aqui também meu [linkedin](https://www.linkedin.com/in/nanialmeida/) para quem quiser me adicionar, grato a todos que leram este artigo e bora aprender galera.