Skip to content


WebServicesREST – Aplicando a JSR-311 e Jersey ao processo de leilão

Aplicando a JSR-311 e o Jersey nos serviços de leilão

Nesta seção mostraremos como usar o Jersey para implementar os serviços do processo de leilão. Devido às limitações de espaço, escolhemos apenas uma parte dos serviços, mas de forma que seja possível ilustrar com clareza as diferenças.

A primeira etapa necessária é a configuração do Jersey no projeto. A distribuição binária estável mais recente no momento da escrita deste artigo é a 0.7. Esta distribuição pode ser obtida no site do projeto.

Devemos mapear todos os prefixos de URIs dos nossos serviços para um Servlet do Jersey. O trecho abaixo mostra um web.xml configurado com este mapeamento. Na nossa aplicação, como todas as URIs são de serviços REST, mapeamos toda a aplicação (/*) para o Servlet do Jersey.

<?xml version="1.0" encoding="UTF-8"?>
 
<web-app>
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.ws.rest.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.ws.rest.config.feature.Redirect</param-name>
<param-value>true</param-value>
</init-param>
 
<init-param>
<param-name>com.sun.ws.rest.config.feature.ImplicitViewables</param-name>
<param-value>true</param-value>
</init-param>
 
<load-on-startup>1</load-on-startup>
 
</servlet>
 
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
 
</web-app>

Além da configuração do Servlet, precisamos adicionar algumas bibliotecas para utilizar o Jersey. O conjunto mínimo de bibliotecas que devem ser colocadas na aplicação inclui o jersey.jar, jsr311-api.jar e asm.jar. Estas bibliotecas e mais algumas dependências estão presentes no diretório /lib da distribuição binária do Jersey.

Se não estiver usando Java SE 6 ou Java EE 5, você também precisará adicionar o JAXB ao projeto. Utilizando um servidor de aplicações Java EE 5 e as bibliotecas presentes na distribuição binária do projeto, você tem a garantia de ter todas as dependências necessárias.

Desenvolvimento dos serviços

Mostraremos agora como pode ser feita a implementação de alguns serviços do processo de leilão com o uso do Jersey. Somente um subconjunto dos serviços será apresentado neste artigo, mas a implementação completa pode ser vista no código fonte.

Começaremos pelos serviços correspondentes ao prefixo /usuario e depois falaremos também sobre os serviços do prefixo /avaliacao. A Tabela 4 lista os serviços que apresentaremos neste artigo.

URI

Método

Formato

Efeito

/usuario

POST

Usuario

Cadastra um usuário.

/usuario/{id}

GET

Usuario

Busca um usuário.

PUT

Usuario

Atualiza um usuário.

/usuario/{id}/avaliacoes

GET

Coleção de avaliações

Busca as avaliações recebidas por um usuário.

/usuario/{id}/itens

GET

Coleção de itens

Busca os itens anunciados por um determinado usuário.

POST

Item

Usuário coloca novo item à venda.

/avaliacao/{id}

GET

Avaliação

Busca uma determinada avaliação.

/avaliacao/de/{id}/para/{id}

POST

Avaliação

Realização da avaliação de um usuário sobre outro.

A listagem abaixo apresenta a classe UsuarioResource. Esta é uma das classes Recurso da nossa aplicação e nela estão todos os serviços do prefixo /usuario. A classe foi anotada com @Path(“usuario”), o que faz a associação da mesma com o prefixo citado. Além disso, a classe possui as anotações @ConsumeMime e @ProduceMime, que neste caso declaram que os serviços da mesma são capazes de consumir e gerar conteúdo nos formatos text/xml e application/json.

@Path("usuario")
@ConsumeMime( { "text/xml", "application/json" })
@ProduceMime( { "text/xml", "application/json" })
public class UsuarioResource {
 
private ItemService itemService;
private UsuarioService usuarioService;
private AvaliacaoService avaliacaoService;
 
public UsuarioResource() {
this.itemService = ServiceFactory.getItemService();
this.usuarioService = ServiceFactory.getUsuarioService();
this.avaliacaoService = ServiceFactory.getAvaliacaoService();
}
 
@GET
@Path("{usuarioId}")
public Response buscarUsuario(@PathParam("usuarioId") String usuarioId) {
Usuario usuario = usuarioService.buscar(usuarioId);
if(usuario == null){
return Response.status(HttpServletResponse.SC_NOT_FOUND).build();
}
Response resposta = Response.ok(usuario).build();
return resposta;
}
 
@POST
public Response cadastrarUsuario(Usuario usuario) {
usuario = usuarioService.cadastrar(usuario);
try {
return Response.created(new URI(usuario.getCodUsuario())).build();
} catch (URISyntaxException e) { throw new RuntimeException(e); }
}
 
@PUT
@Path("{usuarioId}")
public Response atualizarUsuario(Usuario usuario) {
usuarioService.atualizar(usuario);
return Response.ok().build();
}
 
@POST
@Path("{usuarioId}/itens")
public Response cadastrarItem(@Context UriInfo uriInfo, @PathParam("usuarioId") String usuarioId, Item item) throws URISyntaxException {
Usuario usuario = new Usuario(usuarioId);
item = itemService.cadastrar(item, usuario);
URI uriItem = new URI(uriInfo.getBaseUri() + "item/" + item.getCodItem());
return Response.created(uriItem).build();
}
 
@GET
@Path("{usuarioId}/itens")
public Response buscarItensDoUsuario(@PathParam("usuarioId") String usuarioId) {
// Verifica se o usuário existe
if (this.usuarioService.buscar(usuarioId) == null) {
return Response.status(Status.NOT_FOUND).build();
}
 
List itens = itemService.buscarPorVendedor(new Usuario(usuarioId));
return Response.ok(new ItensUsuario(itens)).build();
}
 
@GET
@Path("{usuarioId}/avaliacoes")
public AvaliacoesUsuario buscarAvaliacoesDoUsuario(@PathParam("usuarioId")String usuarioId){
Usuario usuario = new Usuario(usuarioId);
List avaliacoes = avaliacaoService.buscarPorUsuario(usuario);
return new AvaliacoesUsuario(avaliacoes);
}
 
}

O primeiro serviço é o de busca de usuário. Este método foi anotado com @Path(“{usuarioId}”). O casamento da anotação sobre o método com a anotação sobre a classe especifica que este método responde a requisições para a URI /usuario/{usuarioId}. Como o método também foi anotado com @GET, sabemos que as solicitações HTTP GET para /usuario/{usuarioId} serão tratadas por este método. Importante reparar no uso da anotação @PathParam para injetar no parâmetro usuarioId o valor que veio na URI.

Na resposta a esta solicitação, retornamos o status HTTP 200 (OK) e os dados do usuário no corpo da resposta. Caso o usuário não tenha sido encontrado, retornamos status 404 (Not Found). A listagem abaixo mostra a classe Usuario, que é manipulada por alguns serviços na classe UsuarioResource. Por simplicidade mostramos apenas a declaração da classe com os atributos.

@XmlRootElement
public class Usuario {
private String codUsuario;
private String nome;
private String login;
private String email;
private Item[] items;
private Oferta[] ofertas;
private Avaliacao[] avaliacoes;
}

O segundo serviço presente em UsuarioResource é o de cadastro de usuário. Como não colocamos nenhuma anotação @Path sobre este método, ele está associado à URI da classe (/usuario). O método foi anotado com @POST, então ele responde às solicitações POST na URI citada. O parâmetro contendo os dados do usuário não recebeu nenhuma anotação, o que significa que ele é obtido do corpo da solicitação. Como o método de cadastro de usuário não tem as anotações @ConsumeMime e @ProduceMime, ele herda as declarações feitas sobre a classe. Sendo assim, podemos cadastrar usuários usando text/xml ou application/json. Na resposta à criação do usuário nós enviamos o status HTTP 201 (Created), colocando no header Location a URI do novo usuário.

O método de atualização de usuário recebe solicitações PUT em /usuario/{usuarioId}. Os dados do usuário também são consumidos do corpo da solicitação, e as operações com sucesso resultam no envio do status HTTP 200.

No método de cadastrar itens, usamos a anotação @Path para associar o serviço à URI /usuario/{usuarioId}/itens. Usamos a anotação @PathParam para extrair da URI o ID do usuário envolvido. Usamos também a anotação @Context para injetar a classe UriInfo, que nos fornece informações sobre a URI de acesso aos serviços. No final, usamos a UriInfo para colocar no header Location o caminho absoluto de acesso ao item recém-criado. A listagem abaixo mostra a classe Item, manipulada neste serviço.

@XmlRootElement
public class Item {
private String codItem;
private String nome;
private String descricao;
private BigDecimal valorInicial;
private boolean novo;
private boolean vendido;
}

No método de buscar itens do usuário temos o primeiro serviço que manipula coleções. Este método trata de solicitações GET à URI /usuario/{usuarioId}/itens. Para retornar a lista de itens do usuário foi criada a classe ItensUsuario, que simplesmente contém a lista. A listagem a seguir apresenta a declaração desta classe.

@XmlRootElement
public class ItensUsuario {
 
private List item;
public ItensUsuario() {}
public ItensUsuario(List itens) { this.item = itens; }
}

O método de buscar avaliações do usuário é estruturalmente semelhante ao de buscar itens. Foi criada a classe AvaliacoesUsuario para retornar a lista de avaliações. Como esta é muito semelhante à ItensUsuario, ela será omitida. Para implementar os serviços do prefixo /avaliacao foi criada a classe AvaliacaoResource. Esta classe pode ser vista na listagem a seguir. Temos a anotação @Path registrando a URI desejada e também as anotações @ConsumeMime e @ProduceMime declarando que manipulamos text/xml e application/json.

@Path("avaliacao")
@ConsumeMime( { "text/xml", "application/json" })
@ProduceMime( { "text/xml", "application/json" })
public class AvaliacaoResource {
 
private AvaliacaoService avaliacaoService;
public AvaliacaoResource() {
this.avaliacaoService = ServiceFactory.getAvaliacaoService();
}
 
@GET
@Path("{avaliacaoId}")
public Response buscarAvaliacao(@PathParam("avaliacaoId") String avaliacaoId) {
Avaliacao avaliacao = avaliacaoService.buscar(avaliacaoId);
if(avaliacao == null){
return Response.status(HttpServletResponse.SC_NOT_FOUND).build();
}
return Response.ok(avaliacao).build();
}
 
@POST
@Path("de/{avaliador}/para/{avaliado}")
public Response avaliarUsuario(@Context UriInfo uriInfo, @PathParam("avaliador") String avaliador,
@PathParam("avaliado") String avaliado, Avaliacao avaliacao) throws URISyntaxException {
Usuario usuarioAvaliado = new Usuario(avaliado);
avaliacao = avaliacaoService.cadastrar(avaliacao, usuarioAvaliado);
URI uri = new URI(uriInfo.getBaseUri() + "avaliacao/" + avaliacao.getCodAvaliacao());
return Response.created(uri).build();
}
 
}

O primeiro serviço desta classe é o de busca de avaliação, que é muito semelhante ao serviço de busca de usuário que vimos anteriormente. Este serviço ficou mapeado em /avaliacao/{avaliacaoId}, recebendo solicitações GET.

O serviço de avaliar usuário é mais interessante. Extraímos dois parâmetros da URI e consumimos um recurso do corpo da solicitação. A URI /avaliacao/de/{avaliador}/para/{avaliado} é um bom exemplo da liberdade que temos na definição das URIs. Podemos moldá-las para aumentar a clareza das operações. Isto facilita a aproximação dos serviços com o nosso domínio da aplicação.

AnteriorÍndicePróxima


5 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. A2 says

    Bruno,
    pelo que entendi a classe UsuarioService, por exemplo, seria o handler para operações relacionadas a usuários. Ela iria ao banco buscar as informações q o serviço precisa ou cadastrar algo quando necessário… é isso?

  2. blpsilva says

    Oi A2, a idéia é essa mesmo. As classes Service da aplicação são baseadas no pattern Service Layer proposto pelo Martin Fowler no livro Patterns of Enterprise Application Architecture.

    A idéia é que a camada de serviço (Service Layer) contenha lógica de negócio, faça controle transacional e acesse a camada de persistência para o que for necessário.

  3. Lucas Eskopinski says

    Como que você constuma consumir RESTful Web Services? atraves da biblioteca HttpClient? ou utilizando talvez a Jersey Client API?

    Obrigado.

  4. blpsilva says

    Oi Lucas, atualmente uso o HttpClient sim, mas eu gostaria de algo mais alto nível. Pretendo em breve ver o estado atual do client do Jersey e do RESTEasy e ver se eles já são usáveis. Quando comecei a usar o Jersey não tinha disponível nada razoável na parte client, então implementei com o HttpClient mesmo.

  5. Tamara says

    Bruno,

    Preciso passar dois objetos JSON para um método de uma classe recurso, vc saberia como fazer isso com o Jersey?



Some HTML is OK

or, reply to this post via trackback.



  • flu symptoms treatment
  • veterinary health dog
  • body building diet nutrition
  • american health vitamins
  • dog coats
  • prescription drug costs
  • herpes medicine
  • prices generic cialis
  • blood clots treatment
  • how to take valium
  • flonase dosage
  • reduce cholesterol
  • depakote effects
  • diet pill weight loss pill
  • buy generic tadalafil
  • cats anti inflammatory
  • sleep disorder and medication
  • dog weightloss
  • tips for increasing breast size
  • way to improve skin
  • relief from headaches
  • treatment for depression
  • human parasite
  • prevacid vs prilosec
  • adhd teens
  • cheap cholesterol medications
  • weight loss software
  • benefit health woman
  • signs of herpes
  • antihistamine loratadine
  • prescription drug lorazepam
  • benign prostatic hyperplasia
  • pain medicine
  • dog ear problem
  • viagra online
  • cholesterol cures
  • dog skin disorder
  • proactive acne
  • heart attack women
  • control bleeding
  • valium 5 mg
  • sex pheromones
  • alternative medicine cholesterol
  • crestor side effects
  • new arthritis medication
  • new drugs for hypertension
  • flu pandemic
  • benefits of vitamin d
  • avandamet
  • women's health online weight loss program
  • cats anti inflammatory
  • chronic insomnia medications
  • effective diuretics
  • relieve back pain
  • purchase birth control online
  • symptoms of flu
  • stop smoking online
  • quit smoking pills
  • rating erectile dysfunction drugs
  • discount levitra online
  • high blood pressure symptoms
  • foot muscle pain
  • pet med no prescription
  • where can i buy prescription medicine
  • methods of birth control
  • atarax information
  • pain medicine ultram
  • valium for sleep
  • prozac withdrawal
  • valium in pregnancy
  • social anxiety disorder treatment
  • nutritional diet for osteoporosis
  • buy xanax without a prescription
  • strength training supplements
  • dogs weight gin
  • medicine for throat infection
  • viagra with out prescription
  • medicine drugs
  • phentermine on line consultation
  • chlamydia pill
  • low dose aspirin
  • ativan prescription drug
  • left side pain
  • free samples levitra
  • pain management drugs
  • zolpidem dosage
  • buy detox drug
  • online drugs without prescription
  • medical treatment for lung cancer
  • taking a diuretic
  • list of prescription pain killers
  • muscle pain treatment
  • prilosec cost
  • impotence in young men
  • weight loss fast
  • dogs dry skin
  • cure for gout
  • relief for tooth pain
  • canadian online pharmacy price
  • wellbutrin sr
  • xenical no prescription
  • counter claritin
  • where can i get pain medication
  • otc scabies cream
  • ondansetron tablets
  • elevated blood sugar
  • viagra soft flavored sildenafil 100mg
  • buy diabetes drugs
  • seroquel for sleep
  • prilosec cost
  • low blood sugar
  • online drugs
  • prednisolone cheapest
  • osteoporosis drug uses
  • phenazopyridine hcl
  • anti depressant cost
  • kamagra oral jelly 100 mg
  • compare viagra cialis
  • where can i buy tramadol
  • drug sarafem
  • viagra information
  • body acne treatment
  • gonorrhea antibiotic
  • drug free high blood pressure help
  • crestor lipitor vs
  • disease of the skin
  • buy tramadol no perscription
  • online antibiotics
  • medical discount international drug
  • weight loss medications
  • acute insomnia
  • treatments for dog allergies
  • arthritis prevention
  • what is furosemide
  • mens hair loss
  • anti-depressants and stop smoking
  • clozapine medication
  • medication naproxen
  • online antibiotics
  • cat skin diseases
  • omeprazole
  • home remedy for hair loss
  • body building for women
  • chlamydia antibiotics
  • contraception and women's health
  • buy prednisone
  • avoid premature ejaculation
  • cat's health problems
  • cheap vitamin c
  • buy no phentermine prescription
  • mexican online drug stores
  • medical skin care supplies
  • brain insomnia
  • left chest pain
  • strength training supplements
  • cialis pill online
  • new treatment for hepatitis c
  • chronic pain medication
  • leg muscle pain
  • alcohol celebrex
  • thyroid and dogs
  • buy pain meds no prescription
  • apotheke online
  • coupon zantac
  • pet medicine online
  • various diet pills
  • prescription pain medications
  • drugs used in hypertension
  • ultram 50 mg
  • psoriasis aid
  • constipation medications
  • prostate cancer medicine
  • prescription drugs for weight loss
  • canada drugs on line
  • natural hair loss remedy
  • penis enlarger
  • pharmacy phentermine
  • buy discount order osteo arthritis online
  • viagra vs cialis
  • cheapest soma online
  • pharmacy international
  • prices of drugs
  • reduce cholesterol
  • hoodia safety
  • dog food skin problem
  • relief from arthritis pain
  • fat loss diets
  • metoclopramide pediatric
  • medication metformin
  • cheap cialis online
  • natural help sleeping
  • causes of high blood pressure
  • cialis cheap prices
  • buy cheap low blood sugar
  • what is tamiflu
  • tramadole
  • misoprostol
  • asthma home remedies
  • ordering condom
  • cheap diet pill prescriptions