Imagine aquela sexta feira que você chegou em casa depois de uma semana cheia do trabalho e não quer fazer nada para comer, nem sair para comer. Você pede aquela pizza. Mesmo que coma em companhia de alguém, podem haver sobras.
Então você coloca as sobras na geladeira na esperança daqueles pedaços congelados virarem seu café da manhã, almoço ou jantar. No entanto, você lembra que fez alguns compromissos e que vai demorar um dia para voltar para casa.
Você volta sábado à noite e lembra que existe a pizza parada na geladeira, mas está cansado demais para fazer algo. Domingo você levanta e tem aquele almoço com a família. Você passa à tarde assistindo TV ou fazendo qualquer outra coisa. À noite você está em sua casa e lembra da sobra da pizza. Você olha para aqueles pedaços e fica pensando: "Será que não está estragado?".
Você se livra das sobras, jogando no lixo.
Imagine agora quando você faz aquela reforma na sua casa. Você compra tinta, azulejos, piso, cimenta, madeira, massa corrida, vidro, etc. Para que dê tudo certo, compra um pouco a mais da quantidade necessária, pois sabe que imprevistos podem ocorrer e guarda um pouco para futuros reparos.
Nesse caso, o material de construção só ocupará um pouco de espaço na sua casa em algum canto esquecido pelo tempo. De tempos em tempos você deve revisitar aquele material para garantir que nenhum passou da data de validade, se tiverem.
Agora você está em um projeto de software. Sua equipe está desenvolvendo um sistema, funcionalidade por funcionalidade. Independente da metodologia adotada, seu sistema é submetido à testes com o cliente e erros são registrados. Fácil, se o Product Owner achar melhor, ele transfere esses erros como backlog do sistema.
Mas vamos imaginar que o PO deixa esses erros para depois, para sprints posteriores. Ele decide "deixar na geladeira" ou naquele "canto esquecido pelo tempo". Os sprints passam e aqueles itens de backlog são revisitados sempre. Eles ficam com a promessa de sair da geladeira para o microondas ou de serem utilizados para serem utilizados para algum reparo.
É claro que na metodologia ágil, com algum processo de integração contínua, o código é sempre testado e a equipe de desenvolvimento sempre fica sabendo o que acontece. Mas às vezes o problema não é visível para os testes. Os problemas foram deixados para trás, pois não são testáveis unitariamente, são problemas de interface com o usuário que foram classificados como irrelevantes e ficaram congelados em um canto escuro para serem corrigidos depois.
E aí? Não dá para jogar fora e não dá para deixar em um canto esquecido. São sobras de software. Alguém vai ter que corrigir, alguém vai ter que ficar com as sobras. Ficar procurando por um culpado é inútil. Foi o Product Owner que deixou coisa sem corrigir para trás, pois não achava importante para o negócio, foi o Scrum Master que não teve iniciativa de brigar e puxar os problemas para o sprint atual e se comprometer em entregar menos, ou ainda a equipe que não alertou tecnicamente o PO.
Ou foi a empresa que determinou algo como prioritário ou não prioritário? O importante é que alguém vai ter que ficar com as sobras e isso não é bom. Sobras de software são duradouras e vão sempre incomodar, vir à tona e cheirar mal.
Não deixe que essas sobras venham incomodar.
Sunday, June 14, 2015
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:
- Habilitar os pacotes de repositórios, onde se encontrarão as classes de repositório.
- Configurar o MongoDB para ser injetado, com configurações oriundas de um arquivo de propriedades.
- 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!
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!
Wednesday, January 7, 2015
Construindo um CRUD com Spring, REST e Mongo DB parte 3
Passo 3 – A persistência em memória
O pincipal objetivo desse passo não
foi me atentar à persistência, mas sim a criação de serviços
para criar um CRUD, a criação da interface com o usuário e ligar
os serviços com o AngularJS.
Para armazenar os dados, criei uma
interface e uma implementação para o meu DAO em memória para que
fosse administrado pelo Spring. Desse modo, na classe AppConfig,
somente adicionei um método para criar meu DAO. O que preciso fazer
é criar um atributo em alguma classe chamado pessoaDAO do tipo
PessoaDAO e anotar com @Autowired. Ipso facto magico! O Spring vai
injetar essa dependência para você. Segue o código do Bean do
spring na classe AppConfig na listagem abaixo:
@Bean
public PessoaDAO pessoaDAO() {
return new PessoaDAOImpl();
}
A implementação do meu DAO nada mais
é do que a utilização de uma lista parametrizada da classe Pessoa,
com métodos de inserção, deleção, alteração e busca, ou seja
um CRUD.
Não é o ideal, pois quando o servidor
é desligado, todos os dados são descartados. Tudo estará
registrado enquanto o servidor estiver no ar.
Após a criação do DAO, criei as
telas de inclusão, pesquisa e alteração de pessoas. Poderia ter
usado uma tela só para inclusão e alteração, mas queria ter algo
mais didático.
A página de pesquisa possui um campo
para pesquisa por nome ou parte de um nome. Ao acionar o botão de
pesquisa, o script irá verificar se o campo foi preenchido para
chamar serviços diferentes. Se o campo não for preenchido, a
aplicação irá pesquisar por todos os registros, senão pesquisará
aqueles registros que possuem aquela parte do nome.
A figura a seguir exibe a tela de
resultados para uma parte do nome.
Os registros são exibidos nas linhas
da tabela. Cada linha contém o nome com um link para alteração, o
endereço, o telefone e a palavra excluir, que chama o serviço para
exclusão de um registro, transmitindo seu id e ao retornar refaz a
pesquisa. Caso haja algum problema, uma mensagem de erro aparece e os
resultados permanecem inalterados.
A tela de cadastro é simples. Não
existe mistério. A única coisa a se observar é no script quando é
chamado o método POST do objeto $http do AngularJS. O método POST
necessita de um parâmetro adicional, que são os dados do POST. A
listagem abaixo mostra a construção dos parâmetros.
$scope.createPessoa = function
() {
console.log('Calling URL: '
+ $scope.defaultUrl + 'create');
var data = {'nome':
$scope.nome, 'endereco': $scope.endereco, 'telefone': $scope.telefone};
console.log('Data: ' +
data);
$http.post($scope.defaultUrl + 'create', data)
.success(function
(data) {
console.log('[OK]');
$scope.message
= data;
})
.error(function
(data, status) {
console.log('[FAIL]');
$scope.message
= {'result' : data + status};
});
};
Uma variável data é criada a partir
das informações do formulário, que serão transmitidas em formato
JSON.
Essa não é o único lugar que deve
mudar. A interface agora está enviando dados em formato JSON e a
aplicação também deve receber informações em formato JSON. Para
o método create deve-se anotar conforme a listagem abaixo:
@RequestMapping(value = "/create",
method = RequestMethod.POST,
consumes = {"application/json;charset=UTF-8"})
method = RequestMethod.POST,
consumes = {"application/json;charset=UTF-8"})
public @ResponseBody
SimpleResult create(@RequestBody
Pessoa pessoa) {
LOGGER.log(Level.INFO, "Serviço
/create");
service.create(pessoa);
SimpleResult result = new
SimpleResult();
result.setResult("Pessoa
cadastrada com sucesso!");
return result;
}
Duas coisas são importantes de se
ressaltar:
1. consumes =
{"application/json;charset=UTF-8"}
Isso indica que agora nosso método
aceita informações em formato JSON
2. @RequestBody Pessoa pessoa
Isso indica que o objeto deve ser
compatível com os atributos da classe Pessoa. Existindo essa
combinação, não é necessário fazer mais nada.
A imagem a seguir mostra a tela de
cadastro:
Por fim, a tela de alteração. Toda
vez que o usuário clicar no link onde está o nome, será
encaminhado para a tela de alteração levando no parâmetro, o id da
Pessoa. Ao iniciar, o id será pesquisado e populará todos os
campos. O id é um campo hidden que eu deixa à vista para fins
didáticos. No próximo passo vou mostrar que ele pode conter mais do
que imaginamos.
Ao pressionar o botão de alteração,
o mesmo mecanismo para a inserção de registros será executado,
somente mudando o nome do serviço para alteração e não inclusão.
A imagem a seguir mostra a tela de
alteração:
Basicamente o fluxo de trabalho desse
passo é dado pelo diagrama de sequência abaixo. Ao fazer um submit
na página, o controlador Javascript utiliza o recurso $http do
AngularJS que chama um controlador em java, que por sua vez chama um
serviço Java que, por sua vez chama a camada de persitência. A
clássica arquitetura em três camadas.
Para o próximo passo, será utilizado
o banco de dados MongoDB em vez de um banco de dados em memória.
Tuesday, January 6, 2015
Construindo um CRUD com Spring, REST e Mongo DB parte 2
Passo 2 – Integração entre serviços e interface web
O objetivo do segundo passo é de
consumir os serviços criados utilizando AngularJS, um framework
Javascript que melhora o HTML estático adicionando atributos e
ligando o modelo de dados com as atualizações do servidor. Escolhi
AngularJS por ser leve, direto e rápido. Não é tão trivial no
início, mas depois de um começo, seu uso se torna intuitivo.
Anteriormente, havia criado alguns
serviços que foram chamados pela barra de endereços do browser.
Tive que encapsular seus retornos para que formassem um objeto JSON.
Isso facilitou a minha camada de visão quando foi chamado pelo
AngularJS.
As listagens abaixo mostram os retornos
dos serviços em formato JSON:
Serviço:
/crudpeople/testservice/test
Retorno:
{
result:
"testing"
}
(2)
Serviço:
/crudpeople/testservice/echo/{message}
Retorno:
{
result: "message"
}
(3)
Serviço:
/crudpeople/testservice/api
Retorno:
{
result: [
"/crudpeople/testservice/test",
"/crudpeople/testservice/echo/{message}",
"/crudpeople/testservice/api"
]
}
Esses serviços vão ser manipulados
pelo framework AngularJS, utilizando a linguagem Javascript.
Primeiramente, para começar a utilizar
o Angular devemos referenciar o script que está publicado na
internet. A tag script referencia a URL
https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js
para o uso do angular. Depois devemos nosso próprio arquivo de
controlador para podermos usar nossa aplicação. Novamente utilizo a
tag script, agora para referenciar o meu script services.js.
Meu script, possui alguns elementos
referentes ao AngularJS. A primeira linha indica que meu script é um
módulo do angular com o nome de serviceTestApp. A listagem abaixo da
primeira linha ilustra exatamente isso:
var serviceTestApp =
angular.module('serviceTestApp', []);
Agora referencio meu módulo na página,
utilizando a notação ng-app na tag html da minha página. O trecho
abaixo mostra essa transformação.
html ng-app=”serviceTestApp”
O passo seguinte é construir um
controlador para minha aplicação. Construo o controlador chamado
TesteController a partir de módulo AngularJS serviceTestApp.
serviceTestApp.controller('TesteController',
['$scope','$http', function($scope, $http) {
['$scope','$http', function($scope, $http) {
// Insira código aqui
}]);
}]);
O trecho acima mostra que criei um
controlador chamado TesteController. Ele possui duas variáveis do
AngularJS que serão injetadas em sua criação: $scope e $http.
$scope conversa com a minha página, transmitindo objetos JSON,
Strings e variáveis. Por essa variável, existe uma conversa
bidirecional com o meu negócio. Qualquer atualização na página
detectada, o $scope é atualizado. $http é meu objeto para
comunicação com meus serviços. Posso utilizar os métodos GET,
POST, JSONP, por exemplo, para consumir os serviços criados.
Voltando à minha pagina, na tag body,
defino que tenho um controlador chamado TesteController e que toda a
tramitação de dados será controlada a partir desse escopo. Posso
ter um controlador que vai servir a um escopo somente em um div ou
span, mas isso seria restringir ao máximo o uso do AngularJS. O
trecho abaixo mostra a ligação do controlador com a tag body.
body ng-controller=”TesteController”
Desse modo, o AngularJS está pronto
para ser utilizado, ou seja, pronto para ligar a interface gráfica
aos serviços implementados.
Do lado do cliente, os serviços são
chamados utilizando uma rotina bem parecida. A listagem a seguir
mostra esse algoritmo:
$scope.defaultUrl =
"http://localhost:8080/crudpeople/testservice/";
$scope.test = function() {
console.log('Calling URL: '
+ $scope.defaultUrl + 'test');
$http.get($scope.defaultUrl
+ 'test')
.success(function(data,
status) {
console.log('[OK]');
$scope.testReturn =
{'message' : data.result, 'status': status };
})
.error(function(data,
status) {
console.log('[FAIL]');
$scope.testReturn =
{'message' : data, 'status': status };
});
};
A rotina define uma variável do
controller chamada defaultUrl que contém o caminho padrão para
todos os serviços. Desse jeito, basta acrescentar qual o serviço
que se deseja acessar.
O método get do objeto $http define
duas funções de callback: success que é executado quando tudo
ocorre bem e error, quando existe algum problema. Existem outros
parâmetros para esses métodos, mas decidi usar somente os dois mais
significativos.
Do lado do servidor, quase nada mudou.
Agora os métodos retornam um objeto que encapsula as mensagens. No
entanto, uma coisa se faz necessária antes de subir o servidor:
transformar o retorno em JSON. Os objetos devem possuir uma anotação
do framework Jackson que é a
@JsonInclude(JsonInclude.Include.NON_NULL). Essa anotação permite
que o objeto anotado como @ResponseBody no controller seja
transformado em JSON quase que magicamente. O parâmetro
JsonInclude.Include.NON_NULL informa ao Jackson que os campos nulos
deverão ser ignorados.
A seguir são mostradas as telas de
teste dos serviços com os respectivos resultados:
Para acessar o código do projeto no
branch do Passo 2, basta baixar o zip no
endereço https://github.com/ortolanph/CRUDPeople/tree/passo02.
Construindo um CRUD com Spring, REST e Mongo DB parte 1
Apresentação
Construir aplicações web é complicado. Quando se fala em Java, a coisa fica um pouco mais difícil, pois existem várias e várias soluções. Existem frameworks que facilitam a vida do programador, prometendo evitar boilerplate code, o código que lida com tecnologia.
Quando comecei o programar em Java para web tudo era difícil: não existia uma ferramenta para me ajudar com o deploy (logo após a conclusão do meu projeto veio o Ant), programava utilizando servlets (logo após veio o Struts) e não exisitia um jeito de gerenciar minhas dependências (o Maven ainda demorou um pouco para chegar).
Hoje temos um cardápio imenso de frameworks que evitam que o programador coloque a mão em tecnologia e preste atenção mais no negócio. Essa série de blogs tem a intenção de mostrar uma das soluções que usei para implementar um pequeno CRUD bem básico.
No primeiro post (este aqui), vou apresentar como construir as fundações do projeto. Como configurar o Spring MVC, quais as características que usei e subir um servidor Jetty para exemplificar.
No segundo post, vou apresentar como publicar um serviço rest e consumi-lo utilizando AngularJS, um framework MVVM da Google.
No terceiro post, vou apresentar uma implementação do CRUD utilizando dados em memória, ou seja List. Isso ainda é tecnologia, mas o melhor há por vir!
No quarto e último post, vou retirar essa implementação da persistência em memória e substituir por uma solução com Repositories e MongoDB.
Vamos lá para o primeiro post então!
Passo 1 - Criação da Estrutura do Projeto
Para iniciar, usei a IDE Netbeans e criei um projeto WEB, sem servidor pré-definido. Minha intenção é ter um projeto livre de servidor, pronto para eu fazer um deploy em qualquer servidor. Escolhi o servidor Jetty que pode ser inicializado com o Maven.
Depois disso alterei o pom.xml para colocar as dependências do Spring. Segue a tabela com as dependências do Spring.
(1)
groupId.....: javax
artifactId..: javaee-web-api
version.....: 7.0
scope.......: provided
(1)
groupId.....: javax
artifactId..: javaee-web-api
version.....: 7.0
scope.......: provided
(2)
groupId.....: org.springframework
artifactId..: spring-core
version.....: 4.1.1.RELEASE
(3)
groupId.....: org.springframework
artifactId..: spring-context
version.....: 4.1.1.RELEASE
(4)
groupId.....: org.springframework
artifactId..: spring-context-support
version.....: 4.1.1.RELEASE
(5)
groupId.....: org.springframework
artifactId..: spring-webmvc
version.....: 4.1.1.RELEASE
Para que o maven consiga resolver as dependências do spring de forma correta, adicionei a tag repositories para o meu pom.xml, conforme tabela abaixo.
(1)
id..: SpringSource Snapshots
url.: http://repo.springsource.org/libs-snapshot
enabled: true
(2)
id..: SpringSource Milestones
url.: http://repo.springsource.org/libs-milestone
Para iniciar o framework Spring de uma forma programática, criei uma classe chamada AppConfig.java. Essa é uma classe de configuração que elimina a necessidade do arquivo de configuração xml. Ela começa com a annotation @Configuration assinalando que essa classe é de configuração do Spring. Utilizei a annotation @ComponentScan para que o Spring verificasse em alguns pacotes os meus componente de serviço e meus controladores.
Ainda sobre inicialização, criei a classe CRUDPeopleWebInitializer.java que implementa WebApplicationInitializer do framework Spring. Essa classe é responsável pela criação de todos os objetos de minha configuração e inseri-las em um contexto do Spring.
Para publicar meu serviço inicial, criei a classe TestController.java, que publica somente três serviços:
- http://localhost:8080/crudpeople/testservice/test
- http://localhost:8080/crudpeople/testservice/echo/{message}
- http://localhost:8080/crudpeople/testservice/api
Ao acessar o primeiro serviço, o usuário receberá a mensagem testing na tela. O segundo serviço deve ter uma mensagem que será replicada. O terceiro serviço irá mostrar um array das URLs listadas acima.
Anote com @Controller sua classe para que ela vire um componente do Spring. Anote a classe com @RequestMapping para que os métodos passem a ser vistos como um serviço. Adicione um valor padrão que será considerado como um caminho raiz para cada serviço a ser publicado. Indiquei que todos meus serviços produzem uma resposta em JSON. O código abaixo exemplifica o uso dessa anotação:
@RequestMapping(value = "/crudpeople/testservice/*",
produces = {"application/json;charset=UTF-8"})
Para cada método público que quero publicar como serviço, anoto novamente com @RequestMapping, porém, dessa vez, digo para ele qual o nome do meu serviço a ser publicado. Como exemplo, o meu serviço test:
@RequestMapping(value = "/test", method = RequestMethod.GET)
public @ResponseBody
String test() {
LOGGER.log(Level.INFO, "Callling /test service");
return "testing";
}
Preciso indicar qual o nome do meu serviço (value) e qual o método pelo qual ele será chamado (RequestMethod.GET). Note que ainda existe uma outra anotação @ResponseBody antes do retorno na assinatura do método, o que indica que quando meu método retornar alguma coisa ele retornará o objeto que o método retorna. Poderia criar um objeto mais complexo, ao invés de retornar uma String, mas meu objetivo agora é somente testar a publicação de serviço.
Para acessar, devemos iniciar o servidor Jetty utilizando o maven pela linha de comando. Se gosta de utilizar sua IDE para executar o maven, não existe problemas. Iniciando pela linha de comando deve-se digitar, no diretório raiz do projeto, onde se encontra o arquivo pom.xml:
mvn dependency:resolve clean install jetty:run
O que faz o Jetty ser executado é um plugin na tag build do arquivo pom.xml. Seguem as informações do plugin:
Defini uma propriedade para a variável ${jetty.maven.plugin} = 8.1.5.v20120716.
Se tudo der certo (e qual a razão de não dar certo?) é possível acessar essas URLs em seu browser. Use o Chrome para uma melhor renderização. As figuras abaixo mostram o resultado desse primeiro passo.
Para acessar o código do projeto no branch do Passo 1, basta baixar o zip no endereço https://github.com/ortolanph/CRUDPeople/tree/passo01.
Para acessar o código do projeto no branch do Passo 1, basta baixar o zip no endereço https://github.com/ortolanph/CRUDPeople/tree/passo01.
Próximo passo, usar AngularJS para consumir os serviços e exibir os resultados no browser.
Subscribe to:
Posts (Atom)