Monday, February 4, 2019

SpringBoot + MySQL + Docker-Compose (parte 1)


A maioria das aplicações modernas são constituidas de múltiplos pequenos serviços independentes que interagem e assim dão forma à própria aplicação. Chamamos isso de microserviços. Um simples exemplo pode ser uma aplicação com 3 serviços:
  1. web front-end
  2. web back-end
  3. banco de dados
Coloque os três serviços juntos e temos uma aplicação com alguma utilidade.

Subir e gerenciar vários serviços pode se tornar uma tarefa difícil. É aí que entra o Docker-Compose.

Ao invés de juntar tudo com scripts e comandos extreamente longos, o Docker-Compose permite você descrever toda aplicação em único arquivo de configuração declarativo. Depois então você sobe todos os serviços com um único comando:

$ docker-compose up

Vamos ilustrar o uso do docker-compose criando uma aplicação formada por 3 serviços: uma interface REST no backend (com Spring Boot), um front-end HTML (Java Server Faces) e um banco de dados MySQL. Cada serviço totalmente separado um do outro

Front-End com Java Server Faces

Nosso front-end é um formulário HTML com JSF para cadastrar uma entidade Pessoa, a qual possui dois campos: nome e profissão. O front também lista todas as pessoas registradas na base de dados em um elemento table. O container é o WildFly. Há uma camada de serviço para fazer a requisições ao backend, representada pela classe Service.java e retorná-las ao managed bean. A classe que recebe os eventos da página HTML é ManagedBean.java:

classe ManagedBean.java

package com.app;

import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Model;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import com.app.entidade.Pessoa;

@Model
public class ManagedBean {

 @Inject
 private Service service;
 private Pessoa pessoa = new Pessoa();
 private List pessoas;
 
 
 public String salvar() {
  
    try {
  pessoa = service.salvarPessoa(pessoa);
  pessoa = new Pessoa();
  FacesContext.getCurrentInstance()
    .addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, 
           "salvo com sucesso", "salvo com sucesso"));
   }  
   catch(Exception e) {
   FacesContext.getCurrentInstance()
    .addMessage(null, new FacesMessage(FacesMessage.SEVERITY_FATAL, 
            e.getMessage(), e.getMessage()));
  }
  return null;
 }
 
 public Pessoa getPessoa() {
  return pessoa;
 }
 public void setPessoa(Pessoa pessoa) {
  this.pessoa = pessoa;
 }
 public List getPessoas() {
  try {   
   pessoas = service.getPessoas();  
   return pessoas;
  }
  catch(RuntimeException e) {
   FacesContext.getCurrentInstance()
   .addMessage(null, new FacesMessage(FacesMessage.SEVERITY_FATAL, 
           e.getMessage(), e.getMessage()));   
  }
  return null;
 }
 public void setPessoas(List pessoas) {  
  this.pessoas = pessoas;
 } 
}

classe Service.java

package com.app;

import java.net.URI;
import java.util.List;
import javax.enterprise.inject.Model;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;

import com.app.entidade.Pessoa;

@Model
public class Service {

 private final String URL_BACKEND = "http://backend:8080/app-backend/";
 
 public Pessoa salvarPessoa(Pessoa pessoa) {
  
  final String operacao = "salvar";  
  URI uri = UriBuilder.fromUri(URL_BACKEND).path(operacao).build();
  
  //usando JAX-RS Client API para enviar o objeto pessoa ao server back-end
  Entity data = Entity.entity(pessoa, MediaType.APPLICATION_XML_TYPE);
  Response response = ClientBuilder.newClient()
      .target(uri)
      .request(MediaType.APPLICATION_XML)
      .post(data, Response.class);
  
  if(response.getStatusInfo() == Response.Status.OK)
   return pessoa;
  else
   throw new RuntimeException("Ocorreu um erro ao salvar a Pessoa");    
 }
 
 public List getPessoas() {
  
  final String operacao = "all";
  URI uri = UriBuilder.fromUri(URL_BACKEND).path(operacao).build();
  
  Response response = ClientBuilder.newClient()
       .target(uri)
       .request(MediaType.APPLICATION_JSON_TYPE)
       .get(Response.class);
  
  if(response.getStatusInfo() == Response.Status.OK)
   return response.readEntity(List.class);
  else
   throw new RuntimeException("Não foi possível obter a Lista de Pessoas");  
 }
}

Entidade Pessoa.java
package com.app.entidade;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Pessoa implements Serializable{

 private Long id;
 private String nome;
 private String profissao;

    //getters & setters omitidos
}

Página index.xhtml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html">

<h:head>
 <title>Cadastro Pessoa</title>
</h:head>
<h:body>
 <h:form>
  <h:messages />
  <h:panelGrid columns="2">
   <h:outputText value="Nome" />
   <h:inputText value="#{managedBean.pessoa.nome}" />
   <h:outputText value="Idade" />
   <h:inputText value="#{managedBean.pessoa.profissao}" />
  </h:panelGrid>
  <h:commandButton action="#{managedBean.salvar}" value="Salvar" />
  <p />
  Lista
  <h:dataTable value="#{managedBean.pessoas}" var="pessoa" border="1">
   <h:column>
    <h:outputText value="#{pessoa.nome}" />
   </h:column>
   <h:column>
    <h:outputText value="#{pessoa.profissao}" />
   </h:column>
  </h:dataTable>
 </h:form>
</h:body>
</html>

O arquivo Dockerfile é auto explicativo e descreve passo a passo como construir a aplicação e executá-la dentro do Docker: A aplicação roda dentro do Wildfly (FROM) e o arquivo front-end.war é adicionado na pasta /opt/jboss/wildfly/standalone/deployments/ do servidor:

   FROM jboss/wildfly
   MAINTAINER "http://finalexception.blogspot.com"
   ADD target/front-end.war /opt/jboss/wildfly/standalone/deployments/

Com o botão direito do mouse na pasta raiz do projeto, selecione Run As e Run as Maven Install. Esse comando gera o arquivo front-end.war na pasta target, conforme descrito no Dockerfile.

Neste ponto a aplicação pode rodar, porém ela ainda não estará funcional, já que depende de dois outros serviços: o backend propriamente dito, este por sua vez depende do banco de dados.

Na parte 2 deste artigo criamos e subimos esses dois serviços que faltam.



"Ouçam agora, vocês que dizem: 'Hoje ou amanhã iremos para esta ou aquela cidade, passaremos um ano ali, faremos negócios e ganharemos dinheiro'. Vocês nem sabem o que acontecerá amanhã! Que é a sua vida? Vocês são como a neblina que aparece por um pouco de tempo e depois se dissipa. Em vez disso, deveriam dizer: 'Se o Senhor quiser, viveremos e faremos isto ou aquilo'."

Tiago 4:13-15


       

No comments:

Post a Comment