Olá,
Hoje vamos mostrar como subir uma pequena aplicação no apache tomcat 7 que faça uso de JPA pra facilitar as manipulações do banco de dados e jstl para facilitar a apresentação de dados no jsp.
- Fedora 17 64 bits
- OpenJDK 1.7
- Apache Tomcat 7.0.27
- eclipse indigo SR2 (3.7.2)
- H2 database 1.3
- EclipseLink 2.3.1
Como de costume, vamos proceder com os downloads. Para instalar o JDK, entre num terminal o seguinte comando:
sudo yum install java-1.7.0-openjdk-devel
Faça o download do tomcat direto da fonte, preferencialmente a versão .tar.gz:
O download do tomcat também providenciará o suporte a jstl, que veremos como ajustar mais à frente.
Faça o download do eclipse em sua versão JEE:
O banco de dados H2 você baixa a versão zip:
O EclipseLink você baixa o "Installer Zip":
Uma vez coletados os ingredientes, vamos proceder com a montagem do ambiente. Entre na pasta Downloads e descompacte os arquivos que baixamos:
Entre na pasta do eclipse e execute-o. Deixe-o com o workspace padrão:
Uma vez carregado, o eclipse lhe apresentará uma tela de welcome. Livre-se dela e siga para o workbench:
Aí está, o workbench JEE do eclipse, velho conhecido seu, assim espero. Siga para a aba Servers para criarmos um novo servidor clicando no link "new server wizard":
No campo "Select the server type" escreva "tomcat v7" e selecione a opção que sobrar:
Aperte Next, e você verá a tela de configuração da runtime de servidor. Aperte browse e selecione a pasta do tomcat que descompactamos previamente:
Após pressionar finnish, você terá o tomcat disponível no seu workspace:
O passo seguinte é muito simples, vamos criar um novo projeto web chamado agenda. pressione o atalho disponível na barra do eclipse:
Pronto, temos um projeto Java web disponível, podemos começar a trabalhar de verdade, :-)
Nosso modelo de dados, de maneira geral, terá Contatos e Endereços. Nada mais. O único detalhe relevante é que um Contato poderá ter um ou mais Endereços.
Assim sendo, teremos duas telas de cadastro e duas telas de listagem, além de duas telas de status intermediárias que explicarei a seguir.
Vamos começar com as classes de modelo. Crie uma classe chamada Endereco no pacote exemplo.model:
A classe Contato você faz seguindo os passos já mostrados acima. Vamos adicionar alguns atributos ao nosso modelo de dados, a começar pelo Endereço:
package exemplo.model; public class Endereco { private long id; private String rua; private int numero; private String complemento; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getRua() { return rua; } public void setRua(String rua) { this.rua = rua; } public int getNumero() { return numero; } public void setNumero(int numero) { this.numero = numero; } public String getComplemento() { return complemento; } public void setComplemento(String complemento) { this.complemento = complemento; } }
A classe Contato ficará assim:
package exemplo.model; import java.util.List; public class Contato { private long id; private String nome; private String telefone; private Listenderecos; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getTelefone() { return telefone; } public void setTelefone(String telefone) { this.telefone = telefone; } public List getEnderecos() { return enderecos; } public void setEnderecos(List enderecos) { this.enderecos = enderecos; } }
Uma vez criado o modelo, hora de escrever telas que o representem. Vamos criar a tela de cadastro de Contato:
Este JSP é simples, teremos um formulário bem básico, nada complicado de entender:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head></body> </html>Salvar Contato </head> <body>
Você já pode até ver como ele fica no navegador, com ele aberto basta apertar o "play":
Atenção para o atributo action da tag form: ela tem o nome da ação que este formulário tentará executar. Se você apertou o botão Salvar e um erro 404 apareceu, não se preocupe, vamos corrigir isso agora. De volta ao eclipse, vamos criar um servlet:
Após apertar Next, um passo importante: mude o valor do URL Mappings para "/vaisalvar", que é o que tem no form. Só então pressione finnish:
O servlet basicamente mapeia os verbos HTTP para métodos java. Como não informamos o atributo method na tag form, o verbo aqui será o GET. Assim sendo, vamos modificar este servlet que aí está para que ele fique deste jeito:
package exemplo.controller; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import exemplo.model.Contato; @WebServlet("/vaisalvar") public class Salvar extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long id = 0L; String sId = request.getParameter("id").trim(); String sNome = request.getParameter("nome"); String sTelefone = request.getParameter("telefone"); if (!"".equals(sId)) id = Long.parseLong(sId); Contato c = new Contato(); c.setId(id); c.setNome(sNome); c.setTelefone(sTelefone); // TODO mais modificações a seguir // devemos ainda redirecionar para a tela de resultado request.getRequestDispatcher("/sucesso.jsp").forward(request, response); } }
Já podemos ver parte do trabalho caminhando: temos a recuperação dos dados do form através de chamadas "request.getParameter", verificação de id válida (que será útil para salvar um novo ou atualizar), e redirecionamento para uma página intermediária de status. Página essa, que você deve criar no projeto, de forma parecida com o que foi feito na criação do jsp de contato.
Poderíamos fazer o fowrard para o mesmo jsp de origem, entretanto ao usar uma página intermediária você não precisará prever a limpeza do formulário após a submissão. É um problema antigo, típico de web 1.0, e que muitas pessoas esquecem como combater.
Neste momento, precisamos retornar às configurações para habilitarmos o suporte do H2 e do JPA neste projeto. Retorne à pasta Downloads e entre na pasta descompactada do H2; vamos copiar a biblioteca do banco para as bibliotecas do tomcat:
O h2 deverá então ser listado como uma das bibliotecas do tomcat dentro do projeto eclipse:
Como visto em tutoriais anteriores, com JEE a forma correta de configurar o acesso ao banco de dados é via DataSource. Este nós vamos configurar no contexto global do servidor.
Entre no projeto Servers, na pasta de configuração do tomcat 7 e abra o arquivo server.xml, procure a seção GlobalNamingResources:
Adicione nesta seção o seguinte DataSource:
Deve ficar assim:
Agora siga para a pasta do projeto, vamos para WebContent>META-INF. Lá crie um arquivo chamado context.xml com o seguinte conteúdo:
Isso dá à aplicação o direito de usar o DataSource.
Caso fôssemos usar apenas JDBC, nosso trabalho de configuração de banco de dados estaria terminado. Mas agora vamos aos ajustes para usarmos JPA neste projeto. Siga para a pasta onde descompactamos o EclipseLink e copie os jars eclipselink.jar e javax.persistence_2.0.3.v201010191057.jar para a lib do tomcat:
Agora voltamos ao projeto, mas desta vez na pasta src: crie uma pasta chamada META-INF lá:
Crie então dentro desta pasta o arquivo persistence.xml:
java:comp/env/jdbc/agenda-ds exemplo.model.Contato exemplo.model.Endereco
Nas classes Contato e Endereco faça as seguintes modificações:
package exemplo.model; import java.util.List; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; @Entity public class Contato { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private long id; private String nome; private String telefone; @OneToMany private Listenderecos; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getTelefone() { return telefone; } public void setTelefone(String telefone) { this.telefone = telefone; } public List getEnderecos() { return enderecos; } public void setEnderecos(List enderecos) { this.enderecos = enderecos; } }
package exemplo.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; @Entity public class Endereco { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private long id; private String rua; private int numero; private String complemento; @ManyToOne @JoinColumn(name = "CONTATO_ID", referencedColumnName = "ID") private Contato contato; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getRua() { return rua; } public void setRua(String rua) { this.rua = rua; } public int getNumero() { return numero; } public void setNumero(int numero) { this.numero = numero; } public String getComplemento() { return complemento; } public void setComplemento(String complemento) { this.complemento = complemento; } public Contato getContato() { return contato; } public void setContato(Contato contato) { this.contato = contato; } }
Como estamos no tomcat e não num AppServer completo, vamos criar um enum utilitário para recuperarmos uma fererência ao EntityManager:
package exemplo.util; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; public enum JPAUtil { INSTANCE; private EntityManagerFactory emf; JPAUtil() { emf = Persistence.createEntityManagerFactory("agenda-pu"); } public EntityManager getEntityManager() { return emf.createEntityManager(); } }
Usaremos ele no servlet Salvar:
package exemplo.controller; import java.io.IOException; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import exemplo.model.Contato; import exemplo.util.JPAUtil; @WebServlet("/vaisalvar") public class Salvar extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { EntityManager em = JPAUtil.INSTANCE.getEntityManager(); String sId = request.getParameter("id").trim(); String sNome = request.getParameter("nome"); String sTelefone = request.getParameter("telefone"); Contato c = null; if (!"".equals(sId)) c = em.find(Contato.class, Long.parseLong(sId)); else c = new Contato(); c.setNome(sNome); c.setTelefone(sTelefone); EntityTransaction t = em.getTransaction(); t.begin(); em.persist(c); t.commit(); // devemos ainda redirecionar para a tela de resultado request.getRequestDispatcher("/sucesso.jsp").forward(request, response); } }
Siga para o sucesso.jsp e adicione o seguinte código a seguir. Ele serve apenas para desviar o usuário da tela atual. Aproveite e crie logo o index.jsp que vai a seguir:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head>Sucesso! </head> <body>Sucesso!
<script type="text/javascript"> setTimeout(function() { window.location.href = 'index.jsp'; }, 3000); </script> </body> </html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head>Agenda </head> <body> Novo Contato
Listar Contatos </body> </html>
Criaremos agora o servlet de listagem de contatos. Faça do mesmo jeito que você fez com o servlet anterior, e mude o conteúdo dele para o que vem abaixo:
package exemplo.controller; import java.io.IOException; import java.util.List; import javax.persistence.EntityManager; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import exemplo.model.Contato; import exemplo.util.JPAUtil; /** * Servlet implementation class Listar */ @WebServlet("/vailistar") public class Listar extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { EntityManager em = JPAUtil.INSTANCE.getEntityManager(); Listcontatos = // em.createQuery("select c from Contato c", Contato.class)// .getResultList(); request.setAttribute("contatos", contatos); request.getRequestDispatcher("/listar_contatos.jsp")// .forward(request, response); } }
O workspace deve estar ficando assim:
Observe que desta vez o redirecionamento é para listar_contatos.jsp e não para o sucesso.jsp; Em se tratando de Aplicações Action-Based, no caso de listagens devemos navegar para o controlador primeiro e só então irmos para a apresentação.
Este jsp ainda não existe, então vá e crie-o com o seguinte conteúdo:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%--declaração da taglib --%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head>Listar Contatos </head> <body> </body> </html>
Aqui um ponto interessante: este jsp deve surgir para você com um erro na liha de declaração da taglib. Deve estar mais ou menos assim:
A correção deste problema é muito simples, siga para a pasta do tomcat, entre em webapps>examples>WEB-INF/lib:
Copie e cole os dois jars ali presentes para a pasta WebContent>WEB-INF>lib do projeto:
Feito isso, um simples project>clean deve sumir com o alerta de erro:
Dando continuidade ao jsp, modifique-o para ficar assim:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%--declaração da taglib --%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head>Listar Contatos </head> <body>
Id | Nome | Telefone | Endereços |
---|---|---|---|
${contato.id} | ${contato.nome} | ${contato.telefone} | Ver | Novo |
Com jstl fica muito melhor manipular os dados que o servidor encaminha para o jsp.
Observe que criaremos dois novos servlets, um para listar endereços e outro para salvar endereços, além dos jsp's com o formulário para receber os dados de endereço e o que recebe a listagem. Primeiro os arquivos do fluxo de listagem:
package exemplo.controller; import java.io.IOException; import java.util.List; import javax.persistence.EntityManager; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import exemplo.model.Endereco; import exemplo.util.JPAUtil; /** * Servlet implementation class ListarEndereco */ @WebServlet("/vailistarendereco") public class ListarEndereco extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String sId = request.getParameter("contatoid"); long idContato = Long.parseLong(sId); Listenderecos = null; EntityManager em = JPAUtil.INSTANCE.getEntityManager(); String q = "select e from Endereco e where e.contato.id = :id"; enderecos = em.createQuery(q, Endereco.class)// .setParameter("id", idContato).getResultList(); request.setAttribute("enderecos", enderecos); request.getRequestDispatcher("/listar_enderecos.jsp")// .forward(request, response); } }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head>Listar Endreços </head> <body>Listar Endreços do Contato ${param.contatoid}
Id | Rua | Número | Complemento |
---|---|---|---|
${e.id} | ${e.rua} | ${e.numero} | ${e.complemento} |
Agora o fluxo de salvamento:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head></body> </html>Salvar Endereços </head> <body>
package exemplo.controller; import java.io.IOException; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import exemplo.model.Contato; import exemplo.model.Endereco; import exemplo.util.JPAUtil; /** * Servlet implementation class SalvarEndereco */ @WebServlet("/vaisalvarendereco") public class SalvarEndereco extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String sIdContato = request.getParameter("idcontato"); String sId = request.getParameter("id"); String rua = request.getParameter("rua"); String sNumero = request.getParameter("numero"); String complemento = request.getParameter("complemento"); EntityManager em = JPAUtil.INSTANCE.getEntityManager(); Endereco e = null; if (!"".equals(sId)) e = em.find(Endereco.class, Long.parseLong(sId)); else { e = new Endereco(); long contatoId = Long.parseLong(sIdContato); Contato c = em.find(Contato.class, contatoId); e.setContato(c); } e.setRua(rua); e.setNumero(Integer.parseInt(sNumero)); e.setComplemento(complemento); EntityTransaction tx = em.getTransaction(); tx.begin(); em.persist(e); tx.commit(); request.getRequestDispatcher("/sucesso.jsp").forward(request, response); } }
Com isso você terá uma aplicação completamente funcional, simples de entender e que mostra o básico de um projeto web com JPA. Reinicie o tomcat e visite a aplicação em http://localhost:8080/agenda e tente salvar alguns contatos e adicionar endereços.
Detalhes relevantes mas que não mostrei aqui:
- Usar JPA integrado com JEE fullstack é muito mais simples do que mostrei aqui; não precisamos, por exemplo, baixar as libs do EclipseLink, pois normalmente o AppServer já tem uma biblioteca de propósito equivalente dentro de sua runtime básica.
- O trecho transacional, visto em todos os casos em que precisamos salvar entidades, é desnecessário caso usemos o EntityManager de dentro de um EJB.
- A propriedade especial que colocamos no persistence.xml não é padrão, caso a sua implementação de JPA seja o Hibernate, existe uma chave equivalente mas o nome é outro.
Espero que o tutorial lhe seja útil, hoje paramos por aqui.
Até mais.
Nenhum comentário :
Postar um comentário