Utilizar um WebService é uma das maneiras mais comuns de se integrar aplicações diferentes. Existem diferentes tipos de arquiteturas para web services, e o RESTful é mais simples em comparação aos outros web services, que geralmente utilizam o SOAP.
Dada essa simplicidade, isso faz com que a arquitetura RESTful seja uma escolha popular principalmente para serviços abertos ao público. Por exemplo, o Twitter possui uma API Restful. Além do Twitter, o Flickr também possui uma API que segue os princípios da arquitetura REST. De certa forma é uma tendência que os serviços conhecidos como a “Web 2.0″ disponibilizem uma API (geralmente REST), pois é cada vez maior a necessidade que esses serviços sejam integrados com diversos tipos aplicações.
Características de um web service RESTful
Este post não pretende explicar a fundo o que é REST, ou explicar todos os príncipios da arquitetura, pretende apenas mostrar uma introdução de como desenvolver o web service. Para quem quiser estudar mais a fundo a definição da arquitetura, existe disponível a própria tese do Roy Fielding sobre o tema. O artigo sobre REST na Wikipedia também é uma boa referência. Porém, para uma breve introdução como a que será mostrada aqui, não é necessário conhecer todos os termos e princípios.
O que é importante ter em mente é que o principal em um restful web service são as URLs do sistema (geralmente são referidas como restful url’s), e os resources. Um resource é um recurso, uma entidade, ou seja, é um objeto com informação que será representado por meio de um XML. Em geral, a URL para acessar esse recurso será sempre a mesma, porém caso mudemos o método HTTP (GET, POST, PUT, DELETE) o resultado da requisição será diferente. Veja os exemplos tabela abaixo:
| Método | exemplo.com/recurso | exemplo.com/recurso/1 |
|---|---|---|
| GET | lista os recursos | detalhes de um recurso |
| POST | adiciona um recurso | - |
| PUT | - | atualiza um recurso |
| DELETE | - | remove um recurso |
Porém saiba que no REST não existe um padrão definido, as operações listadas acima são apenas uma sugestão. Ao desenvolver um web service você não é obrigado a implementar todas as operações para seguir um determinado padrão, você só precisa implementar o que é necessário no seu contexto. Por exemplo, eu posso decidir que os recursos não podem ser apagados e não implementar nenhuma operação para o método DELETE. O que deve ser levado em consideração é a convenção das ações. GET deve ser usado para “leitura”, por exemplo listar os detalhes de um recurso. POST deve ser usado para adicionar novos recursos. PUT deve ser utilizado para alterar recursos já existentes. E DELETE para apagar recursos.
JAX-RS e Jersey
O JAX-RS é uma especificação (a JSR-311) que define a criação de um WebService com arquitetura RESTful. Na sua API, são utilizadas anotações, que simplificam a necessidade extra de configurações. Atualmente, o JAX-RS é parte integrante do Java EE.
Como o JAX-RS é apenas uma especificação, é necessário escolher uma implementação. Entre os projetos que o implementam, temos o Jersey, que é open source e mantido pela Oracle, e que é a
implementação de referência do JAX-RS.
Configurando o ambiente
O Jersey deve ser baixado no seu site oficial. Atualmente está na versão 1.4. Haverá duas opções, uma é um arquivo zip com todas as dependências e documentação inclusas.
A outra é o jersey-bundle, um jar que já inclui todas as dependências necessárias. Neste exemplo, vamos utilizar o zip mesmo. Haverão quatro jars que devem ser adicionados ao projeto:
- asm.jar
- jersey-core
- jersey-server
- jsr311-api
Estes são os jars obrigatórios em qualquer projeto utilizando o Jersey. Claro que se você quiser mais funcionalidades, como o suporte a JSON terá que adicionar mais jars, como o jersey-json, por exemplo.
No caso do JAX-RS, para rodar o nosso web service RESTful é necessário um Web Container. No exemplo irei utilizar o Tomcat, porém qualquer outro WebContainer como o Jetty, ou
mesmo um servidor de aplicação Java EE como o Glassfish ou o JBoss, que já possuem um WebContainer, funcionariam do mesmo jeito. Para começar, devemos criar um projeto do tipo Dynamic Web Project no Eclipse.
Em seguida, dê um nome ao projeto e selecione o WebContainer (target runtime). Escolhi como nome jersey-tutorial e o Tomcat, como disse anteriormente.
Copie as jars anteriormente para a pasta WebContent/WEB-INF/lib, e pronto, já podemos começar a escrever um pouco de código.
Criando o WebService
Primeiro vamos fazer o famigerado “Hello World” apenas para testar se o ambiente está configurado corretamente. Veja a classe abaixo:
package com.k19.restful.resources;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("/helloworld")
public class HelloWorldResource {
@GET
@Produces("text/plain")
public String showHelloWorld() {
return "Olá mundo!";
}
}
Antes de rodar o exemplo, devemos configurar o web.xml e cadastrar a servlet do Jersey. Preste atenção que devemos passar um parâmetro na inicialização. Esse parâmetro corresponde ao pacote onde estão os nossos resources. Basta seguir o exemplo conforme abaixo:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>jersey-tutorial</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.k19.restful.resources</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Ao tentar rodar o exemplo pela primeira vez, possivelmente o Eclipse mostrará uma caixa de diálogo para escolher qual servidor utilizar. Lembre-se que você já deve ter o Tomcat instalado e configurado no Eclipse para que ele apareça como uma das opções. Bem, após clicar no botão de executar, caso não tenha aparecido nenhuma exception, podemos testar acessando http://localhost:8080/jersey-tutorial/helloworld na barra de endereços do navegador. Altere a URL caso você tenha dado um nome diferente para a aplicação, ou tenha configurado o Tomcat em outra porta. Se tudo estiver certo, você deve ver a mensagem “Olá mundo!”. Nada muito complicado, mas já é o suficiente para saber que está funcionando.
Anotações
Pelo nosso exemplo anterior, já vimos o Jersey em ação e a única coisa que nós fizemos foi adicionar algumas anotações à nossa classe. O Jersey é todo baseado em anotações, e existem várias delas. Vamos listar as mais importantes.
- @Path – essa anotação recebe uma string como parâmentro e indica qual é o path da URL. No exemplo anterior, tivemos a classe anotada com o valor ”/helloworld”, e por isso que acessamos a URL como http://localhost:8080/jersey-tutorial/helloworld.
- @GET – anotação que indica qual o método correspondente do HTTP. Como dito anteriormente, podemos ter a mesma URL para ações diferentes desde que o método HTTP também seja diferente. Da mesma forma, temos as anotações @POST, @PUT e @DELETE.
- @Produces – anotação que indica qual o mime-type do conteúdo da resposta que será enviada para o cliente. No exemplo acima, foi “text/plain” para indicar que é texto puro. Em um web service isso é pouco usual, em geral vamos utilizar valores como “text/xml” para devolver XML.
- @Consumes – anotação que indica qual o mime-type do conteúdo da requisição. Em geral é utilizado principalmente em requisições do tipo POST ou PUT, em que o cliente precisa enviar a informação do que ele deseja adicionar/alterar. Do mesmo jeito que o web service “devolve” XML, ele pode “consumir” (receber) conteúdo XML.
Exemplo de CRUD
Agora vamos fazer um exemplo bem simples de CRUD. Primeiro vamos precisar de uma entidade, um bean para conter as informações que nós queremos manipular. Veja o exemplo abaixo:
package br.com.k19.models;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Banda {
private String nome;
private int anoDeFormacao;
private int id;
// getters e setters
}
Note a presença da anotação @XmlRootElement na definição da nossa classe. Ela é fundamental para que o Jersey conheça a representação do objeto banda em XML. Desse modo os atributos irão se tornar nós no momento em que o XML for enviado ao cliente. E do mesmo jeito, quando chegar um XML no corpo de uma requisição, o Jersey vai saber converter esse XML em um objeto do tipo Banda.
O próximo passo é criar o nosso WebResource. No mundo real, geralmente você vai ter uma tabela “Banda” em alguma base de dados e vai desejar buscar a informação quando for requisitado. Aqui para que o exemplo fique mais simples e a gente mantenha o foco apenas na funcionalidade do Jersey, vamos utilizar um Map para simular a nossa base de dados. Veja o exemplo abaixo:
package br.com.k19.resources;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import br.com.k19.models.Banda;
@Path("/bandas")
public class BandaResource {
// vamos utilizar um Map estático para
// "simular" uma base de dados
static private Map<Integer, Banda> bandasMap;
static {
bandasMap = new HashMap<Integer, Banda>();
Banda b1 = new Banda();
b1.setId(1);
b1.setNome("Led Zeppelin");
b1.setAnoDeFormacao(1968);
bandasMap.put(b1.getId(), b1);
Banda b2 = new Banda();
b2.setId(2);
b2.setNome("AC/DC");
b2.setAnoDeFormacao(1973);
bandasMap.put(b2.getId(), b2);
}
@GET
@Produces("text/xml")
public List<Banda> getBandas() {
return new ArrayList<Banda>(bandasMap.values());
}
// continua depois ...
Para testar, basta acessar a url http://localhost:8080/jersey-tutorial/bandas em qualquer navegador, que o resultado será um XML parecido com esse:
<bandas>
<banda>
<anoDeFormacao>1968</anoDeFormacao>
<id>1</id>
<nome>Led Zeppelin</nome>
</banda>
<banda>
<anoDeFormacaov1973</anoDeFormacao>
<id>2</id>
<nome>AC/DC</nome>
</banda>
</bandas>
E caso queiramos listar apenas uma banda em vez de todas? Também podemos incluir a anotação @Path nos métodos igual ao exemplo abaixo:
@Path("{id}")
@GET
@Produces("text/xml")
public Banda getBanda(@PathParam("id") int id) {
return bandasMap.get(id);
}
Nesse caso, a url para acessar o recurso passa a ser http://localhost:8080/jersey-tutorial/bandas/{id}. As chaves indicam que id é um parâmetro, assim podemos passar diferentes valores para acessar diferentes recursos. Note também o uso da anotação @PathParam no parâmetro id, que serve para indicar que o parâmetro do método se refere ao parâmetro no path. Como teste, podemos acessar http://localhost:8080/jersey-tutorial/bandas/1 e ver algo parecido com o XML abaixo:
<banda>
<anoDeFormacao>1968</anoDeFormacao>
<id>1</id>
<nome>Led Zeppelin</nome>
</banda>
Agora que conseguimos listar as bandas, precisamos também de uma maneira de adicioná-las. Veja o exemplo abaixo:
@POST
@Consumes("text/xml")
@Produces("text/plain")
public String adicionaBanda(Banda banda) {
banda.setId(bandasMap.size() + 1);
bandasMap.put(banda.getId(), banda);
return banda.getNome() + " adicionado.";
}
Temos uma mudança de método do HTTP, de GET passou para POST. Fora essa mudança, a URL é a mesma de quando listávamos todas as bandas, ou seja, http://localhost:8080/jersey-tutorial/bandas. E agora também recebemos (ou consumimos) um XML que vai representar a banda. E se você reparar bem, também vê que o nosso método recebe uma banda como parâmetro.
É isso mesmo que você está pensando, o objeto banda é instanciado pelo Jersey e será preenchido com os valores do XML que vierem no conteúdo da requisição. O problema é que agora não temos como testar usando simplesmente o navegador, porque o padrão é que ele execute as requisições como GET, e não teríamos como enviar o XML contendo as informações da nova banda. Para quem
usa Firefox, uma opção é utilizar o add-on Poster, que permite customizar a requisição de várias maneiras, alterando headers, adicionando conteúdo, etc. Outra opção para quem usa linux, é usar o
comando curl. Veja um exemplo para adicionar uma banda:
$ curl -X POST -H "Content-type:text/xml" \
-d "<banda><nome>Teste</nome><anoDeFormacao>2010</anoDeFormacao></banda>" \
http://localhost:8080/jersey-tutorial/bandas
O parâmetro -X serve para alterar o método HTTP. O -H serve para alterar o cabeçalho da requisição. Nesse caso precisamos alterar para informar que estamos enviando um XML. O parâmetro -d são os dados que serão enviados no conteúdo da requisição. E por fim passamos a URL.
Abaixo temos o restante do exemplo de CRUD, com as operações para atualizar e remover bandas. O exemplo com PUT é bem semelhante ao de adicionar uma nova banda, a diferença é que devemos atualizar uma banda já existente. Já o exemplo do DELETE é ainda mais simples, pois não precisamos consumir nenhum XML, apenas identificamos o id pela URL e excluímos a banda correspondente.
@Path("{id}")
@PUT
@Consumes("text/xml")
@Produces("text/plain")
public String atualizaBanda(Banda banda, @PathParam("id") int id) {
Banda atual = bandasMap.get(id);
atual.setNome(banda.getNome());
atual.setAnoDeFormacao(banda.getAnoDeFormacao());
return banda.getNome() + " atualizada.";
}
@Path("{id}")
@DELETE
@Produces("text/plain")
public String removeBanda(@PathParam("id") int id) {
bandasMap.remove(id);
return "Banda removida.";
}
Concluindo
Esta foi uma rápida introdução ao JAX-RS e ao Jersey, apenas para servir de ponto de partida. Existem muito mais detalhes na documentação oficial.
Em breve teremos mais exemplos, mostrando como utilizar JSON e como desenvolver um Cliente em Java utilizando as classes do Jersey.
Download do código: jersey-tutorial.zip
Tags: java, restful, webservice


[...] Criando um WebService Restful em Java [...]
Oi tudo bem?
Kra eu to tentando fazer exatemente isso..
O problema é que tenho que me conectar com um webservice externo passar um xml e ele me responder um xml.
Não teria que usar o HttpClient?
@Path(“{id}”)
@PUT
@Consumes(“text/xml”)
@Produces(“text/plain”)
public String atualizaBanda(Banda banda, @PathParam(“id”) int id)
O que dizer exatamente esse codigo?
Obrigado pela ajuda e por essa artigo incrivel.
Att, Erich.
Olá Erich,
Nesse artigo eu mostrei apenas como criar o WebService, e não o lado do cliente que consome o WebService. Então, sim, você está certo, no seu caso vc deve usar o HttpClient pois o WebService já está pronto e vc quer apenas consumí-lo. Mas caso o WebService para o qual vc precisa enviar o XML também for RESTful (igual ao exemplo deste artigo), eu recomendo usar o jersey-client, pois vai tornar o seu trabalho mais simples. Eu já respondi uma dúvida bem parecida no GUJ e até coloquei um código como exemplo, caso vc queira dar uma olhada http://www.guj.com.br/java/227376-integracao-com-webservice-via-xml#1165917
Já o código que vc ficou com dúvida, é um método que vai ser chamado quando chegar um request com verbo PUT, e que deve trazer um XML no conteúdo da requisição. É bem parecido com o exemplo de POST que serve para criar bandas, a diferença é que o PUT deve ser utilizado para atualizar uma banda que já existe. Para testar com o curl basta digitar o seguinte comando no terminal (se for Linux):
$ curl -X PUT -H “Content-type:text/xml” \Led Zeppelin 2010 ” \
-d “
http://localhost:8080/jersey-tutorial/bandas/1
Veja que a diferença para o exemplo do POST é que mudamos o verbo para PUT e adicionamos o id na URL da requisição, indicando qual a banda que vai ser atualizada.
Gostei do tutorial! Valeu ae man!
excelente. me ajudou bastante agora.