Good news everyone! Hoje vamos ver um longo tutorial que vai do zero ao aplicativo rodando em um tomcat 7 usando JAX-RS!
De modo a produzirmos exatamente os resultados esperados e vistos quando escrevi isso aqui, os seguintes pré-requisitos devem ser respeitados:
1- Linux Fedora 15 (64 bits)
2- eclipse indigo (3.7)
3- Sun/Oracle Java ou OpenJDK, versão 6
4- mysql 5.1 (padrão no opensuse 11.4)
5- Jersery 1.10
6- tomat 7.0.22
Claro, pequenas variações podem dar certo também, e os passos que apresentaremos podem servir de referencial para soluções parecidas.
Abaixo nosso roteiro:
1- instalar o mysql
2- configurar o mysql
3- instalar o eclipse (e o java)
4- instalar o tomcat 7.0
5- configurar o tomcat 7.0 (no eclipse, criar o Resource do mysql no globalnamingresource, driver jdbc do mysql)
6- escrever pequena agenda de exemplo
No Fedora 15 a ferramenta de linha de comando que instala automagicamente os programas é o yum.
Digite o seguinte comando no terminal para instalar o servidor de banco de dados e o suporte a conexão via java:
sudo yum install mysql-server mysql-connector-java
A ‘parte java’ do processo abordaremos mais à frente. Vamos por hora apenas colocar o banco pra rodar:
sudo service mysqld start
A instalação padrão vem desprotegida; você pode pesquisar em separado como ativar a segurança do mysql, é um assunto bastante conhecido e não preciso repeti-lo aqui.
Vamos criar o banco de dados e o usuário para a aplicação de exemplo que mostraremos bem mais à frente:
mysql -u root
O prompt do mysql surgirá e nele iremos criar o banco de dados:
create database agenda;
Em seguida damos grant ao usuário e apresentamos uma senha:
grant all privileges on agenda.* to useragenda@localhost identified by 'senha';
flush privileges;
Agora vamos fazer login com o usuário que criamos. No terminal do mysql, dê um CTRL+D (terminará a seção e retornará ao shell) e faça login da seguinte forma:
mysql -D agenda -u useragenda -p
Enter password:
A senha não será ecoada. Crie a tabela de contatos utilizando o seguinte SQL:
create table tb_contatos( id integer not null primary key auto_increment, nome varchar(300) not null, endereco varchar(600) not null, telefone varchar(8), data_nascimento date);
Assim o banco estará pronto para usar. Atenção ao nome do banco, do usuário e senha; precisaremos destes dados mais adiante.
Agora é hora de providenciarmos as ferramentas java; comecemos pelo openjdk disponível no repositório do Fedora 15:
sudo yum install java-1.6.0-openjdk-devel.x86_64
Alguns pacotes tem nomes longos, e saber exatamente o que instalar pode dar algum trabalho. É possível fazer uma busca por parte do nome, coisa que facilita encontrar o que se precisa:
sudo yum search openjdk
Na lista de resultados você encontrará o que precisa, 🙂
Dando continuidade, providenciaremos os downloads do eclipse, do tomcat e do jersey framework. Há um eclipse disponível nos repositórios do fedora, entretanto você encontrará mais pessoas usando o eclipse fornecido diretamente pela fundação eclipse.
Baixe os seguintes arquivos:
Atenção: embora eu já tenha esclarecido, reforço: o Fedora escolhido foi o 64 bits; isto influencia no download do elipse, que também será aa versão para linux em 64 bits, pois o eclipse possui uma parte nativa. Mas isto é outra história.
Descompacte o eclipe e o tomcat na sua pasta home, entre na pasta do eclipse e execute-o. A seguinte tela surgirá:
Feche o welcome e vá na aba servers. Este eclipse é o JEE – Java Enterprise Edition. Quem trabalha a sério com java baixa esta versão, mesmo que não vá escrever nada para a WEB no momento.
Crie um novo servidor:
Use o filtro, procure por tomcat v7. será a opção a aparecer na caixa logo abaixo. Indique em seguida o caminho da pasta do tomcat:
O projeto Servers será criado. Ele contém as configurações que este tomcat “capturado” pelo eclipe utilizará por padrão. Você pode fazer o eclipse usar a configuraação de dentro do próprio tomcat bem facilmente, mas deixo isso por sua conta, 😉
Abra o projeto Servers, entre na pasta do tomcat que foi configurado, abra o xml chamado server.xml e selecione a aba source já no editor; ela fica no rodapé do editor. Aí sim você terá acesso ao conteúdo do xml.
Procure a sessão GlobalNamingResources; lá adicione a configuração do datasource para o mysql:
<Resource name="jdbc/agenda" driverClassName="com.mysql.jdbc.Driver" type="javax.sql.DataSource" url="jdbc:mysql://localhost/agenda" auth="Container" username="useragenda" password="senha" maxActive="30" maxIdle="3" />
O xml resultante deve se parecer com o seguinte:
Observe o banco, usuário e senha: tem de ser os mesmos utilizados anteriormente, na configuração do mysql.
Não basta o xml, o driver JDBC do mysql, que baixamos lá no início do tutorial, deve ser copiado para a pasta lib do tomcat.
Você encontrará este driver na pasta “/usr/share/java”, copie o driver de nome “mysql-connector-java-5.1.15.jar”; o outro arquivo de nome mais simples é um link simbólico para este aqui.
Como deve ficar a lib do tomcat:
Agora, vamos criar a aplicação java que consumirá este datasource. A aplicação não terá pistas sobre que banco de dados é este ou onde ele se encontra; apenas saberá o name do Resource: “jdbc/agenda”; é assim que a especificação espera que você use recursos.
É bem simples criar uma aplicação web em java usando esta versão do eclipse; tem um botão que faz quase tudo hoje em dia:
No wizard basta você dar o nome do projeto. Observe que a versão do webmodule será a 3.0, ou seja, salvo uma exceção, sem arquivos xml de configuração dentro do projeto da aplicação. Até outro dia isto era impensável em projetos java, hoje é regra.
Vá até o zip do framework jersey agora. Descompacte, entre na pasta lib:
Copie todos os .jar para dentro da pasta lib do projeto no eclipse.
A partir desta parte, a parte final, este tutorial torna-se diferente dos tutoriais comumente vistos sobre JEE. Nada de Servlets, JSF-ismos ou EJB’s: iremos criar REST Resources!
O passo inicial é criar o “entry point” da aplicação JAX-RS. Basta criar uma classe que estenda de “javax.ws.rs.core.Application”, no nosso exemplo a classe App:
package org.sample.jaxrs; import java.util.Set; import java.util.TreeSet; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("/resource") public class App extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> set = new TreeSet<Class<?>>(); set.add(ContatoResource.class); return set; } }
Esta será também a raíz de todas as chamadas do serviço REST. O propósito do método getClasses é listar os Recursos anotados com os caminhos e verbos HTTP.
Vamos ver o recurso REST:
package org.sample.jaxrs; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import javax.naming.InitialContext; import javax.sql.DataSource; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @Path("/contato") public class ContatoResource { @GET public List<ContatoBean> listContatos() throws Exception { List<ContatoBean> ret = new ArrayList<ContatoBean>(); DataSource ds = (DataSource) new InitialContext() .lookup("java:comp/env/jdbc/agenda"); Connection con = ds.getConnection(); Statement stm = con.createStatement(); ResultSet rs = stm .executeQuery("select id,nome,endereco,telefone,data_nascimento from tb_contatos"); while (rs.next()) { ret.add(new ContatoBean(rs.getInt(1), // rs.getString(2), // rs.getString(3), // rs.getString(4), // rs.getDate(5))); } rs.close(); stm.close(); con.close(); return ret; } @POST public void addContato(ContatoBean c) throws Exception { DataSource ds = (DataSource) new InitialContext() .lookup("java:comp/env/jdbc/agenda"); Connection con = ds.getConnection(); PreparedStatement pst = con .prepareStatement("insert into tb_contatos(nome,endereco,telefone, data_nascimento) values (?,?,?,?)"); pst.setString(1, c.getNome()); pst.setString(2, c.getEndereco()); pst.setString(3, c.getTelefone()); pst.setDate(4, new Date(c.getDataNasc().getTime())); pst.executeUpdate(); pst.close(); con.close(); } }
Embora esteja perfeitamente em ordem, e no glassfish e outros servidors JEE6 certificados código similar funcione corretamente, um ajuste será necessário em nossas configurações de projeto específicas para o tomcat. Crie um arquivo chamado context.xml dentro da pasta META-INF que se encontra dentro da pasta WebContent. O arquivo deverá conter esta configuração:
<Context> <ResourceLink name="jdbc/agenda" global="jdbc/agenda" type="javax.sql.DataSource"/> </Context>
A classe ContatoBean é um pojo simples com anotações do JAXB:
package org.sample.jaxrs; import java.util.Date; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; @XmlRootElement @XmlType(name = "contato") @XmlAccessorType(XmlAccessType.FIELD) public class ContatoBean { private int id; private String nome; private String endereco; private String telefone; private Date dataNasc; public ContatoBean() { } public ContatoBean(int id, String nome, String endereco, String telefone, Date dataNasc) { this.id = id; this.nome = nome; this.endereco = endereco; this.telefone = telefone; this.dataNasc = dataNasc; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getEndereco() { return endereco; } public void setEndereco(String endereco) { this.endereco = endereco; } public String getTelefone() { return telefone; } public void setTelefone(String telefone) { this.telefone = telefone; } public Date getDataNasc() { return dataNasc; } public void setDataNasc(Date dataNasc) { this.dataNasc = dataNasc; } }
Estas 3 classes e aquele xml incidental ilustram como é o lado do servidor de aplicações JAX-RS. Vamos ver agora um pequeno cliente javascript para este serviço.
Usando o que foi visto no post anterior (que tratava justamente de submissões de entidades e não de formulários) podemos montar o seguinte cliente (salve-o como index.html dentro de WebContent):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <script type="text/javascript" src="jquery-1.6.4.js"></script> <script type="text/javascript" src="jq-json-post-0.1.js"></script> </head> <body> <label>id:</label> <br /> <span id="idcontato"></span> <br /> <label>Nome:</label> <br /> <input id="nomecontato" /> <br /> <label>Endereço:</label> <br /> <input id="enderecocontato" /> <br /> <label>Telefone:</label> <br /> <input id="telefonecontato" maxlength="8" /> <br /> <button id="salvar">Salvar</button> <hr /> <table> <thead> <tr> <th>id</th> <th>nome</th> <th>endereco</th> <th>telefone</th> <th>data de nascimento</th> </tr> </thead> <tbody id="tabela"> <!-- dynamic content goes here --> </tbody> </table> <script type="text/javascript"> var id = $("#idcontato"); var nome = $("#nomecontato"); var endereco = $("#enderecocontato"); var telefone = $("#telefonecontato"); var salvar = $("#salvar"); var tabela = $("#tabela"); var list = []; function update() { tabela.html(""); for ( var x in list) { var str = "<tr>"; str += "<td>" + list[x]["id"] + "</td>"; str += "<td>" + list[x]["nome"] + "</td>"; str += "<td>" + list[x]["endereco"] + "</td>"; str += "<td>" + list[x]["telefone"] + "</td>"; str += "<td>" + list[x]["dataNasc"] + "</td>"; str += "</tr>"; tabela.append(str); } } salvar.click(function() { $.json_post("resource/contato", { nome : nome.val(), endereco : endereco.val(), telefone : telefone.val(), dataNasc : new Date() }, function() { $.getJSON("resource/contato", function(ret) { if (ret && ret.contatoBean) list = ret.contatoBean; else list = []; update(); }); }); }); </script> </body> </html>
Observe as duas dependências de script. Estas foram apresentadas no post anterior, não irei cobrir aqui.
Embora pouco funcional, este exemplo mostra claramente como podemos, a partir de um formulário, montar rapidamente um objeto JSON e envia-lo para o servidor, onde ele é convertido automaticamente para um objeto java.
Embora longo, este tutorial mostra o básico para montar um ambiente JAX-RS dentro do tomcat, cobrindo, de fato, mais passos de configuração do que fetivamente o código necessário para publicar recursos REST. De certo modo isto é bom, pois há pouco código a produzir ou configurar uma vez que o JAX-RS resolve de maneira elegante a tradução de objetos e o roteamento dos serviços.
Caso escolhessemos um outro conjunto de tecnologias (glassfish ou jboss no lugar do tomcat) talvez o número de passos fosse menor.
Encerrando, espero que isto lhe seja útil, combine com outros conhecimentos e produza algo ainda melhor!
Pingback: Cliente android consumindo REST de forma transparente, fácil e rápida « sombriks have a plan
não é necessário configurar o realm para jdbc realm?
Olá adriel,
Um Realm só se eu fosse exemplificar a parte de segurança, que não contemplei neste tutorial.
E este blog não recebe mais atualizações, as novidades vão aparecer nesse: http://sombriks.blogspot.com.br/