Sunday, January 11, 2015

Construindo um CRUD com Spring, REST e Mongo DB parte 4

Passo 4 – Repositórios com MongoDB


Neste último passo, a persistência em memória será trocada por uma solução NoSQL. Para que esse passo funcione, deve-se instalar primeiramente o MongoDB. Não foi necessária nenhuma configuração adicional, tais como local de dados, journaling, logs, entre outros. Decida essas configurações do modo que for melhor.

MongoDB é um banco de dados baseado em documentos da geração NoSQL, que significa não estar preso ao modelo relacional. No entanto, existem problemas que nos bancos relacionais não existem, tais como atualizações não garantidas ou a falta de um relacionamento mais forte, por exemplo.

Por outro lado, não se está preso em um modelo pré-definido de uma tabela de dados, com regras restritivas para trabalhar com eles. Cada registro de uma entidade pode ter suas próprias regras existindo ou não alguns campos preenchidos. Não há a necessidade de atribuir a um campo um valor null, porém essas informações devem ser tratadas na aplicação de alguma forma.

Especificamente o banco de dados MongoDB, trabalha com documentos de dados BSON, um formato derivado do JSON. Também chamado de binary JSON, esse formato foi projeto para ser eficiente em armazenamento e leitura de informações.

Para lidar com MongoDB, deve-se adicionar algumas dependências do Spring que lidam com banco de dados e com o banco de dados em questão. Deve-se alterar o código fonte em alguns pontos da aplicação para essa adaptação.

Deve-se, primeiramente, adicionar as dependências do Spring-data e do MongoDB no pom.xml. Note que no passo anterior não foi adicionado o Spring-data, pois os dados foram gravados em memória.

(1)
groupId.....: org.springframework.data
artifactId..: spring-data-mongodb
version.....: 1.7.0.DATAMONGO-1118-SNAPSHOT

(2)
groupId.....: org.mongodb
artifactId..: mongo-java-driver
version.....: 2.12.4

O segundo passo é alterar as configurações da classe AppConfig. Deve-se:

  1. Habilitar os pacotes de repositórios, onde se encontrarão as classes de repositório.
  2. Configurar o MongoDB para ser injetado, com configurações oriundas de um arquivo de propriedades.
  3. Retirar a configuração do DAO persistente em memória e apagar as classes

A listagem a seguir mostra os trechos de código a serem considerados:

@Configuration
@PropertySource("classpath:mongodb.properties")
@EnableMongoRepositories(basePackages = "org.crudpeople.repositories")
@ComponentScan(basePackages={"org.crudpeople.controller", "org.crudpeople.service"})
public class AppConfig extends WebMvcConfigurationSupport {

(…)

@Bean
public Mongo mongo() throws UnknownHostException {
return new
MongoClient(
environment.getProperty("database.host")
);
}

@Bean
public MongoTemplate mongoTemplate() throws UnknownHostException {
return new MongoTemplate(mongo(),
environment.getProperty("database.name"));
}
}

Desse modo, toda vez que o servidor estiver no ar, uma conexão com o banco de dados será realizada.

O próximo passo ainda é alterar a entidade para que ela represente um documento no banco de dados MongoDB. Temos que entender que o MongoDB possui um banco de dados, que abriga coleções, que abriga documentos. Neste projeto temos a estrutura descrita na imagem a seguir.


Na classe de configuração foi descrito em qual banco conectar. Na entidade, deve-se anotar que ela é um documento, com a anotação @Document, e a qual coleção pertence esse documento. A listagem abaixo mostra a entidade Pessoa anotada como documento.

@Document(collection = "pessoas")
public class Pessoa {

(…)

}

O que ainda deve ser modificado nessa classe é o ID, cujo tipo deve ser mudado para String. Será aproveitado o id que o MongoDB gera automaticamente para cada documento BSON em uma forma alfanumérica lembando um UUID. Existem formas de implementar um id numérico e sequencial, mas não estamos lidando com bancos de dados sequenciais, e sim com um NOSQL.

O próximo passo é criar a interface de repositório e criar ela no pacote onde foi configurado. Um repositório é uma abstração que o Spring provê para acesso a dados de uma entidade. Não é necessário implementá-la, somente quando existir a necessidade de fazer alguma operação não previstas pelo interface MongoRepository.

@RepositoryDefinition(
domainClass=org.crudpeople.entities.Pessoa.class,
idClass=java.lang.String.class)
public interface PessoaRepository extends MongoRepository{
}

Pronto. Já temos nosso repositório. Nossa camada de persistência está pronta e configurada.

Algumas correções de código devem ser feitas no próximo passo. As classes estarão com algum problema de tipos ou membros do tipo PessoaDAO. Corrigindo esses probleminhas fará com que a aplicação se torne compilável novamente. Existem dois pontos que devem ser considerados nessa migração.

