Tecnologias JPA e JEE
Tecnologias JPA e JEE
Tecnologias JPA e JEE
Descrição
Propósito
Preparação
Objetivos
Módulo 1
A tecnologia JPA
Descrever as características do JPA.
Módulo 2
Componentes Enterprise
Java Beans
Empregar componentes EJB na construção de regras de negócio.
Módulo 3
Módulo 4
1 - A tecnologia JPA
Ao final deste módulo, você será capaz de descrever
as características do JPA.
ORM: mapeamento
objeto-relacional
Mapeamento objeto-relacional
Comentário
No ambiente Java, os primeiros exemplos de tecnologias para ORM que
obtiveram sucesso foram os Entity Beans e o Hibernate. As duas
tecnologias adotaram o mapeamento baseado em XML, mas utilizaram
padrões funcionais bastante distintos.
Java
content_copy
No fragmento de código a seguir, temos o início da definição de um
Entity Bean, onde o objeto concreto é gerado pelo servidor de aplicativos
e as classes de entidade apresentam apenas as propriedades, definidas
a partir de getters e setters abstratos, além de alguns métodos de
gerência do ciclo de vida, aqui omitidos. O mapeamento do Entity Bean
para a tabela deve ser feito com base na sintaxe XML, como no trecho
apresentado a seguir, para o servidor JBoss. Observe:
XML
content_copy
Java
content_copy
As entidades, para o Hibernate, são apenas classes comuns, sem
métodos de negócios, com um conjunto de propriedades e um
construtor padrão. Todo o mapeamento deve ser efetuado através da
sintaxe XML, como no trecho apresentado a seguir.
XML
content_copy
video_library
Java Persistance API
(JPA) e Sintaxe JPQL
Entenda mais alguns aspectos do JPA associado à utilização da Sintaxe
JPQL.
Comentário
Anotações são metadados anexados ao código, utilizados ao nível da
classe, atributos, métodos ou até parâmetros, e que permitem a leitura
por ferramentas externas, com o objetivo de configurar funcionalidades
adicionais.
Java
content_copy
Dica
Após configurar a tabela que será representada pela entidade,
precisamos completar as informações de mapeamento ao nível
dos atributos, com o uso da anotação Column e o nome do campo
definido no parâmetro name. Com o uso de Id definimos qual atributo
representará a chave primária, e tornamos um atributo obrigatório
através da anotação Basic, tendo o parâmetro optional configurado com
valor false.
arrow_forward_ios Entity
Marca a classe como uma entidade para o JPA.
arrow_forward_ios Table
Especifica a tabela que será utilizada no
mapeamento.
arrow_forward_ios Column
Mapeia o atributo para o campo da tabela.
arrow_forward_ios Id
Especifica o atributo mapeado para a chave
primária.
arrow_forward_ios Basic
Define a obrigatoriedade do campo ou o modo
utilizado para a carga de dados.
arrow_forward_ios OneToMany
Mapeia a relação 1XN do lado da entidade principal
através de uma coleção.
arrow_forward_ios ManyToOne
Mapeia a relação 1XN do lado da entidade
dependente, com base em uma classe de entidade.
arrow_forward_ios OneToOne
Mapeia o relacionamento 1X1 com atributos
de entidade em ambos os lados.
arrow_forward_ios ManyToMany
Mapeia o relacionamento NXN com atributos
de coleção em ambos os lados.
arrow_forward_ios OrderBy
Define a regra que será adotada para ordenar a
coleção.
arrow_forward_ios JoinColumn
Especifica a regra de relacionamento da chave
estrangeira ao nível das tabelas.
XML
content_copy
A primeira informação relevante é o nome da unidade de
persistência (ExemploSimplesJPAPU), com o tipo de transação que
será utilizado. Transações são necessárias para garantir o nível de
isolamento adequado entre tarefas, como no caso de múltiplos usuários
acessando o mesmo banco de dados.
push_pin
Resource local
Utiliza o gestor de transações do JPA, para execução no JSE ou no
modelo não gerenciado do JEE.
push_pin
JTA
Ativa a integração com JTA, para utilizar o gerenciamento de transações
pelo JEE.
Java
content_copy
Passo 1 expand_more
O primeiro passo em nosso código é a definição
do EntityManagerFactory, utilizando o nome da unidade de
persistência (ExemploSimplesJPAPU). Em seguida, obtemos
uma instância de EntityManager a partir da fábrica de gestores,
através de uma chamada para o método createEntityManager.
Passo 2 expand_more
Passo 3 expand_more
Fique atento:
Note que o JPA não elimina o uso de JDBC, pois o que temos é a
geração dos comandos SQL, de forma automatizada, a partir das
informações oferecidas pelas anotações.
Agora, podemos verificar como é feita a inclusão de um produto em
nossa base de dados. Observe a seguir:
Java
content_copy
Java
content_copy
Java
content_copy
Observando os trechos de código apresentados, podemos concluir
facilmente que os
métodos find, persist, merge e remove correspondem, respectivamente,
à execução dos comandos SELECT, INSERT, UPDATE e DELETE, ao nível
do banco de dados.
Execução local de
aplicativo com JPA
Execução do aplicativo
Veremos que a janela de edição de SQL será aberta, permitindo que seja
digitado o script apresentado a seguir. Para executar nosso script,
devemos pressionar CTRL+SHIFT+E, ou clicar sobre o botão de
execução de SQL, disponibilizado na parte superior do editor. Observe:
SQL
content_copy
Questão 1
A Active Record
B DAO
C Facade
D Adapter
E Front Controller
Questão 2
A Persistence
B EntityManager
C Query
D Transaction
E EntityManagerFactory
Visão geral
video_library
Arquitetura e tipos
de Enterprise - Java
Beans (EJB)
Conheça agora a tecnologia de objetos distribuídos dentro do Java.
Comentário
Um pool de objetos segue o padrão de desenvolvimento Flyweight, no
qual o objetivo é responder a uma grande quantidade de requisições
através de um pequeno conjunto de objetos.
O acesso aos serviços oferecidos pelo pool de EJBs deve ser solicitado
a partir de uma interface local (EJBLocalObject) ou remota (EJBObject),
onde as interfaces são geradas a partir de componentes de fábrica,
criadas com a implementação de EJBLocalHome, para acesso local,
ou EJBHome, para acesso remoto. Como é padrão na plataforma Java,
as fábricas são registradas e localizadas via JNDI (Java Naming and
Directory Interface).
looks_one
Cliente acessa a fábrica
de interfaces através de
JNDI.
looks_two
A interface de acesso é
gerada pela fábrica.
looks_3
Cliente recebe a
interface, podendo iniciar
o diálogo com o pool.
Observe a representação a seguir:
Service locator
Utlizado no acesso aos
componentes registrados via
JNDI.
Abstract factory
Utilizado na definição da fábrica
de interfaces.
Proxy
Utilizado na comunicação com
clientes remotos.
Java
content_copy
Como utilizamos JPA, não é necessário efetuar toda essa codificação
para localização e utilização do pool, ficando a cargo do framework de
persistência. No fluxo normal de execução, o cliente faz uma solicitação
para a interface de acesso, que é repassada para o pool de EJBs, sendo
disponibilizado um deles para responder, e na programação do EJB,
utilizamos o JPA para obter acesso ao banco de dados a partir
do DataSource, com o controle transacional sendo efetuado através
do JTA (Java Transaction API).
Curiosidade
No J2EE, existia um EJB para persistência, denominado Entity Bean, que
seguia o padrão Active Record, mas ele se mostrou inferior, em termos
de eficiência, quando comparado a alguns frameworks de persistência,
sendo substituído pelo JPA no JEE5.
Sessão e mensagerias
Session Beans
Stateless
Aqui, não é permitida a
manutenção de estado, ou seja,
não se guardam valores entre
chamadas sucessivas.
Stateful
Aqui, utiliza-se quando é
necessário manter valores entre
chamadas sucessivas, como no
caso de somatórios.
Singleton
Aqui, permite-se apenas uma
instância por máquina virtual,
garantindo o compartilhamento
de dados entre todos os
usuários.
Java
content_copy
Java
content_copy
Quanto ao EJB do tipo Singleton, ele é utilizado quando queremos
compartilhar dados entre todos os usuários conectados, mesmo na
execução sobre múltiplas máquinas virtuais, em ambientes distribuídos.
Não podemos esquecer que os EJBs são uma tecnologia corporativa, e
que a execução de forma clusterizada não é uma exceção em sistemas
de missão crítica.
Comentário
Em um cluster, temos um conjunto de computadores atuando como se
fossem apenas um, o que traz grande poder de processamento e menor
possibilidade de interrupções, já que a falha de um computador causará
a redistribuição das tarefas para os demais
Java
content_copy
Dica
O uso da interface CalculadoraLocal permite solicitar os serviços
do Session Bean, em meio ao pool de objetos, como se fossem simples
chamadas locais.
Tecnologia de mensagerias.
Terminal
content_copy
Java
content_copy
Atenção!
O MDB foi projetado exclusivamente para receber mensagens, a partir
de filas ou tópicos, o que faz com que não possa ser acionado
diretamente, como os Session Beans. Para sua ativação, basta que um
cliente poste uma mensagem.
Java
content_copy
looks_one Passo 1
Inicialmente, devemos mapear a fábrica de
conexões da mensageria e a fila de destino do
MDB, através de anotações Resource.
looks_two Passo 2
Com os recursos mapeados, definimos o
método putMessage, para envio da mensagem,
onde devemos criar uma conexão (Connection) a
partir da fábrica, a sessão (Session) a partir da
conexão, e o produtor de
mensagens (MessageProducer) a partir da sessão.
Na inicialização do MessageProducer, utilizamos o
recurso de fila mapeado, indicando que ele deve
apontar para a fila (Queue) destinada ao MDB.
looks_3 Passo 3
Após configurar a conexão, criamos a mensagem
de texto (TextMessage) através da sessão,
definimos o texto que será enviado com setText, e
finalmente enviamos a mensagem, a partir
do produtor, com o uso de send, finalizando a
definição do método putMessage. Com o método
completo, podemos utilizá-lo na resposta do Servlet
ao protocolo HTTP, e verificar a mensagem na saída
do GlassFish.
Passo 1
Criar um projeto do tipo Enterprise Application, na categoria
Java Enterprise.
Passo 2
push_pin
ExemploEJB-war
Este projeto contém os elementos para Web, como Servlets, Facelets e
páginas XHTML, compilados para um arquivo "war".
push_pin
ExemploEJB
Este projeto agrupa os dois projetos anteriores, compactados em
apenas um arquivo, com adoção da extensão "ear", para implantação.
Passo 1
Selecionar o tipo Session Bean na categoria Enterprise Java
Beans.
Passo 2
Definir o nome (Calculadora) e pacote (ejbs) do novo Session
Bean, escolher o tipo como Stateless e marcar apenas a
interface Local.
Questão 1
A Stateless
B Stateful
C Singleton
D Asynchronous
E Synchronous
Questão 2
B JDBC
C JMS
D JAAS
E JTS
Atenção!
Com os padrões, temos uma terminologia comum, pois eles permitem a
utilização de um vocabulário básico e um ponto de vista semelhante
sobre os problemas e possíveis soluções. Embora existam muitos
padrões de desenvolvimento, alguns deles se destacam em um sistema
cadastral corporativo, como: Facade, Proxy, Flyweight, Front Controller e
DAO.
Comentário
Outros componentes do sistema também deverão seguir padrões de
desenvolvimento, visando organizar as funcionalidades e facilitar a
leitura do código-fonte, como o uso de: Facade, ao nível dos Session
Beans, ou Front Controller, aplicado aos Servlets.
Abstract Factory
Trata-se da definição de uma arquitetura abstrata para a geração de
objetos, muito comum em frameworks.
Command
Trata-se de encapsular o processamento da resposta para algum tipo de
requisição, muito utilizado para o tratamento de solicitações feitas no
protocolo HTTP.
Facade
Trata-se de encapsular as chamadas para um sistema complexo, muito
utilizado em ambientes corporativos.
Flyweight
Trata-se da criação de grupos de objetos que respondem a uma grande
quantidade de chamadas.
Front Controller
Trata-se de concentrar as chamadas para o sistema, efetuando os
direcionamentos corretos para cada chamada.
Iterator
Trata-se do acesso sequencial aos objetos de uma coleção, o que é
implementado nativamente no Java.
Proxy
Trata-se da definição de um objeto para substituir a referência de outro,
utilizado nos objetos remotos para deixar a conexão transparente para o
programador.
Service Locator
Trata-se de gerenciar a localização de recursos compartilhados, com
base em serviços de nomes e diretórios.
Singleton
Trata-se de garantir a existência de apenas uma instância para a classe,
como em controles de acesso.
Strategy
Trata-se da seleção de algoritmos em tempo de execução, com base em
algum parâmetro fornecido.
Padrões arquiteturais
Modelo Padrão
arquitetural arquitetural
Define uma arquitetura Define o perfil dos
de forma abstrata, com componentes
foco apenas no objetivo estruturais, modelo de
ou característica close comunicação e os
principal. padrões de
desenvolvimento mais
adequados na
implementação.
Broker
Sistemas distribuídos.
Camadas
Mud to Structure, Chamada e
Retorno.
Orientado a
Objetos
Chamada e Retorno.
Programa
Principal e Sub-
rotina
Chamada e Retorno.
Pipes/Filters
Mud to Structure, Fluxo de
Dados.
Blackboard
M d t St t C t d
Mud to Structure, Centrada em
Dados.
Lote
Fluxo de Dados.
Repositório
Centrada em Dados.
Processos
Comunicantes
Componentes Independentes.
Event-Driven
Componentes Independentes.
Interpretador
Máquina Virtual.
Baseado em
Regras
Máquina Virtual.
MVC
Si t I t ti
Sistemas Interativos.
PAC
Sistemas Interativos.
Microkernel
Sistemas Adaptáveis.
Reflexiva
Sistemas Adaptáveis.
Comentário
Enquanto para os mainframes era comum a arquitetura de
processamento em lote, sistemas de linha de comando, no UNIX,
utilizam amplamente o padrão de pipes/filters, no qual a saída obtida na
execução de um programa serve como entrada para o próximo
programa da sequência. Em ambos os casos, podemos observar
arquiteturas baseadas no fluxo de dados.
MVC
video_library
Padrões de
arquitetura e model-
view-controller (MVC)
Saiba mais sobre a arquitetura MVC e as ferramentas do Java que se
adequam a ela.
Arquitetura MVC
Model (Modelo)
Controla toda a persistência do sistema.
View (Visualização)
Define a interface do sistema.
Atenção!
A arquitetura MVC é baseada em camadas. Cada camada enxerga
apenas a camada imediatamente abaixo.
A camada Controller precisa ser definida sem que seja voltada para
algum ambiente específico, como interfaces SWING ou protocolo HTTP.
A única dependência aceitável para os objetos de negócio deve ser com
relação à camada Model, e como a gerência do uso dos componentes
DAO ocorre a partir deles, uma das características observadas é a
diminuição da complexidade nas atividades cadastrais que foram
iniciadas na View, o que justifica dizer que temos a aplicação do
padrão Facade.
Comentário
Uma observação importante é a de que, como as regras de negócio
ficam concentradas na camada Controller, podemos gerenciar as
transações eficientemente a partir dos componentes dela. Inclusive,
com a adoção de objetos distribuídos, a funcionalidade das transações
foi ampliada para um modelo com a participação de múltiplos
servidores.
Camadas MVC.
Dica
Utilizar as ferramentas oferecidas pelo fabricante da linguagem pode
ser uma boa opção quando desejamos garantir a continuidade da
evolução do sistema.
Em nosso contexto, a camada Model utiliza JPA, e como deve ser
utilizada apenas pela camada Controller, é definida no mesmo projeto
em que estão os componentes do tipo EJB. Note que a camada
Controller oferece apenas as interfaces para os EJBs, com os dados
sendo transitados na forma de entidades, sem acesso ao banco de
dados, já que anotações não são serializáveis.
looks_one
Com a abordagem adotada, definimos o núcleo funcional e lógico de
nosso sistema, sem a preocupação de satisfazer a qualquer tipo de
tecnologia para construção de interfaces de usuário.
looks_two
A independência do núcleo garante que ele possa ser utilizado por
diversas interfaces simultâneas, como SWING, HTTP ou Web Services,
sem que ocorra qualquer modificação nos componentes do tipo JPA ou
EJB.
looks_3
Um erro comum nos sistemas Java para Web é definir os controladores
no formato de Servlets, pois as regras de negócio se confundem com as
rotinas de conversão utilizadas entre o protocolo HTTP e as estruturas
da linguagem Java.
looks_4
A abordagem errônea faz com que qualquer nova interface, como
SWING, Web Services, ou até linha de comando, seja obrigada a solicitar
os serviços através do protocolo HTTP, algo que não é uma exigência
das regras de negócio dos sistemas, de forma geral.
Java
content_copy
Java
content_copy
No código temos o atributo facade, do tipo ProdutoGestorLocal,
utilizando a anotação EJB para injetar o acesso ao pool de Session
Beans.
Questão 1
A Broker
B MVC
C PAC
D Batch
E Pipes/Filters
Questão 2
JPA
content_copy
Visão geral
video_library
Uso de tecnologias
Java com padrão MVC
para Web
Saiba mais sobre arquitetura MVC com Front Controller no ambiente
Web e o uso da plataforma Java.
Padrões Front
Controller
Conheça agora alguns importantes aspectos do padrão Front Controller.
SQL
content_copy
Aqui, temos as tabelas EMPRESA e DEPARTAMENTO, para a
persistência de dados de um cadastro simples, com um relacionamento
através do campo COD_EMPRESA, da tabela DEPARTAMENTO. Também
podemos observar uma terceira tabela, com o nome SERIAIS, que
viabilizará o autoincremento, através de anotações do JPA.
code Página
Descrição.
code index.html
Página inicial do aplicativo cadastral de exemplo,
com acesso às listagens de empresas e
departamentos.
code ListaEmpresa.jsp
Listagem das empresas e acesso às opções
oferecidas para inclusão e exclusão de empresas.
code DadosEmpresa.jsp
Entrada de dados da empresa que será incluída.
code ListaDepartamento.jsp
Listagem dos departamentos e acesso às opções
de inclusão e exclusão de departamentos.
code DadosDepartamento.jsp
Entrada de dados do departamento que será
incluído.
arrow_forward_ios listaEmp
Obter a lista de empresas.
Direcionar o fluxo para ListaEmpresa.jsp.
arrow_forward_ios excDepExec
Remover o departamento, de acordo com o
código informado.
Obter a lista de departamentos.
Direcionar a informação para
ListaDepartamento.jsp.
arrow_forward_ios excEmpExec
Remover a empresa, de acordo com o código
informado.
Obter a lista de empresas.
Direcionar o fluxo para ListaEmpresa.jsp.
arrow_forward_ios incDep
Direcionar o fluxo para
DadosDepartamento.jsp.
arrow_forward_ios incDepExec
Receber os dados para inclusão do
departamento.
Converter para o formato de entidade.
Incluir o departamento na base de dados.
Obter a lista de departamentos.
Direcionar o fluxo para
ListaDepartamento.jsp.
arrow_forward_ios incEmp
Direcionar o fluxo para DadosEmpresa.jsp.
arrow_forward_ios incEmpExec
Receber os dados para inclusão da empresa.
Converter para o formato de entidade.
Incluir a empresa na base de dados.
Obter a lista de empresas.
Direcionar o fluxo para ListaEmpresa.jsp.
Nos aplicativos Java para Web, o padrão Front Controller pode ser
implementado com base em um Servlet. O processo envolve a recepção
de uma chamada HTTP, através dos métodos doGet ou doPost,
execução de operações que envolvam chamadas aos EJBs,
relacionadas às atividades de consulta ou persistência, e
redirecionamento, ao final, para uma página, normalmente do tipo JSP,
para a construção da resposta.
Camadas Model,
Controller e View
Camadas Model e Controller
Passo 1
Adicionar novo arquivo, escolhendo Entity Classes from
Database, na categoria Persistence.
Passo 2
Passo 4
Passo 5
Escolher, ao chegar na última tela, o tipo de coleção como List,
além de desmarcar todas as opções.
Passo 1
Adicionar arquivo, escolhendo Session Beans For Entity
Classes, na categoria Persistence.
Passo 2
Selecionar todas as entidades do projeto.
Passo 3
Java
content_copy
Observe que a classe é iniciada com um construtor, onde é recebida a
classe da entidade gerenciada, e um método abstrato para retornar uma
instância de EntityManager, ao nível dos descendentes, elementos
utilizados pelos demais métodos da classe.
Java
content_copy
Em todos os três EJBs temos o mesmo tipo de programação, onde
ocorre a herança com base em AbstractFacade, passando o tipo da
entidade. O método getEntityManager retorna o atributo em, e no
construtor a superclasse é chamada, com a passagem da classe da
entidade.
Java
content_copy
Comentário
Não foram utilizadas instruções para o controle transacional, o que
decorre do fato de que o contêiner EJB será o responsável por gerenciar
as transações, via JTA, dentro do modelo conhecido
como CMP (Container Managed Persistence).
XML
content_copy
Programa asadmin.
O arquivo glassfish-resources.xml fica disponível na divisão de
configurações do projeto CadastroEJB-ejb, e foi gerado quando criamos
as entidades a partir do banco de dados, como pode ser visto na
próxima imagem.
Camada View
HTML
content_copy
Observando o código-fonte, temos apenas um formulário comum, com
um parâmetro do tipo hidden guardando o valor de acao, no
caso incEmpExec, e um campo de texto para a razão social da empresa.
Os dados serão enviados para CadastroFC, um Servlet no padrão Front
Controller que iremos criar posteriormente.
JSP
content_copy
JSP
content_copy
A página é iniciada com a definição de um link para CadastroFC, com o
parâmetro acao contendo o valor incEmp. Em seguida, é definida
uma tabela para exibir os dados de cada empresa do banco de dados,
contendo os títulos Código, Razão Social e Opções.
JSP
content_copy
Em termos práticos, a listagem de departamentos é muito semelhante à
de empresas, com a definição de um link de inclusão, agora com o
valor incDep para acao, e a exibição dos dados através de uma tabela
com os títulos Código, Nome, Empresa e Opções.
HTML
content_copy
Construção do Front
Controller
Implementação do Front Controller
Java
content_copy
Java
content_copy
Durante a execução, temos a definição da página de destino
como ListaEmpresa.jsp, a qual será diferente apenas quando o
parâmetro acao tiver valor incEmp, onde temos, como destino, a
página DadosEmpresa.jsp. O método executar irá retornar o nome da
página para o Front Controller, e ele efetuará o redirecionamento.
Java
content_copy
A estratégia para departamentos é um pouco mais complexa, o que
exigiu a utilização de duas interfaces para EJBs. Durante a execução,
teremos a página de destino definida como ListagemDepartamento.jsp,
a não ser para acao com valor incDep, onde a página de destino
utilizada será DadosDepartamento.jsp.
Passo 1
Da mesma forma que na
estratégia de empresa, temos as
operações efetuadas a partir do
atributo facade, como a remoção
da entidade, quando acao tem
valor excDepExec, ou a inclusão,
para o valor incDepExec, e a
chamada para findAll, para o
preenchimento do atributo lista,
nas ações que direcionam para a
página de listagem.
Passo 2
Também temos a utilização
de facadeEmpresa, para definir o
atributo listaEmp,
quando acao tem valor incDep, e
para recuperar a empresa
selecionada,
quando acao vale incDepExec.
Passo 3
Com as estratégias definidas,
podemos executar o último
passo na construção de nosso
aplicativo, adicionando
um Servlet, com o
nome CadastroFC, que será
i d d d
criado de acordo com o
padrão Front Controller.
Java
content_copy
Comentário
Quanto à resposta ao HTTP, no método processRequest, o primeiro
passo é a verificação do parâmetro acao, obrigatório na chamada ao
Servlet. Se o parâmetro estiver presente, localizamos a estratégia
correta, a partir dos HashMaps, invocamos a execução, e com o nome
da página obtido, efetuamos o redirecionamento via RequestDispatcher.
Tela de cadastro
Tela de exclusão
Questão 1
A Diagrama de Classes
B Rede de Petri
D Fluxograma
E Diagrama de Componentes
Questão 2
A HttpSession
D RequestDispatcher
E HttpServletResponse
Considerações finais
Analisamos duas tecnologias fundamentais na plataforma Java para o
ambiente corporativo: JPA (Java Persistence API) e EJB (Enterprise Java
Beans). Observamos que ambas as tecnologias utilizam anotações, e
compreendemos o papel do JPA nas tarefas de persistência, com
mapeamento objeto-relacional, e do EJB para implementação das regras
de negócio de nossos sistemas, de forma síncrona ou assíncrona.
headset
Podcast
Ouça mais detalhes sobre as tecnologias JPA e JEE.
Explore +
Confira as indicações que separamos especialmente para você!
Referências
CASSATI, J. P. Programação Servidor em Sistemas Web. Rio de Janeiro:
Estácio, 2016.
CORNELL, G.; HORSTMANN, C. Core JAVA. 8. ed. São Paulo: Pearson,
2010.
Download material
Relatar problema