Utilizando LocalDate, LocalDateTime e LocalTime na Prática

Tudo bem pessoal, hoje iremos avaliar e analisar operações de manipulação de Datas envolvendo a JavaTime API introduzida no Java 8.

Exemplos da java.time API


Já se passaram alguns anos desde o lançamento do Java 8 e mesmo após este período, há empresas que desconhecem o poder da java.time API, esta foi uma nova API de datas introduzida no Java 8 visando resolver problemas que tínhamos com as velhas classes Date e Calendar.

Vamos mostrar vários exemplos práticos do uso da API:

Criação de objetos

No exemplo abaixo, estamos criando os objetos para manipulação de datas, perceba que temos 3 tipos, sendo LocalDate para manipular datas, LocalDateTime para manipular data/hora e LocalTime para horas:

LocalDate localDate      = LocalDate.now();
LocalDateTime localDateTime = LocalDateTime.now();
LocalTime localTime      = LocalTime.now();

Utilizando formatação

Aqui realizamos a operação de formatação, perceba que não foi necessário utilizar a classe SimpleDateFormat, que usaríamos em conjunto com Date ou Calendar, aqui utilizamos a DateTimeFormatter passando o formato desejado:

String strLocalDate2   = LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
String strLocalDateTime2 = LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
String strLocalTime2   = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));

Adicionando dias, meses e horas

Um recurso muito interessante são os métodos de adicionar períodos, quem já trabalhou com Calendar sabe como essa tarefa era complexa, onde era necessário manipular métodos void e passar constantes para determinar  qual parte gostaríamos de alterar, aqui basta chamar o método plus desejado de forma fluente, veja o exemplo:

LocalDate localDate3         = LocalDate.now().plusDays(1).plusMonths(1);
LocalDateTime localDateTime3 = LocalDateTime.now().plusDays(1).plusMonths(1).plusHours(2);

Subtraindo dias, meses e horas

Da mesma forma que acontece a adição de valores,  podemos também subtrair dados de diferentes parte do período:

LocalDate localDate4       = LocalDate.now().minusDays(1).plusMonths(1);
LocalDateTime localDateTime4 = LocalDateTime.now().minusDays(1).minusMonths(1).minusHours(2);
LocalTime localTime4       = LocalTime.now().minusHours(1);

Criando objetos específicos

Um recurso interessante é quando criamos uma data com valores específicos, onde cada tipo possui métodos fábricas para construção dos objetos:

LocalDate localDate5       = LocalDate.of(2018, 07, 22);
LocalDateTime localDateTime5 = LocalDateTime.of(2018, 07, 22, 10, 15, 30);
LocalTime localTime5       = LocalTime.of(10, 35, 12);

Realizando parse de String em Datas

Uma das situações mais comuns é a operação de parse, que consiste em pegar uma data como String e transformar para a classe de Período correspondente:

