Académique Documents
Professionnel Documents
Culture Documents
Ivan Salvadori
Esse livro est venda em http://leanpub.com/javawebapis
Essa verso foi publicada em 2016-03-26
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
2016 Ivan Salvadori
Contedo
Sobre Este Livro .
Pblico Alvo .
Pr-requisitos
Recursos . . .
Sobre o Autor
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
i
i
i
i
i
Introduo . . . . . . . . . . . . .
Web APIs . . . . . . . . . . . .
Princpios Arquiteturais REST
Jersey . . . . . . . . . . . . . .
Spring Boot . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
3
4
6
Projeto . . . . . . . . . . . . . . . . . . .
Viso Geral . . . . . . . . . . . . . . .
Modelagem do Domnio da Aplicao
Integrao de Dados . . . . . . . . . .
Ferramentas Utilizadas . . . . . . . .
Configurao Inicial . . . . . . . . . .
Contratos . . . . . . . . . . . . . . . .
Configurao do Banco de Dados . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9
9
9
10
11
11
15
16
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
18
18
28
31
35
Tratamento de Excees . . . . . .
Criao de Excees de Negcio
Implementao de Providers . .
Contato No Encontrado . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
41
41
44
45
48
48
49
.
.
.
.
CONTEDO
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
52
54
57
59
63
Prximos Passos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
Pr-requisitos
Para acompanhar adequadamente os assuntos abordados neste livro, recomenda-se que o leitor
possua conhecimentos bsicos de programao na linguagem Java, de gerenciamento de banco de
dados, de modelo cliente/servidor, alm de conhecer o protocolo HTTP.
Recursos
O cdigo fonte dos projetos est diponvel em https://bitbucket.org/salvadori/livro-java-web-apis.
Sobre o Autor
Ivan Salvadori bacharel (2009), mestre (2015) e doutorando em cincia da computao pela Universidade Federal de Santa Catarina. membro do Laboratrio de Pesquisas em Sistemas Distribudos
(LAPESD-UFSC). Atua na rea de sistemas distribudos, com foco em Web services semnticos.
Atualmente est pesquisando mecanismos de composio para arquitetura de Microservices.
http://lapesd.inf.ufsc.br/
Introduo
Web APIs
Organizaes necessitam interligar sistemas e trocar informaes internamente e tambm com
outras organizaes. Uma soluo simples e muito utilizada para este tipo de integrao atravs
do compartilhamento de banco de dados, onde tabelas so criadas para armazenar e compartilhar os
dados dos sistemas. Esta forma de integrao relativamente simples e rpida de ser implementada,
porm apresenta algumas desvantagens. Com a evoluo dos sistemas, inevitvel que ocorram
alteraes (estruturais ou de contedo) nas bases de dados. Como diversas aplicaes utilizam tabelas
em comum, uma alterao pontual no banco de dados pode afetar diversas aplicaes, dificultando
a evoluo e manuteno dos sistemas integrados.
Outra alternativa realizar a integrao atravs de Web APIs, que disponibilizam as funcionalidades
das aplicaes em rede local ou na Web. A principal diferena entre Web APIs e aplicaes
Web tradicionais o usurio. Aplicaes Web tradicionais so manipuladas diretamente por seres
humanos, enquanto Web APIs so projetadas para operar com outros sistemas. No cenrio de
integrao atravs de Web APIs, cada aplicao possui sua prpria base de dados, sem compartilh-la
com os demais sistemas. As informaes so expostas atravs de Web APIs, que formam uma camada
de integrao. Os dados so geralmente representados nos formatos JSON ou XML, e transportados
via HTTP. Com esta abordagem de integrao, a Web se torna uma infraestrutura para construo
de sistemas distribudos.
A integrao por Web APIs possui a vantagem de reduzir o acoplamento entre as aplicaes,
possibilitando que evoluam em ritmos diferentes, pois alteraes nos modelos de dados no
influenciam diretamente a integrao. Outro ponto positivo a possibilidade da integrao se
estender para fora dos domnios da organizao. Como a base de dados no compartilhada, apenas
dados especficos so disponibilizados, atuando como backend para outras aplicaes. Por outro
lado, acrescenta a complexidade de implementao de uma camada extra, responsvel por realizar e
atender chamadas a outras Web APIs, alm converter os dados nos formatos estipulados. Alm disso,
1
Introduo
Web APIs so fundamentais para aplicaes mobile, que geralmente utilizam o suporte server-side
para atender aos seus objetivos.
Introduo
Espera-se que o significado dos verbos HTTP sejam respeitados, empregando o verbo adequado para
cada ao, embora muitas implementaes REST negligenciem esta restrio e utilizam GET para
obter, criar, alterar e remover recursos, dentre outras combinaes. Outra restrio imposta pelo
REST a correta utilizao de cdigos de status ou mensagens. Todas as requisies tratadas pelo
servidor recebem um cdigo de status, que informa ao cliente o resultado da requisio. Os cdigos
possuem tamanho fixo de trs dgitos e esto organizados da seguinte forma:
1XX - Informaes;
2XX - Sucessos;
3XX - Redirecionamentos;
4XX - Erros causados pelo cliente;
5XX - Erros causados no servidor.
Introduo
Outra restrio arquitetural REST exige que as requisies contenham todas as informaes
necessrias para sua execuo, sem recorrer a dados armazenados em sesses do usurio, ou seja,
requisies auto-descritivas. No esperado que o servidor mantenha dados na sesso do usurio,
tornando a aplicao stateless, ou seja, o servidor no deve manter nenhuma informao sobre
as requisies realizadas. Esta restrio importante para promover a escalabilidade do sistema,
pois diversas instncias da Web API podem ser iniciadas para realizar o balanceamento de carga.
Considerando que as requisies dos clientes sejam auto-descritivas, qualquer Web API pode atender
a qualquer requisio sem necessidade de compartilhamento de estados entre os servidores.
Jersey
Jersey a implementao de referncia da especificao JAX-RS, que estabelece os mecanismos
para o desenvolvimento de Web Services REST para a linguagem Java. O framework Jersey permite
a manipulao de requisies HTTP, a serializao de representaes de recursos em diversos
formatos, alm de mecanismos para tratamento de excees.
O cdigo de exemplo de utilizao do Jersey apresenta uma classe que recebe as anotaes do framework para manipular requisies HTTP. A anotao @Path(caminho1) aplicada diretamente
sobre a classe e determina uma URL de acesso. As anotaes @GET, @POST, @PUT e @DELETE so
utilizadas para associar os mtodos da classe aos respectivos verbos HTTP. As anotaes @Consumes
e @Produces especificam o formato das representaes que so esperadas e retornadas pelos mtodos,
respectivamente. Neste exemplo, as representaes sero serializadas em JSON. Atravs da anotao
@Path, aplicada sobre um mtodo, possvel adicionar trechos adicionais URL, alm de definir
variveis atravs de @PathParam ou de @QueryParam, como exemplificado no mtodo carregar. Os
valores das variveis do tipo @PathParam so atribudos como parte integrante da URL, enquanto
os valores de @QueryParam so associados aos nomes das variveis.
Introduo
Introduo
Spring Boot
Spring Boot um framework para o desenvolvimento de aplicaes baseadas em Spring. Sua
principal contribuio a facilidade de configurao do projeto e aumento de produtividade. Alm
disso, o Spring Boot uma das opes mais adotadas para o desenvolvimento de Web APIs em Java,
principalmente para a arquitetura de microservices. Caso voc no tenha experincia com o Spring
framework no se preocupe, pois uma breve introduo ser apresentada a seguir. Se voc domina
os conceitos bsicos do Spring, fique a vontade para seguir em frente.
Antes de falar sobre o Spring framework, primeiro vamos discutir um pouco sobre design de
software. Uma das formas mais tradicionais de modelagem o design em camadas, que agrupa
o sistema em classes que possuem a mesma responsabilidade, tais como: persistir informaes em
um banco de dados, aplicar regras de negcio ou interagir com os usurios. Alm disso, existe a
camada de domnio de aplicao, que descreve as informaes manipuladas pelo sistema, sendo
utilizada pelas demais camadas. Neste exemplo, a camada de persistncia de dados presta servios
para a camada de regras de negcio, que por sua vez, presta servios para a camada de integrao.
Os servios so descritos por meio de contratos, que estabelecem as diretrizes para a execuo das
funcionalidades.
Design em camadas
As camadas do sistema trocam mensagens atravs de um fluxo bem definido, como mostra a
figura a seguir. Ao receber uma requisio do usurio, a camada de integrao converte os dados
recebidos em um objeto de domnio (DOM). Em seguida, a informao (objeto de domnio) passada
para a camada de negcio atravs da construo de um objeto (NEG) e a invocao de uma de
suas funcionalidades descritas no seu contrato. Por sua vez, a camada de negcio aplica as regras
necessrias e solicita servios de persistncia (DAO). Por fim, a camada de persistncia recebe o
objeto de domnio e executa alguma operao de banco de dados.
Introduo
Atravs deste modelo de interao, possvel dizer que a camada de integrao depende da camada
de negcios, que por sua vez, depende da camada de persistncia. Entretanto, para manter o baixo
acoplamento, as camadas se comunicam com base somente nos contratos de servio. As classes que
implementam os servios no devem ser compartilhadas entre as camadas. neste ponto que o
Spring framework entra em ao. Ele capaz de realizar a injeo de dependncias, que a partir do
contrato de servio (interface), cria um objeto que implementa esta interface.
A anotao @Component define uma classe como um bean do Spring que pode ser injetado em
outro bean, fazendo parte do contexto das classes gerenciadas pelo framework. A classe Integracao
apenas informa que depende de um objeto que implementa o contrato definido pela interface
Negocio. O mesmo ocorre na classe NegocioImpl, que depende de um objeto que implementa a
interface Dao. Estes pontos de injeo so demarcados atravs da anotao @Autowired, e durante o
carregamento da aplicao, o Spring framework providencia a criao dos objetos necessrios. Nas
prximas sees sero apresentados exemplos concretos que utilizam a injeo de dependncias.
A injeo de dependncias apenas uma das funcionalidades disponibilizadas pelo Spring. Vrios
outros mdulos fazem parte da pilha de tecnologias do framework. Neste projeto, ser utilizado
tambm o suporte JDBC do Spring, que facilita a manipulao de banco de dados, alm de oferecer
controle de transaes, fundamental para garantir a integridade dos dados.
Introduo
fundamental compreender corretamente o comportamento dos beans dos Spring. Por padro,
quando o Spring cria uma instncia de um bean, este objeto segue o comportamento singleton,
onde apenas um objeto construdo e utilizado nos pontos de injeo. Ao anotar um endpoint com
@Component, adota-se o comportamento prototype, onde os valores dos atributos da classe sero
mantidos entre as requisies. Este entendimento sobre os beans do Spring fundamental para
garantir o comportamento correto da aplicao.
Endpoint singleton
Endpoint prototype
Projeto
Este captulo apresenta os detalhes do projeto de uma Web API que ser implementada com Spring
Boot e Jersey. Primeiramente apresentada a viso geral, seguida da modelagem do domnio da
aplicao e da integrao de dados, ferramentas utilizadas, contratos de servio e configurao de
banco de dados.
Viso Geral
Uma aplicao de gerenciamento de uma agenda de contatos utilizada como exemplo para aplicar
as tecnologias abordadas neste livro. Diversas simplificaes foram realizadas no projeto para
manter o foco nas tecnologias, simplificar o entendimento e a implementao. Embora o exemplo
seja baseado em um estudo de caso simples, o projeto apresenta os requisitos mais comuns em
aplicaes reais. O projeto contempla o desenvolvimento de uma Web API para a manipulao
de dados de contatos. Atravs de requisies HTTP, deve ser possvel cadastrar novos contatos,
consultar contatos anteriormente cadastrados, alm de alterar e remover os dados.
10
Projeto
Contato.java
public class Cliente {
private String id;
private String nome;
private String email;
private String cpf;
private String telefone;
private Date dataNascimento;
private Endereco endereco;
//gets e sets omitidos
}
Endereco.java
public class Endereco {
private String estado;
private String cidade;
private String bairro;
private String logradouro;
//gets e sets omitidos
}
Integrao de Dados
A integrao de dados representa a interface com o usurio do sistema, que no contexto de Web APIs
so outras aplicaes. Com base nas funcionalidades descritas na viso geral do projeto, pode-se
modelar as classes de integrao por meio de dois recursos. O recurso ListaDeContatos agrupa todos
os contatos cadastrados no sistema, e disponibiliza dois mtodos para interao. O primeiro mtodo
utiliza HTTP GET, que retorna a representao da lista ao usurio. O segundo mtododo utiliza
HTTP POST para adicionar um novo contato lista. O recurso Contato manipula as informaes de
um contato especfico, e disponibiliza trs mtodos de interao. O primeiro mtodo utiliza HTTP
GET que retorna os dados de um contato, enquanto o segundo e o terceiro mtodo utilizam HTTP
PUT e DELETE para alterar e remover um contato, respectivamente.
11
Projeto
Ferramentas Utilizadas
A IDE utilizada para implementar o projeto foi o Eclipse verso Mars Release (4.5.0). Entretanto,
outras IDEs podem ser utilizada sem prejuzos para o desenvolvimento. O MySQL verso 5.5.46 foi
utilizado com SGBD da aplicao. Novamente, outros bancos de dados podem ser utilizados para
implementar o projeto. O Apache Maven foi utilizado para gerenciar o projeto. Foi utilizada a verso
que acompanha o Eclipse, sem necessidade de nenhuma instalao externa.
Configurao Inicial
Como dito anteriormente, o projeto gerenciado pelo Apache Maven. Para criar um projeto Maven
basta selecionar New > Maven Project no menu File. Atravs da seleo da opo Create a simple
project, ser criado um projeto Maven simples, sem nenhuma pr-configurao. Na prxima janela
sero preenchidas as informaes de Group Id e Artifact Id, que representam a organizao que
desenvolve o projeto, e o nome do projeto, respectivamente. Neste exemplo, o valor de Group Id
br.com.exemplo e de Artifact Id agenda-api. Embora o projeto seja uma aplicao Web, o Packaging
selecionado jar.
Com o projeto criado, o momento de organizar as classes em pacotes. O pacote config agrupa
todas as classes relacionadas com a configurao da aplicao. Os pacotes dao e negocio agrupam
as classes e interfaces de persistncia e regras de negcio, respectivamente. As classes do domnio
da aplicao so agrupadas no pacote dominio. As classes responsveis por manipular as requisies
dos usurios so agrupadas no pacote endpoint. Por fim, as representaes de recursos que exigem
algum tratamento de apresentao sero agrupadas no pacote representacao.
12
Projeto
Estrutura de pacotes
Projeto
pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source> <target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>
true
</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
</dependencies>
13
Projeto
14
O Spring Boot permite que uma aplicao Web seja executada a partir de um arquivo jar executvel,
semelhante a uma aplicao stand-alone. Sendo assim, preciso implementar uma classe que implementa o mtodo main. Crie uma classe no pacote config com o contedo de WebApiApplication.java.
A anotao @SpringBootApplication define a classe como a responsvel por iniciar a aplicao.
A anotao @ComponentScan recebe o nome do pacote para iniciar a varredura dos beans do
Spring anotados com @Component. De acordo com o exemplo, a varredura contempla todos os
pacotes a partir de br.com.exemplo.agenda.api, localizando beans nos pacotes, config, dao, dominio,
endpoint, negocio e representacao.
WebApiApplication.java
@SpringBootApplication
@ComponentScan("br.com.exemplo.agenda.api")
public class WebApiApplication {
public static void main(String[] args) {
SpringApplication.run(WebApiApplication.class, args);
}
}
Projeto
15
Neste momento a aplicao est pronta para manipular requisies HTTP. Vamos fazer um teste
para verificar se tudo est configurado corretamente. Crie uma classe no pacote endpoint com o
contedo de TesteEndPoint.java. Este endpoint manipula requisies HTTP GET mapeadas para a
URL teste. O resultado da requisio uma mensagem de texto informando que o teste foi bem
sucedido. Os endpoints so acessados atravs de URLs resultantes da concatenao da URL base
definida na configurao do Jersey com os caminhos definidos em cada endpoint e seus respectivos
mtodos. Por padro, o Spring Boot utiliza a porta HTTP 8080. Para realizar o teste, execute a classe
main* e digite a seguinte URL em seu navegador: localhost:8080/agenda-api/teste.
TesteEndPoint.java
Path("teste")
public class TesteEndPoint {
@GET
public Response teste() {
return Response.ok("Teste bem sucedido").build();
}
}
Contratos
Os contratos so as descries dos servios prestados pelas camadas do sistema. Na linguagem de
programao Java, os contratos so desenvolvidos atravs de interfaces. A seguir, so definidos
os dois contratos da camada de persistncia. Cada contrato descreve os servios de persistncia
associados a uma classe de domnio da aplicao. Sendo assim, o contrato especificado em ContatoDao.java define os servios de persistncia para a classe Contato, enquanto o contrato especificado
em EnderecoDao.java define os servios para a classe Endereco.
ContatoDao.java
public interface ContatoDao {
void cadastrar(Contato contato);
void alterar(Contato contato);
void remover(String idContato);
Contato consultar(String idContato);
List<Contato> listarTodos();
}
16
Projeto
EnderecoDao.java
public interface EnderecoDao {
void cadastrar(Endereco endereco, String idContato);
Endereco consultar(String idContato);
void remover(String idContato);
}
Apenas um contrato estabelecido na camada de negcio, como especificado em RegrasContatos.java. Este contrato considera que o objeto contato composta por um objeto endereco. Dessa
forma, o endereo manipulado juntamente com os dados do contato, mesmo que persistido de
forma independente.
RegrasContatos.java
public interface RegrasContatos {
void cadastrar(Contato contato);
List<Contato> listarTodos();
Contato consultar(String idContato);
public void alterar(Contato contato);
public void remover(String idContato);
}
Projeto
17
Por fim, as configuraes de acesso ao banco de dados, como por exemplo: URL, porta, nome de
usurio e senha, devem ser realizadas no arquivo application.yml. Alm das configuraes bsicas,
apresentada a configurao necessria para realizar a verificao das conexes, evitando que a
aplicao utilize uma conexo invlida.
Configurao do banco de dados (application.yml)
spring.datasource.url: "jdbc:mysql://<enderecoServidor>:3306"
spring.datasource.username: <usuario>
spring.datasource.password: <senha>
spring.datasource.driver-class-name: com.mysql.jdbc.Driver
spring.datasource.max-active: 10
spring.datasource.initial-size: 5
spring.datasource.max-idle: 5
spring.datasource.min-idle: 1
spring.datasource.test-while-idle: true
spring.datasource.test-on-borrow: true
spring.datasource.validation-query: "SELECT 1"
pring.datasource.time-between-eviction-runs-millis: 5000
spring.datasource.min-evictable-idle-time-millis: 60000
Cadastramento
O cadastramento a funcionalidade responsvel por criar um novo contato na agenda. O processo
de cadastramento iniciado atravs de uma requisio HTTP, que solicita que a representao
informada seja mantida no banco de dados. Sendo assim, vamos iniciar a implementao pelo
endpoint responsvel por manipular as requisies do usurio.
Crie uma classe no pacote endpoint com o contedo de ListaContatosEndpoint.java. A anotao
@Path(listaDeContatos) define que a classe tem o comportamento de endpoint e estabelece uma
URL de acesso. Nas linhas 4 e 5 demarcado um ponto de injeo de dependncia para uma instncia
de objeto que representa as regras de negcio. Este o ponto onde a informao passa da camada de
integrao para a camada de negcio. Entre as linhas 7 e 13 implementado o mtodo que recebe
a requisio para o cadastro do contato. O mtodo anotado com @POST, que define o verbo
HTTP a ser utilizado. As anotaes @Produces e @Consumes definem o JSON como formato de
representao de entrada e de sada do mtodo. O mtodo recebe um objeto que automaticamente
convertido de JSON para um objeto do tipo Contato. Na sequncia, invocado o mtodo cadastrar
do contrato das regras de negcio e retornado ao usurio o objeto armazenado no banco de dados.
O prximo passo implementar a classe responsvel pelas regras de negcio para o cadastramento
de contatos. O cdigo apresentado em GerenciadorContatos.java apresenta a classe que implementa
a interface RegrasContatos com todos os mtodos definidos no contrato. Deve-se anotar a classe com
@Component para defini-la como um bean do Spring. O cadastramento exige a manipulao das
informaes do contato e de seu endereo. Sendo assim, nas linhas 4 a 8 so definidos os pontos de
injeo de dependncia para os Daos responsveis pela persistncia dos dados. O mtodo cadastrar
apenas gera um id aleatrio para o contato, alm de solicitar para a camada de persistncia o
armazenamento das informaes.
18
19
ListaContatosEndpoint.java - cadastramento
1
2
@Path("listaDeContatos")
public class ListaContatosEndpoint {
@Autowired
private RegrasContatos regrasContatos;
4
5
6
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response cadastrarContato(ContatoRep contato) {
regrasContatos.cadastrar(contato);
return Response.ok(contato).build();
}
7
8
9
10
11
12
13
14
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response carregarListaContatos() {...}
15
16
17
18
Note que os mtodos cadastrar, alterar e remover so anotados com @Transactional. Esta anotao
define uma transao de negcio, que garante a execuo atmica de todas as instrues do mtodo.
Caso alguma exceo seja lanada durante a execuo do mtodo, o Spring framework garante o
retorno do banco de dados para o estado inicial da transao.
Imagine o seguinte cenrio onde no seja definida uma transao. Na linha 15 de GerenciadorContatos.java, solicitada a gravao das informaes do contato no banco de dados. Considere que
as informaes foram persistidas na tabela de contatos. Durante a gravao dos dados de endereo
(linha 16) ocorre alguma exceo que no permita a persistncia na tabela de endereo. Entretanto,
existe uma restrio que todo contato deve obrigatoriamente possuir informaes do endereo.
Neste cenrio, o banco de dados est em um estado de inconsistncia, pois os dados do contato
foram armazenados sem os dados de endereo. Por outro lado, quando o mtodo anotado com
@Transactional, a transao garante que os dados armazenados na tabela do contato sejam desfeitos,
resultando no rollback automtico dos dados.
20
GerenciadorContatos.java - cadastramento
1
2
@Component
public class GerenciadorContatos implements RegrasContatos {
@Autowired
private ContatoDao contatoDao;
4
5
6
@Autowired
private EnderecoDao enderecoDao;
7
8
9
@Override
@Transactional
public void cadastrar(Contato contato) {
String idContato = UUID.randomUUID().toString();
contato.setId(idContato);
contatoDao.cadastrar(contato);
enderecoDao.cadastrar(contato.getEndereco(), idContato);
}
10
11
12
13
14
15
16
17
18
@Override
public List<Contato> listarTodos() {...}
19
20
21
@Override
public Contato consultar(String idContato) {...}
22
23
24
@Override
@Transactional
public void alterar(Contato contato) {...}
25
26
27
28
@Override
@Transactional
public void remover(String idContato) {...}
29
30
31
32
JdbcContatoDao.java - cadastramento
@Component
public class JdbcContatoDao implements ContatoDao {
@Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
@Override
public void cadastrar(Contato contato) {
StringBuilder sql = new StringBuilder();
sql.append("insert into agenda.contato ");
sql.append("(id, nome, email, cpf, telefone, data_nascimento) ");
sql.append("values (:id, :nome, :email, :cpf, :tel, :dataN)");
Map<String, Object> parametros = new HashMap<>();
parametros.put("id", contato.getId());
parametros.put("nome", contato.getNome());
parametros.put("email", contato.getEmail());
parametros.put("cpf", contato.getCpf());
parametros.put("tel", contato.getTelefone());
parametros.put("dataN", contato.getDataNascimento());
jdbcTemplate.update(sql.toString(), parametros);
}
@Override
public List<Contato> listarTodos() {...}
@Override
public Contato consultar(String idContato) {...}
@Override
public void alterar(Contato contato) {...}
@Override
public void remover(String idContato) {...}
}
21
22
JdbcEnderecoDao.java - cadastramento
@Component
public class JdbcEnderecoDao implements EnderecoDao {
@Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
@Override
public void cadastrar(Endereco endereco, String idContato) {
StringBuilder sql = new StringBuilder();
sql.append("insert into agenda.endereco ");
sql.append("(estado, cidade, bairro, logradouro, id_contato) ");
sql.append("values (:estado, :cidade, :bairro, :logradouro, :idContato)");
Map<String, Object> parametros = new HashMap<>();
parametros.put("idContato", idContato);
parametros.put("estado", endereco.getEstado());
parametros.put("cidade", endereco.getCidade());
parametros.put("bairro", endereco.getBairro());
parametros.put("logradouro", endereco.getLogradouro());
jdbcTemplate.update(sql.toString(), parametros);
}
@Override
public Endereco consultar(String idContato) {...}
@Override
public void remover(String idContato) {...}
}
23
retornadas. A mensagem de retorno contm os dados enviados com a adio do id gerado pela
aplicao. Entretanto, possvel notar que a data de nascimento retornou com um valor diferente.
Analisando com mais detalhes, vamos at o banco de dados para verificar como o registro foi
armazenado. Como verificado, a data de nascimento foi armazenada com um valor incorreto (200010-09), sendo que o valor informado foi 2000-10-10. Isto ocorre devido converso direta de
uma String para um objeto do tipo Date. Uma forma de corrigir este erro converter os dados
manualmente para uma representao personalizada do recurso, ao invs de utilizar diretamente o
objeto de domnio da aplicao.
24
Criao de Representaes
Representaes so classes de apoio para a troca de informaes entre Web APIs e seus clientes. Elas
so utilizadas em situaes em que compartilhar diretamente os objetos de domnio da aplicao no
adequado, principalmente quando necessrio atender questes de formatao de dadas, valores
numricos ou a prpria estrutura das informaes.
A classe ContatoRep.java mostra o cdigo da representao do contato e de seu endereo. Todos os
atributos so valores textuais, inclusive a data de nascimento. Dessa forma, as informaes enviadas
pelos clientes sero tratadas como String e convertidas adequadamente. Outra diferena entre a
representao e as classes de domnio da aplicao a forma como os atributos esto estruturados,
pois todos os atributos esto organizados de forma plana, sem composio de classes. Sendo
assim, possvel criar diversas representaes para atender diferentes expectativas e propsitos das
aplicaes clientes.
ContatoRep.java
1
2
3
4
5
6
7
8
9
10
11
12
13
public ContatoRep() {}
14
15
16
17
18
19
20
21
22
if (contato.getEndereco() != null) {
this.estado = contato.getEndereco().getEstado();
this.cidade = contato.getEndereco().getCidade();
this.bairro = contato.getEndereco().getBairro();
this.logradouro = contato.getEndereco().getLogradouro();
}
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
25
26
Alm do construtor padro, est disponvel um construtor que preenche os atributos a partir de
um objeto de domnio, alm de um mtodo conversor de representao para domnio. Existe
tambm o conversor para manipular datas. O mtodo converterData converte uma data representada
textualmente no formato dd/MM/yyyy, em um objeto do tipo Date. A converso inversa realizada
pelo mtodo serializarData capaz de transformar em String um objeto do tipo Date. Para manipular a
data foi utilizada a biblioteca joda-time. Entretanto, necessrio incluir ao pom.xml esta dependncia
Dependncia joda-time (pom.xml)
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response cadastrarContato(ContatoRep contato) {
Contato contatoDominio = contato.converterParaDominio();
regrasContatos.cadastrar(contatoDominio);
ContatoRep contatoCadastrado = new ContatoRep(contatoDominio);
return Response.ok(contatoCadastrado).build();
}
27
28
@Path("listaDeContatos")
public class ListaContatosEndpoint {
@Autowired
private RegrasContatos regrasContatos;
4
5
6
7
8
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response carregarListaContatos() {
List<Contato> lista = regrasContatos.listarTodos();
List<ContatoRep> representacoes = new ArrayList<>();
for (Contato contato : lista) {
representacoes.add(new ContatoRep(contato));
}
return Response.ok(representacoes).build();
}
9
10
11
12
13
14
15
16
17
18
19
29
@Component
public class JdbcContatoDao implements ContatoDao {
3
4
5
@Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
6
7
8
9
10
@Override
public List<Contato> listarTodos() {
StringBuilder sql = new StringBuilder();
sql.append("select * from agenda.contato");
11
12
13
14
30
15
16
17
18
19
20
21
22
}
});
23
24
}
//demais metodos omitidos
25
26
27
31
@Path("contato")
public class ContatoEndpoint {
@Autowired
private RegrasContatos regrasContatos;
4
5
6
@QueryParam("idContato")
private String idContato;
7
8
9
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response obterContato() {
Contato contato = regrasContatos.consultar(idContato);
return Response.ok(new ContatoRep(contato)).build();
}
10
11
12
13
14
15
16
@PUT
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response alterarContato(ContatoRep contato) {...}
17
18
19
20
21
@DELETE
@Produces(MediaType.TEXT_PLAIN)
public Response removerContato() {...}
22
23
24
25
32
invocado o mtodo consultar disponibilizado pelo objeto de negcio, que retorna um objeto de
domnio correspondente ao contato desejado. Por fim, retornada a representao do recurso a
partir do objeto de domnio. Os demais mtodos (linhas 17 a 25) sero implementados nas prximas
sees.
A classe GerenciadorContatos implementa a regra de negcio para esta consulta. O mtodo consultar
no aplica nenhuma restrio de negcio, apenas solicita camada de persistncia que consulte as
informaes do contato e de seu respectivo endereo. Por fim, o endereo associado ao contato e
retornado ao endpoint.
GerenciadorContatos.java - consulta a um contato especfico
1
2
3
4
5
6
7
8
9
10
11
@Component
public class GerenciadorContatos implements RegrasContatos {
@Override
public Contato consultar(String idContato) {
Contato contato = contatoDao.consultar(idContato);
Endereco endereco = enderecoDao.consultar(idContato);
contato.setEndereco(endereco);
return contato;
}
//demais metodos omitidos
}
33
34
Para testar a funcionalidade vamos executar uma requisio no Postman com HTTP GET aplicada
sobre a URL localhost:8080/agenda-api/contato, adicionando o queryParam idContato com o
identificador desejado. importante adicionar o cabealho HTTP Content-Type configurado para
application/json.
35
Alterao e Remoo
As ltimas funcionalidades que faltam ser implementadas so a alterao e a remoo dos contatos
cadastrados. Vamos comear com a implementao da classe ContatoEndpoint. O identificador do
contato atribudo varivel idContato por meio da anotao QueryParam, utilizada por ambos
os mtodos. Alm disso, os dois mtodos respeitam a semntica do protocolo HTTP e utilizam PUT
para alterao e DELETE para remoo de recursos.
O mtodo alterarContato recebe do cliente uma representao com os dados atualizados do contato.
Note que o identificador obtido a partir do atributo associado ao QueryParam deve ser atribudo ao
objeto, e convertido para o modelo de domnio antes de ser repassado camada de negcio. O mtodo
removerCliente apenas utiliza o identificador para solicitar a remoo do contato. Ao remover um
contato, a Web API retorna apenas uma mensagem de sucesso, sendo assim, a anotao @Produces
define o formato da representao como texto plano.
36
37
A classe JdbcContatoDao implementa os mtodos que manipulam o banco de dados para alterar e
para remover um contato. Os dois mtodos utilizam o mesmo princpio: primeiramente construdo
o comando SQL com base nas variveis do objeto de domnio; em seguida criado um mapa
com os parmetros; por fim, o comando SQL executado com base no mapa dos parmetros.
A remoo de um endereo, funcionalidade implementada pela classe JdbcEnderecoDao, segue o
mesmo procedimento.
38
39
JdbcEnderecoDao.java - remoo
@Component
public class JdbcEnderecoDao implements EnderecoDao {
@Override
public void remover(String idContato) {
StringBuilder sql = new StringBuilder();
sql.append("delete from agenda.endereco ");
sql.append("where id_contato = :idContato");
MapSqlParameterSource params = new MapSqlParameterSource("id", idContato);
jdbcTemplate.update(sql.toString(), params);
}
//demais metodos omitidos
}
40
Tratamento de Excees
Quando desenvolvemos sistemas, temos em mente que tudo ir funcionar perfeitamente. Entretanto,
no podemos ignorar o fato que erros e situaes no planejadas podem e iro acontecer. Quando o
sistema atinge um estado de no conformidade, por exemplo: um erro de execuo de um comando
SQL, ou alguma informao invlida proveniente do usurio, so lanadas excees, que se no
tratadas adequadamente se transformam em erros do sistema. Este captulo apresenta como definir
as excees de negcio e como tratar os erros do sistema.
41
Tratamento de Excees
GerenciadorContatos.java
@Component
public class GerenciadorContatos implements RegrasContatos {
private final int IDADE_MINIMA = 18;
@Autowired
private ContatoDao contatoDao;
@Autowired
private EnderecoDao enderecoDao;
@Override
@Transactional
public void cadastrar(Contato contato) {
validarDataNascimento(contato.getDataNascimento());
String idContato = UUID.randomUUID().toString();
contato.setId(idContato);
contatoDao.cadastrar(contato);
enderecoDao.cadastrar(contato.getEndereco(), idContato);
}
@Override
@Transactional
public void alterar(Contato contato) {
validarDataNascimento(contato.getDataNascimento());
contatoDao.alterar(contato);
enderecoDao.remover(contato.getId());
enderecoDao.cadastrar(contato.getEndereco(), contato.getId());
}
private void validarDataNascimento(Date dataNascimento) {
DateTime dateTimeDn = new DateTime(dataNascimento);
DateTime hoje = new DateTime();
int idade = Years.yearsBetween(dateTimeDn, hoje).getYears();
if (idade < IDADE_MINIMA) {
String msgErro = "Contato com menos de %s anos";
msgErro = String.format(msgErro, IDADE_MINIMA);
throw new IdadeContatoException(msgErro);
}
}
//demais metodos omitidos
}
42
Tratamento de Excees
43
Uma vez lanada, a exceo precisa ser tratada para disponibilizar uma resposta adequada ao cliente
da aplicao. Uma forma envolver a chamada do mtodo de negcio com try/catch. O exemplo a
seguir mostra a modificao na classe ListaContatosEndpoint, necessria para tratar a exceo no
momento de cadastramento do contato. O caminho feliz implementado no escopo try, enquanto
catch contm o cdigo que ser executado caso a exceo seja lanada.
ListaContatosEndpoint.java - try/catch
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response cadastrarContato(ContatoRep contato) {
try {
Contato contatoDominio = contato.converterParaDominio();
regrasContatos.cadastrar(contatoDominio);
ContatoRep contatoCadastrado = new ContatoRep(contatoDominio);
return Response.ok(contatoCadastrado).build();
}
catch (IdadeClienteException e) {
return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
}
}
O tratamento de excees no contexto de Web APIs implica em retornar uma resposta adequada ao
cliente, considerando a semntica do protocolo de comunicao utilizado. No casso do protocolo
HTTP, a exceo de idade mnima para o cadastro do contato resultado de uma informao
invlida proveniente do prprio cliente. Uma boa forma de informar ao cliente que ele est enviando
informaes invlidas atravs de uma resposta com o cdigo 400 (HTTP BAD REQUEST). Sendo
assim, aplicaes clientes de Web APIs devem ser capazes de interpretar corretamente os cdigos
retornados, resultando em sistemas mais robustos e confiveis aos usurios finais. Por fim, a figura a
seguir mostra a execuo de uma requisio contendo dados invlidos, e o resultado retornado pela
Web API.
44
Tratamento de Excees
Implementao de Providers
Tratar excees diretamente no endpoint pode tornar o cdigo pouco legvel e agradvel. Entretanto,
possvel utilizar Providers para mapear e tratar as excees lanadas durante a execuo da
aplicao. A classe IdadeContatoExceptionHandler mostra a implementao do Provider responsvel
por tratar as excees relacionadas idade do contato. Primeiramente, a classe precisa ser anotada
com @Provider. Alm disso, a classe deve implementar a interface ExceptionMapper para uma
determinada exceo ou hierarquia de excees. Por fim, a resposta adequada para a exceo
construda no mtodo toResponse. Por se tratar de uma configurao da Web API, os providers
foram agrupados no pacote config. Os providers ou seus pacotes devem ser registrados no arquivo
de configurao do Jersey, conforme mostrado em JerseyConfig.java. Dessa forma, o bloco try/catch
pode ser retirado sem prejuzo ao funcionamento da aplicao.
Tratamento de Excees
45
IdadeContatoException.java
@Provider
public class IdadeContatoExceptionHandler
implements ExceptionMapper<IdadeContatoException> {
@Override
public Response toResponse(IdadeContatoException exception) {
return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
Contato No Encontrado
Uma situao muito comum em Web APIs a inexistncia de um recurso solicitado pelo cliente. Ao
consultar ou solicitar alteraes de um contato inexistente, deve-se retornar uma resposta adequada
ao cliente. Para tratar este problema, vamos implementar uma classe de exceo para esta situao.
ContatoNaoEncontradoException.java
package br.com.exemplo.agenda.api.negocio;
public class ContatoNaoEncontradoException extends RuntimeException {
public ContatoNaoEncontradoException(String msg) {
super(msg);
}
}
Tratamento de Excees
46
47
Tratamento de Excees
Viso Geral
De forma geral, Web APIs no so manipuladas diretamente pelos usurios finais, mas por
aplicaes intermedirias, conhecidas como aplicaes clientes. Estas aplicaes se comunicam
com uma ou mais Web APIs, e oferecem uma interface grfica adequada ao usurio final do
sistema. Existem diversas tecnologias para o desenvolvimento de clientes de Web APIs. Dentre
as mais comuns destacam-se as aplicaes desktop desenvolvidas com diferentes linguagens de
programao, aplicaes nativas ou hibridas para dispositivos mveis e aplicaes Web. Para este
exemplo, vamos desenvolver uma aplicao Web com HTML e JQuery com Ajax, pois uma opo
muito utilizada e relativamente simples de ser implementada.
Neste captulo vamos implementar uma aplicao cliente capaz de se comunicar com a Web API
de contatos que desenvolvemos anteriormente. A aplicao cliente constituda por quatro pginas
HTML. A partir da lista.html, que apresenta todos os contatos cadastrados, possvel cadastrar
novos contatos em cadastro.html, consultar todas as informaes de um contato especfico em
consulta.html ou modificar os dados em alteracao.html. A remoo de um contato no exige uma
pgina dedicada, sendo realizada diretamente na pgina da listagem.
48
49
No topo da pgina HTML existe um campo de texto que define a URL da Web API, alm dos botes
de listar e cadastrar. Embora especificar o endereo da Web API parea irrelevante inicialmente,
este mecanismo permite que uma nica aplicao cliente se comunique com diversas Web APIs
de agenda. Isto desejvel em cenrios onde existe um grande nvel de distribuio de dados, por
exemplo: departamentos, filiais ou parceiros que possuem sua prpria instncia da Web API, e os
dados precisam ser reunidos em uma aplicao cliente.
O arquivo lista.html apresenta o cdigo da pgina HTML necessrio para representar as informaes
dos contatos. As pginas HTML so capazes apenas de apresentar as informaes desejadas, a
interao com a Web API deve ser feita com javascript. Neste exemplo, vamos utilizar o apoio do
JQuery. Sendo assim, deve-se primeiro obter o arquivo JQuery e import-lo na pgina (linha 6).
Alm disso, o cdigo javascript responsvel pela interao com a Web API desenvolvido em um
arquivo separado (lista.js) e tambm importado pela pgina (linha 7).
https://jquery.com/download/
50
lista.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<html>
<head>
<title>Gerenciador de Contatos</title>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="jquery/jquery-2.1.4.min.js"></script>
<script src="lista.js"></script>
</head>
<body>
<input id='apiPath' style='width: 400px;' value='http://localhost:8080/agenda-api'>
<button id='botaoListarTodos' type="button">Listar</button>
<button id='botaoCadastrar' type="button">Cadastrar</button>
<br><br>
<div id="listaDeContatos">
<table id="tabelaContatos" border="0" cellspacing="10">
<thead> <tr>
<th>Nome</th>
<th>Email</th>
<th>CPF</th>
<th></th>
<th></th>
<th></th>
</tr> </thead>
<tbody></tbody>
</table>
</div>
</body>
</html>
O arquivo lista.js - parte 1 mostra a implementao responsvel por realizar a consulta dos contatos
cadastrados na Web API. O arquivo comea com a funo listarTodosContatos, que realiza uma
requisio HTTP com ajax. Com base na URL da Web API, so criadas duas variveis, uma para
montar a URL da lista, e outra para criar a URL de acesso aos contatos (linhas 2 e 3). Entre as linhas
6 e 9 so definidos os detalhes da requisio ajax.
Basicamente duas coisas podem acontecer em uma requisio ajax com JQuery, sucesso ou erro. Em
caso de sucesso, ser atribuda variavel contatos a lista de registros retornados pela Web API, que
sero iterados e apresentados em uma linha da tabela HTML. Primeiramente, executada a funo
limparTabela (lista.js - parte2) para garantir que a tabela est vazia. Atravs do comando $.each,
todos os registros so iterados e transformados em uma nova linha, que adicionada tabela HTML.
As funcionalidades consultar, alterar e remover so disponibilizadas atravs de links associados com
cada linha da tabela. Funes so associadas aos links, que recebem a URL do contato e executam
as funcionalidades desejadas.
51
lista.js - parte 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$.ajax({
url: pathLista,
type: 'GET',
async: true,
contentType: 'application/json',
success: function(contatos) {
limparTabela();
$.each(contatos, function(index, contato) {
var novaLinha =
'<tr>' +
'<td>' + contato.nome + '</td>'+
'<td>' + contato.email + '</td>'+
'<td>' + contato.cpf + '</td>'+
'<td><a href="#" onclick=consultar("'+pathContato+contato.id+'")>consultar</a></td>'+
'<td><a href="#" onclick=alterar("'+pathContato+contato.id+'")>alterar</a></td>'+
'<td><a href="#" onclick=remover("'+pathContato+contato.id+'")>remover</a></td>'+
'</tr>';
$("#tabelaContatos tr:last").after(novaLinha);
});
},
error: function() { }
});
};
As funes consultar e alterar recebem a URL do contato como parmetro de entrada, que armazenada na rea de memria local do navegador, denominada sessionStorage. Os itens armazenados
nesta rea de memria podem ser acessados mesmo quando ocorre troca de pgina. Dessa forma,
as funes de consulta e alterao direcionam o usurio para outras pginas e recuperam o item
armazenado na memria local do navegador. Mais adiante ser apresenta a recuperao do item. A
funo remover tambm recebe a URL do contato como parmetro para executar uma requisio
HTTP DELETE, que remove o contato na Web API. Note que a funcionalidade de remoo
implementada no mesmo arquivo javascript da listagem, uma vez que no exige uma pgina dedica.
Entretanto, mecanismos mais elaborados para remoo poderiam ser implementados, como por
exemplo a confirmao de remoo.
52
lista.js - parte 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$(document).ready(function() {
$("#botaoListarTodos").click(function() {
listarTodosContatos();
});
30
31
32
33
34
$("#botaoCadastrar").click(function() {
window.location.href = "cadastro.html";
});
});
53
implementar o mecanismo de Cross-Origin Resource Sharing (CORS), que permite Web API
controlar o acesso de recursos de diferentes domnios. Dessa forma, deve-se implementar o CORS
diretamente na Web API. No pacote config do projeto da Web API, crie um provider de acordo com o
arquivo CorsInterceptor.java, que deve ser registrado em JerseyConfig.java. A partir deste momento,
a aplicao cliente deve ser capaz de interagir corretamente com a Web API.
54
Cadastro
O cadastro dos contatos realizado pela pgina cadastro.html e pelo arquivo cadastro.js. Primeiramente, so definidos os elementos HTML que compem a pgina, juntamente com algumas
instrues de estilo css que atuam na aparncia da pgina ( desejvel que o css seja implementado
em um arquivo distinto e importado na pgina html). Note que os campos de texto e seus rtulos
no esto inseridos em um formulrio HTML, como ocorre em aplicaes tradicionais. Uma vez
que o JQuery o responsvel pela realizao da requisio via ajax, nenhum formulrio precisa ser
submetido. As informaes escritas nos campos de texto so obtidas com base no identificador dos
elementos. Estas informaes so utilizadas para construir um documento JSON que enviado para
a Web API para o cadastro de um novo contato.
cadastro.html
<html>
<head>
<title>Gerenciador de Contatos</title>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script src="jquery/jquery-2.1.4.min.js"></script>
<script src="cadastro.js"></script>
<style>
label {
float: left;
width: 120px;
clear: both;
margin: 2px;
}
input {
width: 250px;
clear: both;
margin: 2px;
}
</style>
</head>
<body>
<h1>Cadastro de Contato</h1>
<div id="dadosContato">
<h3>Dados do contato</h3>
<label>Nome:</label><input id="nome" type="text"></input><br>
<label>Email:</label><input id="email" type="text"></input><br>
<label>CPF:</label><input id="cpf" type="text"></input><br>
<label>Telefone:</label><input id="telefone" type="text"></input><br>
<label>Data Nascimento:</label><input id="datan" type="text"></input><br>
<h3>Endereo</h3>
<label>Estado:</label><input id="estado" type="text"></input><br>
<label>Cidade:</label><input id="cidade" type="text"></input><br>
<label>Bairro:</label><input id="bairro" type="text"></input><br>
<label>Logradouro:</label><input id="logradouro" type="text"></input><br><br>
<button id="botaoCadastrar">Cadastrar</button><br><br>
<div id="resultado"></div>
</div>
</body>
</html>
55
56
57
Consulta
A consulta busca as informaes de um contato especfico e apresenta na pgina consulta.html. O
arquivo consulta.js implementa a requisio ajax que busca as informaes na Web API. Note que
no momento que pgina est pronta (contexto $(document).ready()), a funo consultarContato
invocada com a URL do contato como parmetro de entrada. Entretanto, a URL obtida a partir
do sessionStorage, armazenada anteriormente pela pgina de listagem. Essa uma forma de tornar
acessveis as informaes que precisam ser acessadas entre troca de pginas. Uma vez que a funo
consultarContato obtm os dados da Web API, as informaes so associadas aos elementos HTML
de acordo com seus identificadores.
<html>
<head>
<title>Gerenciador de Clientes</title>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="jquery/jquery-2.1.4.min.js"></script>
<script src="consulta.js"></script>
</head>
<body>
<h1>Detalhes do Contato</h1>
<h3>Dados do contato</h3>
<b>Nome:</b><span id="nome"></span><br>
<b>Email:</b><span id="email"></span><br>
<b>CPF:</b><span id="cpf"></span><br>
<b>Telefone:</b><span id="telefone"></span><br>
<b>Data Nascimento:</b><span id="datan"></span><br>
<h3>Endereco</h3>
<b>Estado:</b><span id="estado"></span><br>
<b>Cidade:</b><span id="cidade"> </span><br>
<b>Bairro:</b><span id="bairro"> </span><br>
<b>Logradouro:</b><span id="logradouro"></span><br>
</body>
</html>
consulta.js
var consultarContato = function(urlContato) {
$.ajax({
url: urlContato,
type: 'GET',
async: true,
contentType: 'application/json',
success: function(contato) {
$("#nome").text(contato.nome);
$("#email").text(contato.email);
$("#cpf").text(contato.cpf);
$("#telefone").text(contato.telefone);
$("#datan").text(contato.dataNascimento);
$("#estado").text(contato.estado);
$("#cidade").text(contato.cidade);
$("#bairro").text(contato.bairro);
$("#logradouro").text(contato.logradouro)
},
error: function() { }
});
};
$(document).ready(function() {
consultarContato(sessionStorage.getItem('urlContato'));
});
58
59
Alterao
A alterao do contato realizada pela pgina alterao.html, que apresenta rtulos e campos
de texto para que as informaes de um contato sejam alteradas. No arquivo alteracao.js, duas
funes so implementadas: consultarContato e consultarContato. A funo de consulta a mesma
do exemplo anterior, que busca as informaes do contato desejado para que suas informaes
sejam apresentadas nos campos de texto. Esta funcionalidade poderia ser reutilizada com algumas
modificaes no arquivo consulta.js, entretanto, para facilitar o entendimento, permitimos algumas
duplicaes de cdigo. Quando o boto com o identificador botaoAlterar pressionado, a funo
alterar invocada. Esta funo obtm os dados dos campos de texto, constri um objeto JSON e
realiza uma requisio HTTP PUT para a URL do contato armazenada no sessionStorage.
alteracao.html
<html>
<head>
<title>Gerenciador de Contatos</title>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="jquery/jquery-2.1.4.min.js"></script>
<script src="alteracao.js"></script>
<style>
label {
float: left;
width: 120px;
clear: both;
margin: 2px;
}
input {
width: 250px;
clear: both;
margin: 2px;
}
</style>
</head>
<body>
<h1>Alterao de Contato</h1>
<div id="dadosContato">
<h3>Dados do contato</h3>
<label>Nome:</label> <input id="nome" type="text"></input> <br>
<label>Email:</label> <input id="email" type="text"></input> <br>
<label>CPF:</label> <input id="cpf" type="text"></input> <br>
<label>Telefone:</label> <input id="telefone" type="text"></input> <br>
<label>Data Nascimento:</label> <input id="datan" type="text"></input>
<h3>Endereo</h3>
<label>Estado:</label> <input id="estado" type="text"></input> <br>
<label>Cidade:</label> <input id="cidade" type="text"></input> <br>
<label>Bairro:</label> <input id="bairro" type="text"></input> <br>
<label>Logradouro:</label> <input id="logradouro" type="text"></input><br><br>
<button id="botaoAlterar">Alterar</button> <br><br>
<div id="resultado"></div>
</div>
</body>
</html>
60
alteracao.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
61
62
63
Prximos Passos
64