Tutorial: Criando um CRUD utilizando Quarkus Java + REST + CDI + Panache, Hibernate com Postgres (Docker) + Postman
Tags: quarkus, developer, hibernate, java
Published: 2021-02-01 12:28:33

### Tutorial: Criando um CRUD utilizando Quarkus Java + REST + CDI + Panache, Hibernate com Postgres (Docker) + Postman

 

> [**Se inscreva no meu canal do Youtube, vários conteúdos para Desenvolvedores: https://www.youtube.com/channel/UCzoyY_hIVs53dQUeY4yVkhA**](https://www.youtube.com/channel/UCzoyY_hIVs53dQUeY4yVkhA)

![](https://cdn-images-1.medium.com/max/800/1*5DrjPTcfjAJajWz5ERyNfw.png)


### Introdução

Os programadores de Java estão “cansados” de ouvir as seguintes expressões: “Java é lento!”, “O pacote do java é grande”, “O tempo de inicialização é lento!”. Como uma forma de resolver isso, a [Red Hat](https://www.redhat.com/) lançou o [Quarkus](http://quarkus.io/), um framework Java nativo do [Kubernetes](https://kubernetes.io/) feito sob medida para o [GraalVM](https://www.graalvm.org/) e [OpenJDK HotSpot](https://openjdk.java.net/). O [Quarkus](http://quarkus.io/) visa tornar o [java](https://www.java.com/pt_BR/) uma plataforma líder em ambientes serverless e [Kubernetes](http://kubernetes.io/), oferecendo aos desenvolvedores um modelo unificado de [programação reativa e imperativa](https://medium.com/alexandre-malavasi/descomplicando-programa%C3%A7%C3%A3o-imperativa-declarativa-e-reativa-a481baa87742).

![](https://cdn-images-1.medium.com/max/800/0*MW2Z3ZamB86Wj-58)

O [QuarkusIO](https://quarkus.io/), promete entregar pacotes menores, com um tempo de inicialização extremanente rápido, menor consumo de memória, desde que combinado com a [GraalVM](https://www.graalvm.org/), O Quarkus vai realizar a compilação [Ahead-of-time(AOT)](https://openjdk.java.net/jeps/295). Baseada nos melhores padrões, plataforma integrada, baixo consumo de processamento e tempo de inicialização é incrivelmente rápido, em milisegundos, Quarkus permite o uso do Java em ambientes serverless, suportando um ambiente responsivo e escalável.

Na imagem abaixo, podemos ver a comparação do consumo e memória e o tempo de inicialização + tempo da resposta da primeira requisição, podemos perceber que o Quarkus + OpenJDK + GraalVM, consomem menos memória e iniciam mais rapidamente, do que a o Quarkus + OpenJDK e um framework equivalente de mercado.

![](https://cdn-images-1.medium.com/max/800/0*63Q0D7QX_a8PwJdX)

Um grande diferencial do Quarkus é que ele suporta as principais especificações, ou seja, você, não precisa aprender nada de novo. Por exemplo, você pode utilizar o [CDI](https://blog.caelum.com.br/use-cdi-no-seu-proximo-projeto-java/) e [JAX-RS](https://docs.oracle.com/javaee/6/tutorial/doc/giepu.html), também é possível suportar as extensões como: [Hibernate](https://hibernate.org/), [Kafka](https://kafka.apache.org/), [OpenShift](https://www.openshift.com/), [Kubernetes](http://kubernetes.io/). Na era do cloud, no qual containers, Kubernetes, microservices, functions-as-a-service (Faas), e aplicações nativas para o cloud estão apresentando altos níveis de produtividade e eficiência, o Quarkus surge com uma alternativa muito interessante.

Antes de continuar o post, gostaria de compartilhar a apresentação que fiz nesse ano.

### Apresentação no Evento Brasília Dev Festival 2019

Em Setembro de 2019, palestrei no evento [Brasília Dev Festival](https://www.sympla.com.br/brasilia-dev-festival-2019__581528), realizado em Brasília, foi um evento recheado de muito conhecimento e network, a apresentação está disponível abaixo:

### Parte prática — Hands-on (Tutorial passo a passo)

Antes de iniciar o desenvolvimento da aplicação, é necessário atender os requisitos mínimos abaixo:

### Requisitos mínimos:

-   Você vai precisar de uma [IDE](https://en.wikipedia.org/wiki/Comparison_of_integrated_development_environments#Java) como por exemplo: [IntelliJ IDEA](https://www.jetbrains.com/idea/download/), [Eclipse](https://www.eclipse.org/downloads/), [VSCode](https://code.visualstudio.com/Download).
-   Instale a [JDK 8 or 11+](https://adoptopenjdk.net/)
-   Instale o [Apache Maven 3.5.3+](https://maven.apache.org/) ou o [Gradle](https://gradle.org/)
-   (Opcional) — Você pode baixar o [GraalVM](https://www.graalvm.org/) 19.2.1 para compilar nativamente sua aplicação.
-   [Panache Entity](https://quarkus.io/guides/hibernate-orm-panache) (Possível artigo futuro)
-   [Docker](https://www.docker.com/)
-   Escolha um cliente para conectar com o Banco de dados, exemplo: [DBeaver](https://dbeaver.io/download/), [PGAdmin](https://www.pgadmin.org/), [Postico (Mac)](https://eggerapps.at/postico/)
-   Cliente para realizar requisições REST: [Postman](https://www.getpostman.com/) ou o [Insomnia](https://insomnia.rest/download/).

### Instruções Adicionais:

-   [Instalação do Docker (Documentação oficial)](https://docs.docker.com/install/)
-   [Instalando Docker no windows](https://www.youtube.com/watch?v=OweZAewo54A): (Youtube, ESR)
-   [Instalando o Docker no Linux](https://www.youtube.com/watch?v=FTxBa7i8VMM): (Youtube: LinuxTips)
-   [Instalando o Docker no Mac:](https://www.youtube.com/watch?v=pFavwxt-4ig) (Youtube: Wellington Rogati)

### Escopo da aplicação

A partir de agora, vamos criar uma aplicação que será desenvolvida com o Quarkus, utilizando o Panache + Hibernate para persistência, vamos utilizar o CDI para Injeção de Dependência e JAX-RS para a API REST.

> Vamos criar uma API para Listar, Cadastrar, Editar e Excluir alimentos.

O Quarkus possui um Archetype para criação da aplicação de forma fácil, basta executar o comando abaixo:

-   **Sugestão: verifique a última versão no site oficial do** [**Quarkus.io**](https://quarkus.io/)**.**

mvn io.quarkus:quarkus-maven-plugin:1.11.1.Final:create \  
     -DprojectGroupId=br.com.food \  
     -DprojectArtifactId=quarkus-food \  
     -DclassName="br.com.food.resource.FoodResource" \  
     -Dpath="/food"

$ cd quarkus-food

Vamos entender o que cada trecho significa:

# Plugin do Maven para criação do Projeto no Quarkus  
$ mvn io.quarkus:quarkus-maven-plugin:1.11.1.Final:create

# Definição do pacote do projeto  
-DprojectGroupId=br.com.food

# Definição do Nome do Projeto  
-DprojectArtifactId=quarkus-food

# Definindo o caminho da classe Rest (inicial)  
-DclassName="br.com.food.resource.FoodResource"

# Definição da URI, final do endereço para acessar no navegador  
-Dpath="/food

O Quarkus disponibiliza um site chamado [Quarkus.code.io](https://code.quarkus.io/), onde é posísvel configurar o projeto de uma forma mais visual, vale a pena conferir, segue o link: [https://code.quarkus.io/](https://code.quarkus.io/)

![](https://cdn-images-1.medium.com/max/800/1*o89osaxaalTeTkmdEAhXBw.png)

Site: code.quarkus.io

### Criando o projeto — Executando o comando de criação

mvn io.quarkus:quarkus-maven-plugin:1.11.1.Final:create \  
>     -DprojectGroupId=br.com.mp \  
>     -DprojectArtifactId=food \  
>     -DclassName="br.com.mp.FoodResource" \  
>     -Dpath="/food"

// Log omitido   
[INFO] Your application will be accessible on [http://localhost:8080](http://localhost:8080)  
[INFO] ------------------------------------------------------------------------  
[INFO] BUILD SUCCESS  
[INFO] ------------------------------------------------------------------------  
[INFO] Total time:  42.305 s  
[INFO] Finished at: 2019-12-12T09:36:11-02:00  
[INFO] ------------------------------------------------------------------------

Log completo você encontra aqui: [https://pastebin.com/UfczCUDL](https://pastebin.com/UfczCUDL)

> Observação: A criação do projeto pode levar um tempo, já que o Maven, irá realizar o download de todas as dependências

### Abra a aplicação em sua IDE preferida

Para esse exemplo, estou utilizando o InteliJ, porém, gosto bastante do Eclipse e Visual code, sinta-se a vontade para escolher sua IDE favorita.

Na imagem abaixo, podemos ver a estrutura do projeto (Maven), ressaltando a criação dos arquivos dentro da pasta Docker, Dockerfile.jvm e Dockerfile.native, que pretendo falar em um outro artigo. Logo abaixo, veremos o arquivo FoodResource, essa classe é a responsável por “expor” a API.

![](https://cdn-images-1.medium.com/max/800/0*_np4Y_KFaEkvnZ0X)

### Executando o projeto inicial

No terminal, execute o comando abaixo:

mvn compile quarkus:dev

Resultado da execução:

> Possivelmente, na primeira execução o compilador irá verificar se existe alguma dependência para baixar, como no exemplo abaixo.

[INFO] Scanning for projects...  
[INFO]   
[INFO] ---------------------------< br.com.mp:food >---------------------------  
[INFO] Building food 1.0-SNAPSHOT  
[INFO] --------------------------------[ jar ]---------------------------------  
[INFO]   
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ food ---  
[INFO] Using 'UTF-8' encoding to copy filtered resources.  
[INFO] Copying 2 resources  
// LOG OMITIDO   
[INFO] ---------------------------< br.com.mp:food >---------------------------  
[INFO] Building food 1.0-SNAPSHOT  
[INFO] --------------------------------[ jar ]---------------------------------  
[INFO]   
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ food ---  
2019-12-12 15:12:19,730 INFO  [io.quarkus] (main) Quarkus 1.0.1.Final started in 0.735s. Listening on: [http://0.0.0.0:8080](http://0.0.0.0:8080)  
2019-12-12 15:12:19,740 INFO  [io.quarkus] (main) Profile dev activated. Live Coding activated.  
2019-12-12 15:12:19,741 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]

Log completo da execução da aplicação: [https://pastebin.com/pnLdVYsc](https://pastebin.com/pnLdVYsc)

No final Log, aparece a URL para acessar com o navegador.

[io.quarkus] (main) Quarkus 1.0.1.Final started in 0.735s. Listening on: [http://0.0.0.0:8080](http://0.0.0.0:8080)

> Você pode acessar a API através dos endereços: [http://localhost:8080,](http://localhost:8080,) [http://0.0.0.0:8080](http://0.0.0.0:8080) ou [http://127.0.0.1:8080.](http://127.0.0.1:8080.)

Para acessar a página, basta clicar no endereço exposto no terminal ou simplesmente copiar e colar no seu navegador, como mostrado no exemplo abaixo:

![](https://cdn-images-1.medium.com/max/800/0*35XhTaM2Je0WAkuE)

### Testando a API /food, através do navegador

A URI da nossa API está definida inicialmente na classe FoodResource.java, com o caminho : /food

![](https://cdn-images-1.medium.com/max/800/0*KM0HxddtB87IpGt2)

Abra o navegador e digite o endereço: [http://localhost:8080/food,](http://localhost:8080/food,) conforme a imagem a seguir:

![](https://cdn-images-1.medium.com/max/800/0*Vt7hkOGFOjW5o-c4)

### Executando uma instância do Postgresql no Docker

Para armazenar as informações, vamos subir uma instância do Postgresql, utilizando o Docker, para isso, é necessário ter o Docker instalado e executar o comando listado abaixo:

# Criando uma instância do Postgressql através do Docker

docker run --name postgres-food -e "POSTGRES_PASSWORD=postgres" -p 5433:5432 -v ~/developer/PostgreSQL:/var/lib/postgresql/data -d postgres

> Observação: Precisei mudar a porta padrão de 5432 para 5433, já que tinha uma outra instância rodando aqui.

Vamos testar a conexão com o Banco de dados, no meu caso, eu estou utilizando o DBeaver 6.1.0, porém, existem diversas outras aplicações para conectar com o Banco de Dados PostgreSQL, abaixo, segue o teste da conexão do banco de dados:

![](https://cdn-images-1.medium.com/max/800/0*KPkBWQqIZIuXcZ80)

No cliente SQL, vamos abrir o schema do Banco de dados e percebemos que o mesmo está vazio, não existe nenhuma tabela criada.

![](https://cdn-images-1.medium.com/max/800/0*XxjZCaN7s6DqYKfs)

### Voltando para a nossa aplicação

Retorne para sua IDE e adicione as seguintes dependências para o PanacheEntity e a dependência do Postgresql, as informações devem ser adicionadas no arquivo pom.xml (Na raiz do projeto).

<!-- Hibernate ORM specific dependencies -->  
<dependency>  
  <groupId>io.quarkus</groupId>  
  <artifactId>quarkus-hibernate-orm-panache</artifactId>  
</dependency>

<!-- JDBC driver dependencies -->  
<dependency>  
  <groupId>io.quarkus</groupId>  
  <artifactId>quarkus-jdbc-postgresql</artifactId>  
</dependency>

<!-- JSONB serialize JSON -->  
<dependency>  
  <groupId>io.quarkus</groupId>  
  <artifactId>quarkus-resteasy-jsonb</artifactId>

</dependency>

> O Panache Entity visa facilitar a implementação da camada de persistência da aplicação. Além disso, o framework trás diversos métodos como Count, ListAll(), findById, persist, delete já implementados, conforme exibido código abaixo

Exemplo do PanacheEntity (Retirado do site: [https://quarkus.io/guides/hibernate-orm-panache](https://quarkus.io/guides/hibernate-orm-panache))

// creating a person  
Person person = new Person();  
person.name = "Stef";  
person.birth = LocalDate.of(1910, Month.FEBRUARY, 1);  
person.status = Status.Alive;

// persist it  
person.persist();

// note that once persisted, you don't need to explicitly save your entity: all  
// modifications are automatically persisted on transaction commit.

// check if it's persistent  
if(person.isPersistent()){  
    // delete it  
    person.delete();  
}

// getting a list of all Person entities  
List<Person> allPersons = Person.listAll();

// finding a specific person by ID  
person = Person.findById(personId);

// finding all living persons  
List<Person> livingPersons = Person.list("status", Status.Alive);

// counting all persons  
long countAll = Person.count();

// counting all living persons  
long countAlive = Person.count("status", Status.Alive);

// delete all living persons  
Person.delete("status", Status.Alive);

// delete all persons  
Person.deleteAll();

> Observação: O PanacheEntity é muito interessante, porém, vou explicar melhor em um artigo futuro.

### Voltando para a implementação da classe de modelo (Entity)

Na IDE, crie a classe (Entidade): Food.java, dentro da pasta br.com.food.entity.

Classe: Food.java

package br.com.food.entity;

import io.quarkus.hibernate.orm.panache.PanacheEntityBase;

import javax.persistence.*;  
import java.util.Objects;

@Entity  
public class Food extends PanacheEntityBase {

    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
      
    @Column  
    private String name;  
      
    @Column  
    private Double calories;

// Omitido  
}

### Configurando a conexão de Banco de dados no projeto

Procure o arquivo application.properties, dentro da pasta resources e adicione as seguintes configurações:

# configure your datasource  
quarkus.datasource.url = jdbc:postgresql://localhost:5433/food  
quarkus.datasource.driver = org.postgresql.Driver  
quarkus.datasource.username = postgres  
quarkus.datasource.password = postgres

# drop and create the database at startup (use `update` to only update the schema)  
quarkus.hibernate-orm.database.generation = drop-and-create

> Ao executar nossa aplicação, nos deparamos com o seguinte problema: Caused by: org.postgresql.util.PSQLException: FATAL: database “food” does not exist

Caused by: org.postgresql.util.PSQLException: FATAL: database "food" does not exist  
        at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2468)  
        at org.postgresql.core.v3.QueryExecutorImpl.readStartupMessages(QueryExecutorImpl.java:2587)  
        at org.postgresql.core.v3.QueryExecutorImpl.<init>(QueryExecutorImpl.java:134)  
        at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:250)  
        at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49)  
        at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:195)  
        at org.postgresql.Driver.makeConnection(Driver.java:458)  
        at org.postgresql.Driver.connect(Driver.java:260)

> Solução: Criar um Database no Postgresql, através do ClienteSQL

![](https://cdn-images-1.medium.com/max/800/0*HkKziu22zWScQ5Yz)

![](https://cdn-images-1.medium.com/max/800/0*vBeDC7LDFhmIHGP8)

### Executando a aplicação com o Banco de Dados configurado

Retornando para a nossa IDE, vamos executar o comando que irá iniciar nossa aplicação:

$ mvn compile quarkus:dev  
  

[INFO] Scanning for projects...  
[INFO]   
[INFO] --------------------------< br.com.food:food >--------------------------  
[INFO] Building food 1.0-SNAPSHOT  
[INFO] --------------------------------[ jar ]---------------------------------  
[INFO]   
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ food ---  
[INFO] Using 'UTF-8' encoding to copy filtered resources.  
[INFO] Copying 2 resources  
[INFO]   
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ food ---  
[INFO] Changes detected - recompiling the module!  
[INFO] Compiling 2 source files to /home/marcus/Estudo/Quarkus/food/target/classes  
[INFO]   
[INFO] --- quarkus-maven-plugin:1.0.1.Final:dev (default-cli) @ food ---  
Listening for transport dt_socket at address: 5005  
2019-12-12 16:44:24,885 WARN  [org.hib.eng.jdb.spi.SqlExceptionHelper] (main) SQL Warning Code: 0, SQLState: 00000  
2019-12-12 16:44:24,891 WARN  [org.hib.eng.jdb.spi.SqlExceptionHelper] (main) table "food" does not exist, skipping  
2019-12-12 16:44:25,135 INFO  [io.quarkus] (main) Quarkus 1.0.1.Final started in 1.715s. Listening on: [http://0.0.0.0:8080](http://0.0.0.0:8080)  
2019-12-12 16:44:25,136 INFO  [io.quarkus] (main) Profile dev activated. Live Coding activated.  
2019-12-12 16:44:25,136 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache, jdbc-postgresql, narayana-jta, resteasy]

> Obversação 1: Assim que finalizar a execução, percebemos que a tabela Food foi criada no banco de dados.

> Obvervação 2: Caso não queira o comportamento de criação automatica do banco de dados, basta comentar ou remover a linha: “quarkus.hibernate-orm.database.generation = drop-and-create”, de dentro do arquivo do application.properties.

### Verificando se a tabela foi criada no Banco de Dados.

![](https://cdn-images-1.medium.com/max/800/0*UzES496LwJbjGDJF)

> Espero que esteja gostando desse artigo.

### Implementando uma simples classe de negócio

Crie uma classe chamada de FoodController.java, dentro da pasta br.com.food.controller. Essa classe será responsável por conter uma regra de negócio simples.

@ApplicationScoped  
public class FoodController {

    public Food update(Long id, Food food) {  
        Food foodEntity = Food.findById(id);

        if (foodEntity == null) {  
            throw new WebApplicationException("Food with id of " + id + " does not exist.", Response.Status.NOT_FOUND);  
        }

        foodEntity.setName(food.getName());  
        foodEntity.setCalories(food.getCalories());

        return foodEntity;  
    }

    /**  
     * This method is main purpose to show simple "Business" example  
     * @param food  
     * @return  
     */  
    public boolean isFoodNameIsNotEmpty(Food food) {  
        return food.getName().isEmpty();  
   
   }  
}

### Implementação do FoodResouce.java

A classe FoodResource, é responsável por expor a API com os métodos para cadastro, edição, remoção e lista de todos os alimentos cadastrados.

# FoodResource.java  
package br.com.food.resource;  
// OMITIDO

@Path("/food")  
@Produces(MediaType.APPLICATION_JSON)  
@Consumes(MediaType.APPLICATION_JSON)  
public class FoodResource {

    @Inject  
    private FoodController foodController;

    @GET  
    public List<Food> findAll() {  
        return Food.listAll();  
    }

    @POST  
    @Transactional  
    public Response create(Food food) {  
        Food.persist(food);  
        return Response.ok(food).status(201).build();  
    }

    @PUT  
    @Path("{id}")  
    @Transactional  
    public Response update(@PathParam("id") Long id, Food food) {

        if (foodController.isFoodNameIsNotEmpty(food)) {  
            return Response.ok("Food was not found").type(MediaType.APPLICATION_JSON_TYPE).build();  
        }

        Food foodEntity = foodController.update(id, food);

        return Response.ok(foodEntity).build();  
    }

    @DELETE  
    @Path("{id}")  
    @Transactional  
    public Response delete(@PathParam("id") Long id) {  
        Food foodEntity = Food.findById(id);

        if (foodEntity == null) {  
            throw new WebApplicationException("Food with id " + id + " does not exist.", Response.Status.NOT_FOUND);  
        }

        foodEntity.delete();  
        return Response.status(204).build();  
    }  
}

> Observação: Reparem que é possível efetuar uma operação de persistência tanto na camada de Resource(API), quanto na classe de negócio ou até mesmo em uma classe Data Access Object — [DAO](https://pt.stackoverflow.com/questions/113840/como-funciona-o-padr%C3%A3o-dao).

### Testando a API através do Postman

Abra o Postman, selecione o método POST e digite a URL: [http://localhost:8080/food.](http://localhost:8080/food.) Adicionalmente, adicione um Body com os dados conforme a imagem abaixo:

![](https://cdn-images-1.medium.com/max/800/0*prt7lK8MsX4qWDqk)

### Cadastrando outro alimento no Postman

![](https://cdn-images-1.medium.com/max/800/0*dma82JkvOgM9OlDC)

### Listando todas os alimentos no Postman

No Postman, crie uma outra requisição do tipo GET e digite a url: [http://localhost:8080/food,](http://localhost:8080/food,) o resultado será a lista de todos os alimentos cadastrados no banco de dados, conforme a imagem abaixo:

![](https://cdn-images-1.medium.com/max/800/0*l0s5y9Js6drFZClc)

### Postman — Atualizando um objeto

Para atualizar a descrição e/ou a caloria de um alimento, basta criar uma nova requisição do tipo PUT, adicionar no final da URL o código (ID) do alimento que modificado. Não esqueça de preencher o body, que contém o JSON do objeto alterado.

![](https://cdn-images-1.medium.com/max/800/0*QPuv-9ZGzJOg-ckj)

### Verificando os registros no Banco de Dados

![](https://cdn-images-1.medium.com/max/800/0*yyJWkqJsQ6h2XEAr)

### Removendo um alimento através do Postman

![](https://cdn-images-1.medium.com/max/800/0*MwVDoLzoiRCtR8g0)

### Listando todos os alimentos através do Postman

No último teste, será listado todos os alimentos que estão cadastrados no banco de dados.

### Conclusão

Esse é o meu primeiro artigo e espero que vocês tenham gostado, sinta-se à vontade para sugerir, criticar ou elogiar. Um grande abraço e até a próxima.

### Código-Fonte

O código-fonte está disponível no endereço: [https://github.com/marcuspaulo/quarkus-food](https://github.com/marcuspaulo/quarkus-food)