LocalDate localDate6       = LocalDate.parse("2018-07-22", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime localDateTime6 = LocalDateTime.parse("2018-07-22 10:35:10", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
LocalTime localTime6       = LocalTime.parse("11:40:02", DateTimeFormatter.ofPattern("HH:mm:ss"));

Recuperando partes especificas de um objeto

Outro recurso interessante e muito utilizando é quando temos que recuperar uma parte especifica do objeto, podendo ser ano, mês, dia, hora, minuto, segundo:

int year    = LocalDate.now().getYear();
Month month = LocalDateTime.now().getMonth();
int hour    = LocalTime.now().getHour();

Comparando com os métodos isAfter, isBefore e isEqual

Com frequência temos que comparar objetos Data, analisando se um período é maior, menor ou igual ao outro, para isto temos métodos utilitários que facilitam esse tipo de ação, veja abaixo:

LocalDate localDate8 = LocalDate.now();
LocalDate localDate9 = LocalDate.now().minusDays(1);
  
boolean isAfter  = localDate8.isAfter(localDate9);   //true
boolean isBefore = localDate8.isBefore(localDate9); //false
boolean isEqual  = localDate8.isEqual(localDate9); //false

Capturando Diferenças entre LocalDate com classe Period

É comum precisar saber a diferença entre dois objetos Data, aqui temos a classe Period que possui vários métodos utilitários para esta finalidade, esta classe representa o tempo em anos, meses e dias, vamos testar o método between que recupera a diferença entre dois objetos LocalDate, veja abaixo:

LocalDate localDate10 = LocalDate.now();
LocalDate localDate11 = LocalDate.now().plusDays(2);
  
Period period1 = Period.between(localDate10, localDate11); 

Capturando Diferenças com a Enum ChronoUnit

A Enum ChronoUnit é utilizada para manipular Tempos, com ela podemos manipular tempos de  diferentes formas, podemos utiliza-la em conjunto com LocalDate, LocalDateTime e LocalTime, segue o exemplo:


LocalDateTime localDateTime12 = LocalDateTime.now();
LocalDateTime localDateTime13 = LocalDateTime.now().plusDays(2);
  
long periodAsMinutes = ChronoUnit.MINUTES.between(localDateTime12, localDateTime13);
long periodAsHours  = ChronoUnit.HOURS.between(localDateTime12, localDateTime13);
long periodAsDays = ChronoUnit.DAYS.between(localDateTime12, localDateTime13);

A API java.time possui uma porção de outros métodos e classes que podemos utilizar no decorrer dos projetos, trabalhar com datas, períodos, tempos, é praticamente obrigatórios em 90% dos sistemas.

A maioria dos frameworks do Mundo Java como Spring, Hibernate, JSF, já fornecem suporte full para o uso da API.

Até mais.

Código fonte

Referências

Instalando o Apache Spark e utilizando o Spark Shell

Olá pessoal, hoje iremos conhecer e instalar a ferramenta para processamento de dados Apache Spark, esta é uma ferramenta que atualmente vem sendo muito utilizada em ambientes de manipulação de grande quantidade de dados.

O Que é BigData

BigData é com certeza uma das palavras mais faladas em tecnologia nos últimos anos, e com isso temos diferentes significados espalhados pelas mais variadas fontes, mas basicamente BigData pode ser resumido em:
  • Volume: Grande quantidade de dados;
  • Variedade: Dados variados, sendo de tipos e fontes diferentes;
  • Velocidade: Dados crescendo/aumentando em alta velocidade.
Quando manipulamos uma grande quantidade de dados, começam a surgir desafios do mesmo tamanho, tais como performancecapacidadearmazenamentoescalabilidade, entre outros, e para esses novos desafios foram surgindo várias ferramentas, entre elas: Hadoop, Spark, NoSQL, Hive, entre outras.

Conhecendo o Spark

Como falamos anteriormente o Apache Spark foi uma dessas ferramentas que surgiram para resolver desafios enfrentados em cenários de BigData e Análise de Dados, a sua finalidade é realizar o processamento de uma grande quantidade de dados de forma escalável e com alta performance.

O site oficial da ferramenta é o https://spark.apache.org/

O Spark foi desenvolvido utilizando a linguagem Scala,  e pode ser utilizado com as linguagens ScalaPython ou Java, no site de exemplos temos uma variedade de exemplos de códigos em ambas as linguagens mencionadas, o intuito de poder utilizar diferentes linguagens, é que estas são as mais utilizadas em ambientes de grande quantidade de dados, além de fornecer opções para o desenvolvedor de acordo com seu skill.

Download do Spark

O primeiro passo é acessar https://spark.apache.org/downloads.html aqui encontramos todos os detalhes para o correto funcionamento da ferramenta, atualmente o Spark encontra-se na versão 2.3.0.

Site de download oficial do Apache Spark.

Um ponto importante aqui é que devemos ter o Java instalado na máquina, de acordo como site oficial, a versão da JVM recomendada é a 8.

O processo de instalação é o mesmo independente do Sistema Operacional, seja ele Linux, Windows ou Mac, basta efetuar o download e realizar a descompactação com um utilitário de preferência.

Como foi dito, após efetuar o download, basta descompactar em um diretório de sua preferência e teremos a seguinte estrutura:

Estrutura do Apache Spark após descompactação.

 Um ponto importante é a configuração da variável de ambiente chamada SPARK_HOME com o valor do diretório de instalação do Spark, isso é importante porque alguns utilitários do Spark utilizam esta variável como base para execução.


Conhecendo o Spark Shell

O Spark disponibiliza diversos shells, com eles podemos escrever códigos diretamente na linha de comando e acompanhar a execução, estes consoles estão disponíveis para Scala Python.

Como exemplo, vamos executar o console padrão que é o console chamado spark-shell onde você pode escrever códigos em Scala, o executável fica dentro do diretório bin/spark-shell.

Chamada do utilitário spark-shell

Ao executar teremos a seguinte resultado no terminal:

Console para execução de código Scala.

Neste console podemos utilizar todas as funcionalidades do Spark utilizando a linguagem Scala, geralmente este console é utilizado mais a critério de testes, porque para um grande projeto é recomendado o uso de alguma IDE ou ambiente que possua ferramentas de debug e testes.

O console possui alguns objetos implícitos disponíveis para uso, um deles é o principal, o SparkContext, este é o contexto responsável pela criação dos RDD que é a estrutura que utilizamos para manipular os dados dentro do Spark, para ver o SparkContext basta digitar no terminal sc:

Exibindo o SparkContext no console.

Após estes passos já temos o Apache Spark instalado e configurado.

Até a próxima.


Referências

Criando e Executando Funções no MongoDB

Olá pessoal, hoje iremos ver como realizar a criação e execução de funções dentro de uma base no banco de dados MongoDB.


Conhecendo o MongoDB

Nos dias atuais o tema NoSQL vem sendo muito discutido, muitas empresas vem adotando este paradigma de armazenamento, mas como toda tecnologia existem prós e contras, para entender bem o tema recomento a leitura do livro NoSQL Essencial (NoSQL Destilled) dos autores Promod J. Sadalage e Martin Fowler, o livro mostra características de aplicações, modelos de NoSQL, entre outras detalhes importantes sobre adoção de qualquer banco desse segmento.

O MongoDB é um banco de dados NoSQL baseado no modelo de documentos, onde cada registro é armazenado em forma de um documento BSON, uma característica muito legal do MongoDB é justamente trabalhar neste formato, porque o formato JSON é amplamente utilizado pela maioria dos desenvolvedores, sendo assim o entendimento da estrutura de armazenamento se torna simples.

Criando Funções no MongoDB

O MongoDB permite a criação de funções JavaScript dentro do banco, com isso podemos criar funções e executa-las manipulando nossas coleções e seus dados.

Um ponto muito importante que devemos ressaltar, seguindo boas práticas de desenvolvimento, devemos evitar de adicionar lógicas de negócio dentro dessas funções, o uso de funções deve ser efeito com a finalidade de manipular informações, evitando criar as famosas "Procedures" do mundo SQL.

No próprio site oficial do MongoDB, existe uma nota informando para usar as funções com cautela e evitar de acrescentar lógicas de negócio dentro do banco, pois existem limitações na execução de código JavaScript sobre o MondoDB.

https://docs.mongodb.com/manual/tutorial/store-javascript-function-on-server/index.html
(09/04/2018 ás 19:00)


Calculando o Tamanho de um Documento BSON

Para termos um exemplo do uso de funções no MongoDB, vamos criar uma função que retorna o tamanho de um documento de uma determinada coleção, para realizar a criação de funções, podemos utilizar a linha de comando logado na devida base de dados, ou utilizar alguma ferramenta como o Robomongo (Robo 3T), a função irá ficar como abaixo:


1
2
3
4
5
6
7
8
function(collectionName, _id) {
    
    var data = db.getCollection(collectionName).findOne({_id:_id});
    
    var result = Object.bsonsize(data);
    
    return result;
}

Perceba que é puro código JavaScript, na linha 1, temos a declaração da função, onde receberemos como argumento o collectionName (nome da coleção) e o _id (chave da coleção), na linha 3, executamos a busca do documento utilizando como critério o _id, na linha 5, utilizamos a função Object.bsonsize(), que retorna o tamanho em bytes do documento.

Para criar a função no Robomongo, basta seguir como abaixo:

Criando uma função utilizando a ferramenta Robomongo.

Existem outras maneiras de criar funções no MongoDB, para mais detalhes veja a documentação oficial: https://docs.mongodb.com/manual/tutorial/store-javascript-function-on-server/index.html


Executando uma Função

Agora vamos executar a função da seguinte maneira:

1
2
3
db.loadServerScripts();

documentSize("collection_teste", "123456");

Na linha 1, carregamos os scripts para que possam ser executados, na linha 3, executamos a função chamada documentSize(<<nome_coleção>>, <<valor_da_chave>>)

Executando no Robomongo temos o seguinte resultado:

Execução da função no Robomongo.

Na imagem acima foi executada a função retornando o devido resultado, as funções no MongoDB podem ajudar em atividades comuns na manipulação dos dados.

Até a próxima.

Referências

Lendo e Manipulando arquivos CSV com Java

Olá hoje veremos como realizar a leitura e manipulação de arquivos CSV com Java, mostrando que as novas versões da plataforma Java deixaram algumas tarefas simples de serem realizadas.


Exemplo de Arquivo

Hoje em dia é comum ao realizar integrações ou carga de dados o uso de arquivos CSV, isto porque, este arquivo possui uma estrutura de fácil entendimento e simples de manipular na maioria das plataformas de desenvolvimento.

Para realizar a leitura dos dados vamos manipular um arquivo com as seguintes colunas: namecpfagephone address:

name;cpf;age;phone;address
caio;123456789;20;1145223643;Avenida Paulista
vinicius;147852369;18;1125253625;Avenida Manoel
sandra;963258741;30;1174587858;Rua Teixeira
regina;125478522;40;1145254536;Rua Fernando 
fernando;785245563;42;1145253669;Rua Pereira
augusto;456123014;50;1125363633;Avenida Paulinia
maria;456123789;10;1125455525;Avenida Nossa Senhora

Para representar os dados em objetos Java iremos utilizar a seguinte classe:

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
@AllArgsConstructor
public class User {
 
 private String name, cpf;
 private Integer age;
 private String phone, address;
}

Realizando a Leitura do Arquivo

Para entender o processo de leitura do arquivo, vamos começar apenas exibindo os dados existentes, neste tutorial iremos utilizar a classes Files, que faz parte da NIO API da plataforma Java:

Files.lines(Paths.get("file.csv"))
     .forEach(System.out::println);

O Resultado desse trecho de código será o abaixo:

name;cpf;age;phone;address
caio;123456789;20;1145223643;Avenida Paulista
vinicius;147852369;18;1125253625;Avenida Manoel
sandra;963258741;30;1174587858;Rua Teixeira
regina;125478522;40;1145254536;Rua Fernando 
fernando;785245563;42;1145253669;Rua Pereira
augusto;456123014;50;1125363633;Avenida Paulinia
maria;456123789;10;1125455525;Avenida Nossa Senhora

Perceba que para lermos o conteúdo do arquivo o processo é muito simples, apenas utilizamos o método Files.lines, passando como argumento o Path do arquivo, após este processo podemos manipular o Stream<String> da forma que nosso programa necessita.

O Segundo passo da leitura será a remoção do cabeçalho do arquivo, isto porque, na maioria das importações oque realmente importa são os valores, vamos analisar como ficará o código:


Files.lines(Paths.get("file.csv"))
     .skip(1)
     .forEach(System.out::println);

Aqui foi adicionado ao pipeline a operação skip(1), que faz o primeiro item do Stream ser removido, sendo a linha contendo as informações de cabeçalho do arquivo:

caio;123456789;20;1145223643;Avenida Paulista
vinicius;147852369;18;1125253625;Avenida Manoel
sandra;963258741;30;1174587858;Rua Teixeira
regina;125478522;40;1145254536;Rua Fernando 
fernando;785245563;42;1145253669;Rua Pereira
augusto;456123014;50;1125363633;Avenida Paulinia
maria;456123789;10;1125455525;Avenida Nossa Senhora

Realizando conversões e lógicas com Stream API

Agora vamos adicionar a leitura do arquivo algumas operações mais complexas, a primeira será a conversão da linha em um Objeto do tipo User:


1
2
3
4
5
Files.lines(Paths.get("file.csv"))
     .skip(1)
     .map(line -> line.split(";"))
     .map(col-> new User(col[0], col[1], Integer.parseInt(col[2]), col[3], col[4]))
     .forEach(System.out::println);

Aqui utilizamos da operação map() da Stream API, que é utilizada para realizar transformações de dados, na linha 3 é realizado a transformação da linha do arquivo em um Array de colunas, isto utilizando o método split(";"), onde o ; é o caractere utilizado como quebra, já na linha 4, passamos os dados do String[] para o construtor da classe User, o resultado será o abaixo:


User(name=caio, cpf=123456789, age=20, phone=1145223643, address=Avenida Paulista)
User(name=vinicius, cpf=147852369, age=18, phone=1125253625, address=Avenida Manoel)
User(name=sandra, cpf=963258741, age=30, phone=1174587858, address=Rua Teixeira)
User(name=regina, cpf=125478522, age=40, phone=1145254536, address=Rua Fernando )
User(name=fernando, cpf=785245563, age=42, phone=1145253669, address=Rua Pereira)
User(name=augusto, cpf=456123014, age=50, phone=1125363633, address=Avenida Paulinia)
User(name=maria, cpf=456123789, age=10, phone=1125455525, address=Avenida Nossa Senhora)

Agora vamos utilizar a Stream API para aplicar alumas lógicas, vamos exibir todos os usuários que tenham mais que 30 anos:

1
2
3
4
5
6
Files.lines(Paths.get("file.csv"))
     .skip(1)
     .map(list -> list.split(";"))
     .map(str -> new User(str[0], str[1], Integer.parseInt(str[2]), str[3], str[4]))
     .filter(usr -> usr.getAge() > 30)
     .forEach(System.out::println);

Aqui utilizamos o operação de filter, onde na linha 5, passamos como parâmetro uma expressão lambda com a regra para exibir apenas objetos User que tenham o getAge() > 30, o resultado será o abaixo:

User(name=regina, cpf=125478522, age=40, phone=1145254536, address=Rua Fernando )
User(name=fernando, cpf=785245563, age=42, phone=1145253669, address=Rua Pereira)
User(name=augusto, cpf=456123014, age=50, phone=1125363633, address=Avenida Paulinia)

Após estes exemplos podemos notar como é simples a leitura de arquivos CSV com Java, vale ressaltar que existem várias outras maneiras e formas de realizar esta leitura, sendo que devemos analisar qual a melhor forma dependendo do tamanho do arquivo, e lógicas que queremos aplicar nos resultados.

Até a próxima.

Código fonte

Referências

Versionamento de Banco Dados com Flyway

Olá pessoal, hoje iremos analisar e aprender como realizar o versionamento e gerenciamento das bases de dados relacionais utilizando o framework Flyway.

Versionamento de Banco Dados

Ao trabalhar com desenvolvimento de sistemas é comum realizarmos o versionamento, isso porque uma aplicação pode necessitar de correções, novas funcionalidades e evoluções, onde para garantir a compatibilidade e cuidar do seu ciclo de vida, geramos versões onde é especificado quais itens estão presentes em cada release.

Vamos imaginar seguinte cenário:
  • Sistema ERP
    • 1.0.0: Entrega dos módulos Financeiro e RH;
    • 1.1.0: Entrega do módulo Contas a Receber.
Perceba que a ideia é controlar o que cada versão possui de diferente, e para controlar essas mudanças no lado da aplicação existem várias técnicas e ferramentas, mas e para controlar as mudanças no lado do Banco de dados ? 

Para isso podemos utilizar ferramentas de versionamento que ajudam a realizar este controle, a ferramenta que iremos utilizar é o Flyway.

Conhecendo o Flyway

O Flyway é um framework que permite o versionamento e gerenciamento do Banco de dados, com ele podemos controlar a evolução dos elementos que compõem uma determinada base de dados, sendo eles Tabelas, Sequences, Views, entre outros.

Site oficial: https://flywaydb.org/

Podemos utilizar o Flyway para manipular diferentes sistemas de Banco de dados relacionais, isso é possível porque ele é desenvolvido baseado na API JDBC onde basta especificar o Driver do banco e realizar as migrações.

O Flyway pode ser utilizado através de linha de comando, ou utilizando ferramentas como Maven, Gradle, Ant, SBT, entre outras.

Utilizando Flyway através da Linha de Comando

Download

Para começar, vamos realizar o download do Flyway https://flywaydb.org/download/, a versão corrente é a 5.0.7

Descompactação

Após realizar o download para o S.O desejado, basta descompactar e teremos a seguinte estrutura:

Estrutura do Flyway após descompactação.

Configurando flyway.conf

O próximo passo é a configuração da conexão entre o Flyway e a base de dados, para este exemplo tenho uma base de dados chamada erp criada no PostgreSQL:

Base de dados chamada ERP no PostgreSQL.

Para configurar temos de editar o arquivo localizado em conf/flyway.conf,  nele adicionamos as configurações para realizar a migração, informações como url de acesso, usuário, senha, entre outras.

As partes principais que devemos configurar são:
  • flyway.url
    • Aqui colocamos os dados de conexão baseados na API JDBC, no caso usamos PostgreSQL, então ficaria: jdbc:postgresql://<host>:<port>/<database>
  • flyway.driver
    • Nesta tag adicionamos o Driver de conexão, no caso do PostgreSQL seria: org.postgresql.Driver
  • flyway.user
    • Usuário para se conectar a sua base de dados;
  • flyway.password
    • Senha de acesso a base de dados.
Não esqueça de remover o # da frente das tags mencionadas acima.

Um item muito importante, é que devemos adicionar o jar do Driver do banco de dados utilizado dentro do diretório jars, no caso adicionamos o jar do PostgreSQL, caso não saiba onde efetuar o download acesse https://mvnrepository.com/ e faça uma pesquisa pelo nome do seu banco de dados.

Criando os Scripts

Os scripts são criados utilizando a linguagem SQL ou através de uma API Java, neste exemplo utilizaremos SQL, o Flyway segue uma convenção para o nome dos Scripts, que é V{numero da versão}__<nome_do_script>.sql, estes scripts devem ser adicionados dentro do diretório sql.

Nosso primeiro script de migração será V1.0.0__criacao_estrutura_inicial.sql, e terá o seguinte conteúdo:

create table usuario(
 id serial primary key,
 nome varchar(50) not null,
 login varchar(50) not null,
 senha varchar(50) not null
);

create table produto(
 id serial primary key,
 titulo varchar(50) not null,
 valor numeric(10, 2) not null
);

Agora através da linha de comando e estando dentro do diretório do Flyway, devemos executar o seguinte comando: flyway migrate, o resultado será o abaixo:

Resultado da execução do primeiro script.

Estrutura criada na base de dados ERP.

Após a execução o Flyway realizou a criação de uma tabela adicional, chamada flyway_schema_history, esta tabela o framework utiliza para gerenciar o histórico dos Scripts executados.

Agora vamos incrementar nosso banco de dados realizando a criação de uma nova tabela, para isso iremos criar o script V1.1.0__criando_a_estrutura_pedidos.sql, com o seguinte conteúdo:

create table pedido(
 id serial primary key,
 data timestamp not null
);

create table pedido_itens(
 pedido_id integer references pedido(id),
 produto_id integer references produto(id)
);

Agora basta executar novamente o comando flyway migrate, após realizar todas as migrações vamos analisar a estrutura da tabela flyway_schema_history:


Resultado na tabela de histórico de migrações.

Após todo esse processo temos o banco de dados com versionamento, mantendo todo o histórico de evoluções facilitando o gerenciamento das aplicações.

Até a próxima.

Referências