O primeiro ponto é na classe PessoaService no método find, que é responsável por procurar por parte de um nome. Com o repositório não é tão trivial. Deve-se criar um objeto Query e definir os parâmetros. A listagem abaixo mostra a implementação da solução.


public List find(String nome) {
LOGGER.log(Level.INFO, "find");
Query query = new Query();
query.addCriteria(Criteria.where("nome").regex(nome));
return mongoTemplate.find(query, Pessoa.class);
}

Outra modificação é uma alteração pequena na tela de alteração. Ao inicializar a tela, busca-se um registro de pessoa pelo seu id. O problema é que o id gerado pelo MongoDB é alfanumérico e isso atrapalha um pouco o AngularJS. Para resolver esse problema foi colocado o parâmetro do método findById em aspas simples. A listagem abaixo mostra a solução encontrada.

findById('${param['id']}')

Para verificar os registros cadastrados no console do mongo devemos usar a seguinte lista de comandos:

Inicia o console do mongodb

mongo

Usa o banco de dados PessoasDB

use PessoasDB

Pesquisa por todos os documentos na coleção pessoas

db.pessoas.find()

O resultado é:

{ "_id" : ObjectId("54b2ee7744ae7df913204e75"), "_class" : "org.crudpeople.entities.Pessoa", "nome" : "Homer Simpson", "endereco" : "Rua Evergreen Terrace, 742", "telefone" : "(11)12345-1234" }
{ "_id" : ObjectId("54b2ef1644ae7df913204e76"), "_class" : "org.crudpeople.entities.Pessoa", "nome" : "Sheldon Cooper", "endereco" : "Rua Los Robles, 2311", "telefone" : "(11)12345-1234" }
{ "_id" : ObjectId("54b2ef3a44ae7df913204e77"), "_class" : "org.crudpeople.entities.Pessoa", "nome" : "Sherlock Holmes", "endereco" : "Rua Baker, 221B", "telefone" : "(11)12345-1234" }
{ "_id" : ObjectId("54b2ef8144ae7df913204e78"), "_class" : "org.crudpeople.entities.Pessoa", "nome" : "Frd Flintstones", "endereco" : "Rua Cobblestone, 301", "telefone" : "(11)12345-1234" }
{ "_id" : ObjectId("54b2efcb44ae7df913204e79"), "_class" : "org.crudpeople.entities.Pessoa", "nome" : "Peter Griffin", "endereco" : "Rua Spooner, 31", "telefone" : "(11)12345-1234" }
{ "_id" : ObjectId("54b2f00244ae7df913204e7a"), "_class" : "org.crudpeople.entities.Pessoa", "nome" : "Stan Smith", "endereco" : "Rua Cherry, 1024", "telefone" : "(11)12345-1234" }
{ "_id" : ObjectId("54b2f05f44ae7df913204e7b"), "_class" : "org.crudpeople.entities.Pessoa", "nome" : "Charles Xavier", "endereco" : "Pista Graymalkin, 1407", "telefone" : "(11)12345-1234" }


Note que o id, chamado de _id, é um objeto do MongoDB chamado ObjectId e é uma chave hexadecimal UUID. Esse é o id da entidade Pessoa. Adicionalmente, o framework Spring-data MongoDB grava o nome da classe Java que foi usada.

Para acessar o código do projeto no branch do Passo 4, basta baixar o zip no endereço https://github.com/ortolanph/CRUDPeople/tree/passo04.

Conclusão


O framework spring ajuda muito a tirar a complexidade do código, fazendo o programador a focar no negócio. Não é necessário pensar em servlets, abrir conexões com o banco de dados, pensar em como um grafo de objeto deve ser montado. Somente deve ser pensado uma vez e usar no projeto inteiro. O framework faz o resto.

O framework AngularJS ajuda muito a criar uma página web. Não é necessário mais utilizar snippets java para adicionar uma funcionalidade. Basta utilizar o AngularJS para montar uma tabela, trazer dados de um serviço para a tela e ainda obter atualizações em tempo real. Isso ainda sem pensar em tags JSF.

Criar uma aplicação com esses dois frameworks deixa a vida do desenvolvedor um pouco mais fácil. A parte mais importante ainda é fazer o algoritmo do sistema. Mas esses posts criam uma aplicação exemplo, nada real. Deve-se fazer uma prova de conceito, medindo tempo de desenvolvimento, complexidade de implementação e complexidade de integração com outras aplicações com outras tecnologias.

O importante é dar certo!

1 comment:

  1. amigo muito bom seu post, estou seguindo seu blog, se puder siga meu blog também obrigado e espero novas postagens linuxbugone.blogspot.com.br

    ReplyDelete

Let me know your opinion