Skip to content

Commit

Permalink
Merge pull request #21 from diegosneves/develop
Browse files Browse the repository at this point in the history
Release/1.0.1 🔖
  • Loading branch information
diegosneves authored Mar 10, 2024
2 parents 3b9b4e6 + 0160c71 commit 97308db
Show file tree
Hide file tree
Showing 27 changed files with 515 additions and 112 deletions.
272 changes: 161 additions & 111 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Arquitetura Hexagonal
# Arquitetura Hexagonal
[![CI Develop](https://github.com/diegosneves/hexagonal-architecture/actions/workflows/ci-develop.yaml/badge.svg)](https://github.com/diegosneves/hexagonal-architecture/actions/workflows/ci-develop.yaml)
[![wakatime](https://wakatime.com/badge/user/018bea20-dbbc-48e2-b101-5415903acf5a/project/018d6c68-6a0d-455d-b172-3016d1867673.svg)](https://wakatime.com/@diegosneves)

Conhecida também como **Ports and Adapters**, a Arquitetura Hexagonal é um padrão de design arquitetural focado em
desenvolver aplicações de maneira que não dependam de tecnologias específicas usadas em camadas de interface de usuário
Expand All @@ -14,13 +16,170 @@ Essa estrutura permite que a aplicação seja mais mantida, testada e potenciali
na interface de usuário ou na persistência de dados afetem minimamente a lógica de negócio central.

---
# Como Configurar e Executar o Projeto na Sua IDE

Este projeto utiliza o padrão `REST` com Spring e `Java puro`. Aqui estão as etapas para configurá-lo e executá-lo na sua IDE:

## Pré-requisitos

1. **Java:** Este projeto é baseado em Java, então, você precisará ter ele instalado no seu sistema.

2. **IDE compatível:** Você vai precisar de uma IDE compatível com Java e Spring, como o IntelliJ IDEA ou o Eclipse.

## Configuração do Projeto

1. Clone o projeto do repositório GitHub para a sua máquina local usando o seguinte comando no terminal:

```shell
git clone git@github.com:diegosneves/hexagonal-architecture.git
```

2. Abra a sua IDE de escolha e importe o projeto clonado. Geralmente, isso pode ser realizado selecionando `File -> Open` e navegando até o diretório do projeto.

3. Certifique-se de que sua IDE reconheceu corretamente o projeto como um projeto `Maven` e que todas as dependências necessárias foram baixadas corretamente.

## Execução do Projeto com Java puro

O projeto utiliza Spring Boot, o que simplifica a sua execução. No pacote `CLI`, você irá encontrar o ponto de entrada para o projeto. Aqui estão as etapas para rodá-lo:

1. Navegue até o diretório `src/main/java/diegosneves/github/hexagonal/adapters/` no pacote `CLI`.

2. Procure pela classe `Application.java` com o método `main()`. Esta é a classe principal que inicia a aplicação.
3. Clique com o botão direito na classe e selecione a opção `Run` para executar o projeto.
#### CLI
```mermaid
classDiagram
direction BT
class Application {
+ Application()
+ main(String[]) void
}
class Entity~T~ {
<<Interface>>
+ serialize() String
+ deserialize(String[]) T
}
class Menu {
+ Menu()
- ProductEntityService productEntityService
- String MENU_DIVIDER
- String NEW_LINE
- String SINGLE_OPTION
- String MENU_MESSAGE
- String MENU_OPTION_SEPARATOR
- int MENU_DIVIDER_SIZE
- String TOTAL_OPTIONS
+ displayMenu() void
- optionBuilder(Scanner, String[]) int
}
class ProductEntity {
+ ProductEntity(String, String, ProductStatus, Double)
+ ProductEntity()
- String id
+ String FIELD_SEPARATOR
- ProductStatus status
- String productName
- Double productPrice
+ serialize() String
+ deserialize(String[]) ProductEntity
+ toString() String
+ getProductPrice() Double
+ getStatus() ProductStatus
+ getId() String
+ getProductName() String
}
class ProductEntityDTO {
+ ProductEntityDTO(String, String, ProductStatus, Double)
+ ProductEntityDTO()
- String id
- String productName
- Double productPrice
- ProductStatus status
+ getStatus() ProductStatus
+ getId() String
+ getProductPrice() Double
+ getProductName() String
+ toString() String
}
class ProductEntityRepository {
<<Interface>>
}
class ProductEntityRepositoryImpl {
+ ProductEntityRepositoryImpl()
- String FILE_PATH
+ save(ProductContract) ProductContract
+ get(String) ProductContract
}
class ProductEntityService {
<<Interface>>
+ get(String) ProductEntityDTO
+ enable(String) ProductEntityDTO
+ create(String, Double) ProductEntityDTO
+ disable(String) ProductEntityDTO
}
class ProductServiceImpl {
+ ProductServiceImpl()
- ProductEntityRepository repository
+ disable(String) ProductEntityDTO
+ create(String, Double) ProductEntityDTO
+ get(String) ProductEntityDTO
+ enable(String) ProductEntityDTO
}
class QuestionHandler {
<<enumeration>>
+ QuestionHandler()
+ INTEGER
+ DOUBLE
- String QUESTION_FORMAT
+ STRING
+ response(Scanner, String) Object
}
Application ..> Menu
Menu ..> ProductEntityDTO
Menu "1" *--> "productEntityService 1" ProductEntityService
Menu ..> ProductServiceImpl
Menu ..> QuestionHandler
ProductEntity ..> Entity~T~
ProductEntityRepositoryImpl ..> ProductEntity
ProductEntityRepositoryImpl ..> ProductEntityRepository
ProductEntityService ..> ProductEntityDTO
ProductServiceImpl ..> ProductEntity
ProductServiceImpl ..> ProductEntityDTO
ProductServiceImpl "1" *--> "repository 1" ProductEntityRepository
ProductServiceImpl ..> ProductEntityRepositoryImpl
ProductServiceImpl ..> ProductEntityService
```
---
## Utilização da API REST
Para garantir o funcionamento correto da API, é importante seguir os passos abaixo em ordem:
1. #### Subindo o Banco de Dados
Primeiro, precisamos subir o banco de dados. Este projeto já inclui um arquivo Docker Compose que configura o banco de dados para você. Para subir o banco de dados, abra um terminal na pasta raiz do projeto e execute o seguinte comando:
```shell
docker compose up -d
```
2. #### Iniciando a API
Agora que nosso banco de dados está em funcionamento, podemos iniciar nossa API. A API é construída com o Spring Boot, o que simplifica o processo de inicialização.
Lembre-se, a ordem desses passos é importante! O banco de dados deve ser iniciado antes da API para garantir que todas as tabelas e conexões estejam corretamente configuradas quando a API for iniciada.
Esperamos que estas instruções ajudem você a configurar corretamente este projeto na sua IDE. Caso encontre qualquer problema, sinta-se à vontade para abrir uma "issue" no projeto no GitHub.
## Swagger
- [Swagger - Local](http://localhost:8080/swagger-ui/index.html)
- [Api - Docs](http://localhost:8080/v3/api-docs)
---
#### API - Rest
```mermaid
Expand Down Expand Up @@ -303,113 +462,4 @@ ProductServiceContract ..> ProductException
ProductWriter ..> ProductContract
```
---
#### CLI

```mermaid
classDiagram
direction BT
class Application {
+ Application()
+ main(String[]) void
}
class Entity~T~ {
<<Interface>>
+ serialize() String
+ deserialize(String[]) T
}
class Menu {
+ Menu()
- ProductEntityService productEntityService
- String MENU_DIVIDER
- String NEW_LINE
- String SINGLE_OPTION
- String MENU_MESSAGE
- String MENU_OPTION_SEPARATOR
- int MENU_DIVIDER_SIZE
- String TOTAL_OPTIONS
+ displayMenu() void
- optionBuilder(Scanner, String[]) int
}
class ProductEntity {
+ ProductEntity(String, String, ProductStatus, Double)
+ ProductEntity()
- String id
+ String FIELD_SEPARATOR
- ProductStatus status
- String productName
- Double productPrice
+ serialize() String
+ deserialize(String[]) ProductEntity
+ toString() String
+ getProductPrice() Double
+ getStatus() ProductStatus
+ getId() String
+ getProductName() String
}
class ProductEntityDTO {
+ ProductEntityDTO(String, String, ProductStatus, Double)
+ ProductEntityDTO()
- String id
- String productName
- Double productPrice
- ProductStatus status
+ getStatus() ProductStatus
+ getId() String
+ getProductPrice() Double
+ getProductName() String
+ toString() String
}
class ProductEntityRepository {
<<Interface>>
}
class ProductEntityRepositoryImpl {
+ ProductEntityRepositoryImpl()
- String FILE_PATH
+ save(ProductContract) ProductContract
+ get(String) ProductContract
}
class ProductEntityService {
<<Interface>>
+ get(String) ProductEntityDTO
+ enable(String) ProductEntityDTO
+ create(String, Double) ProductEntityDTO
+ disable(String) ProductEntityDTO
}
class ProductServiceImpl {
+ ProductServiceImpl()
- ProductEntityRepository repository
+ disable(String) ProductEntityDTO
+ create(String, Double) ProductEntityDTO
+ get(String) ProductEntityDTO
+ enable(String) ProductEntityDTO
}
class QuestionHandler {
<<enumeration>>
+ QuestionHandler()
+ INTEGER
+ DOUBLE
- String QUESTION_FORMAT
+ STRING
+ response(Scanner, String) Object
}
Application ..> Menu
Menu ..> ProductEntityDTO
Menu "1" *--> "productEntityService 1" ProductEntityService
Menu ..> ProductServiceImpl
Menu ..> QuestionHandler
ProductEntity ..> Entity~T~
ProductEntityRepositoryImpl ..> ProductEntity
ProductEntityRepositoryImpl ..> ProductEntityRepository
ProductEntityService ..> ProductEntityDTO
ProductServiceImpl ..> ProductEntity
ProductServiceImpl ..> ProductEntityDTO
ProductServiceImpl "1" *--> "repository 1" ProductEntityRepository
ProductServiceImpl ..> ProductEntityRepositoryImpl
ProductServiceImpl ..> ProductEntityService
```

---
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,20 @@

import diegosneves.github.hexagonal.adapters.cli.controller.Menu;

/**
* A classe Application representa o ponto de entrada do programa.
* Ela inicializa e executa o {@link Menu menu}.
*
* @author diegosneves
*/
public class Application {

/**
* O método principal é o ponto de entrada do programa.
* Ele cria uma instância da classe {@link Menu} e chama o método {@link Menu#displayMenu() displayMenu} para iniciar o menu.
*
* @param args os argumentos da linha de comando
*/
public static void main(String[] args) {
Menu menu = new Menu();
menu.displayMenu();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* <p>
* <b>Vale ressaltar que esta é apenas uma classe de exemplo para fins didáticos e, portanto, não segue necessariamente as melhores práticas de desenvolvimento de software.</b>
*
* @author diegoneves
* @author diegosneves
*/
public class Menu {

Expand All @@ -44,6 +44,18 @@ public Menu() {
this.productEntityService = new ProductServiceImpl();
}

/**
* Exibe as opções do menu e lida com a entrada do usuário. As opções são listadas na seguinte ordem:
* <pre>{@code
* 1. Obter produto por ID: Solicita ao usuário o ID do produto e exibe as informações do produto correspondente.
* 2. Criar um produto: Solicita ao usuário os detalhes do produto (como nome e preço) e cria um novo produto.
* 3. Ativar produto por ID: Solicita ao usuário o ID do produto e ativa o produto correspondente.
* 4. Desativar produto por ID: Solicita ao usuário o ID do produto e desativa o produto correspondente.
* 5. Sair: Encerra o menu.
* }</pre>
* <p>
* Se a entrada do usuário for inválida, uma mensagem de erro é exibida.
*/
public void displayMenu() {
boolean isOn = Boolean.TRUE;
Scanner scanner = new Scanner(System.in);
Expand Down Expand Up @@ -93,6 +105,13 @@ public void displayMenu() {
scanner.close();
}

/**
* Builds a menu option from the provided options and handles user input.
*
* @param scanner The scanner object used to get user input.
* @param options The list of options to display in the menu.
* @return The selected menu option.
*/
private int optionBuilder(Scanner scanner, String... options) {
int option = 0;
StringBuilder sb = new StringBuilder(MENU_DIVIDER.repeat(MENU_DIVIDER_SIZE)).append(NEW_LINE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

import diegosneves.github.hexagonal.app.enums.ProductStatus;

/**
* A classe {@link ProductEntityDTO} representa um objeto de transferência de dados (DTO) para uma entidade de produto.
* Ela contém as informações básicas de um {@link diegosneves.github.hexagonal.adapters.cli.model.ProductEntity produto}, como ID, nome, status e preço.
*
* @author diegosneves
*/
public class ProductEntityDTO {

private String id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

import java.util.Scanner;

/**
* O enum {@link QuestionHandler} fornece diferentes tipos de perguntas e seus respectivos métodos de resposta.
* Cada constante do enum representa um tipo diferente de resposta: STRING, DOUBLE e INTEGER.
* O método de resposta recebe um objeto Scanner e uma pergunta como entrada e retorna a resposta digitada.
*
* @author diegosneves
*/
public enum QuestionHandler{

STRING {
Expand Down Expand Up @@ -46,6 +53,13 @@ public Object response(Scanner scanner, String question) {

private static final String QUESTION_FORMAT = "-> %s?\n- ";

/**
* Este método fornece uma resposta para uma determinada pergunta com base no tipo de entrada.
*
* @param scanner O objeto {@link Scanner} usado para ler a entrada do usuário.
* @param question A pergunta a ser exibida ao usuário.
* @return A resposta para a pergunta.
*/
public abstract Object response(Scanner scanner, String question);

}
Loading

0 comments on commit 97308db

Please sign in to comment.