17
WebService WSDL e RESTful com Java e Apache CXF Neste tutorial demonstrarei como criar um WebService WSDL e RESTful na mesma aplicação de modo simplificado, utilizando Spring e Apache CXF que na nova versão traz suporte total para JSR 311 de forma clara e via annotations. Usaremos também o Maven2 para gerenciar nosso projeto, assumo que você já tem prévio conhecimento, recomendo este tutorial para entender o Maven2 e também como configura-lo. Também presumo que você tenha conhecimento sobre os dois protocolos, porém, caso queira aprender mais sobre leia: WSDL e RESTful . Bom, cabe a você também decidir qual tipo de serviço sua aplicação deve prover, tanto o WSDL como o RESTful tem suas vantágens e desvantágens e é necessário saber qual delas prover para seu cliente e se preciso prover as duas soluções, com o Apache CXF isso é possível, cheguei a essa conclusão pois a pouco tempo, participei de um projeto onde inicialmente províamos acesso a um WebService WSDL para o cliente, porém foi necessário disponibilizar também o acesso ao RESTful e como utilizávamos o Apache CXF não tivemos que mudar nada no projeto e nenhúm cliente foi afetado, pois a interface do projeto continuava a mesma.

WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Embed Size (px)

Citation preview

Page 1: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

WebService WSDL e RESTful com Java e Apache CXF

Neste tutorial demonstrarei como criar um WebService WSDL e

RESTful na mesma aplicação de modo simplificado, utilizando Spring e Apache

CXF que na nova versão traz suporte total para JSR 311 de forma clara e via

annotations. Usaremos também o Maven2 para gerenciar nosso projeto,

assumo que você já tem prévio conhecimento, recomendo este tutorial para

entender o Maven2 e também como configura-lo. Também presumo que você

tenha conhecimento sobre os dois protocolos, porém, caso queira aprender

mais sobre leia: WSDL e RESTful.

Bom, cabe a você também decidir qual tipo de serviço sua aplicação

deve prover, tanto o WSDL como o RESTful tem suas vantágens e

desvantágens e é necessário saber qual delas prover para seu cliente e se

preciso prover as duas soluções, com o Apache CXF isso é possível, cheguei a

essa conclusão pois a pouco tempo, participei de um projeto onde inicialmente

províamos acesso a um WebService WSDL para o cliente, porém foi

necessário disponibilizar também o acesso ao RESTful e como utilizávamos o

Apache CXF não tivemos que mudar nada no projeto e nenhúm cliente foi

afetado, pois a interface do projeto continuava a mesma.

Page 2: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Bom, vamos ao nosso projeto.

Primeiro precisamos mapear nossas dependências no Maven2,

segue o pom do nosso projeto:

O Apache CXF utiliza dentro dele o Spring como dependência, removemos o

mesmo para utilizar uma versão atualizada do SpringFramework. Adicionei ao

nosso POM também o Plugin do Jetty que iremos utilizar para debugar nossa

aplicação dentro do Eclipse. Utilizei também um plugin para compilar nosso

projeto o Maven Compiler Plugin dizendo qual versão do Java estamos

utilizando e qual o encoding do nosso projeto (não esqueça de mudar o

encoding no seu projeto do Eclipse para UTF-8). Agora nossa dependências

estão prontas e nosso projeto configurado.

Nosso projeto possui uma interface seguindo o padrão de projeto Façade, essa

interface será exposta como nosso WebService, de maneira simplificada, o

Façade torna o projeto mais fácil de entender e usar.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://w w w .w 3.org/2001/XMLSchema-i xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" <modelVersion>4.0.0</modelVersion> <groupId>com.w ordpress.dchohfi</groupId> <artifactId>ServiceSample</artifactId> <packaging>w ar</packaging> <version>0.0.1-SNAPSHOT</version> <developers> <developer> <id>dchohfi</id> <name>Diego Chohfi</name> <email>[email protected]</email> <url>http://dchohfi.w ordpress.com</url> </developer> </developers>

Page 3: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Interface:

Verifique como é simples desenvolver uma interface para disponibilizar acesso

tanto para RESTful como para WSDL, utilizamos annotations para dizer ao

CXF qual o tipo de retorno que o nosso WebService vai prover tanto para o

RESTful quanto para o WSDL, no mesmo código! Na implementação da nossa

interface não iremos precisar de praticamente nenhuma configuração adicional

para o Apache CXF saber o que deve fazer.

Implementação:

package com.w ordpress.dchohfi.service;

import com.w ordpress.dchohfi.exception.ClienteException;import com.w ordpress.dchohfi.model.entity.Cliente;

@Path("/")//caminho onde o serviço REST fica disponibilizado, seguido pelo @Path de cada parametro@Produces({"application/xml", "application/json"})//tipos de retorno que o nosso REST pode produzir@WebService//definimos aqui que essa interface é um WebService WSDLpublic interface Service {

@GET//tipo do metodo REST @Path("/cliente")//caminho do método @WebMethod(operationName="getClientes")//nome do metodo no WSDL public Collection<Cliente> getClientes();

package com.w ordpress.dchohfi.service;

@WebService(endpointInterface = "com.w ordpress.dchohfi.service.Service")public class ServiceImpl implements Service {

private ClienteDAO clienteDao; @Override public Cliente getCliente(int id) throw s ClienteException { return clienteDao.getCliente(id); }

@Override public Collection<Cliente> getClientes() { return clienteDao.getClientes();

Page 4: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Veja que tivemos apenas uma anotação indicando ao Apache CXF

qual o Endpoint que ele deve procurar para fazer o mapeamento do XML para

o WSDL. Criei também uma interface de ClienteDAO, faremos uma

implementação simples do DAO, mas você pode integrá-lo ao Hibernate, por

exemplo, ou qualquer outra forma para obter acesso ao seus dados, até

mesmo outro WebService. É sempre bom trabalhar com interfaces para

garantir o baixo acoplamento das suas classes garantindo uma escalabilidade

maior, você não precisa saber o que a classe faz em si, deste que você tenha a

assinatura dela.

Implementação Simples do ClienteDAO:

Verifique que na implementação lançamos uma Exception do tipo

ClienteException caso nenhúm usuário seja encontrado com aquela ID, o

Apache CXF ainda não consegue mapear para o REST a exception lançada e

responder adequadamente a requisição ao usuário, precisamos então ter um

ExceptionMapper para dizer ao Apache CXF o que fazer caso aquela

Exception seja lançada.

package com.w ordpress.dchohfi.model.dao.simple;//você pode implementar a classe ClienteDAO da forma que desejarpublic class ClienteSimpleDAO implements ClienteDAO {

private Collection<Cliente> clientes; @Override public Cliente getCliente(int id) throw s ClienteException { for (Cliente cliente : clientes) { if(cliente.getId() == id) return cliente; } throw new ClienteException("Cliente com id "+id+" não encontrado!"); }

Page 5: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

ClienteExceptionMapper:

Verifique como é simples, você pode dizer qual o Status do Response gerado

pelo método, ainda é possível colocar uma mensagem para mostrar para o

usuário o que aconteceu com a requisição que ele fez. Agora precisamos

configurar o Spring juntando tudo o que fizemos, considere isso como um

pequeno tutorial desse incrivel framework. Leia os comentários dentro do XML

e qualquer dúvida poste um comentário e caso seja necessário farei um breve

tutorial sobre Spring.

package com.w ordpress.dchohfi.exception;

public class ClienteExceptionMapper implements ExceptionMapper<ClienteException>{

@Override public Response toResponse(ClienteException arg0) { return Response.status(Status.BAD_REQUEST).build(); }}

Page 6: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Configuração do Spring:

Considero que a configuração feita em XML é pequena visto o tamanho da

aplicação que temos em tão pouco tempo, normalmente a configuração do

Spring é bem extensa em projetos de grande porte, então quem já trabalha

com Spring não terá problema para entender o contexto. Agora precisamos

configurar o servlet dentro do web.xml para nossa aplicação.

web.xml

Bom, aqui estamos dizendo ao Spring o que fazer com a nossa aplicação e

estamos carregando o Apache CXF para rodar dentro de um servidor de

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://w w w .springframew ork.org/schema/beans" xmlns:xsi="http://w w w .w 3.org/2001/XMLSchema-instance" xmlns:context="http://w w w .springframew ork.org/schema/context" xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxw s="http://cxf.apache.org/jaxw s" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xsi:schemaLocation="http://w w w .springframew ork.org/schema/beans http://w w w .springframew ork.org/schema/beans/spring-beans-2.5.xsd http://w w w .springframew ork.org/schema/context http://w w w .springframew ork.org/schema/context/spring-context-2.5.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/jaxw s http://cxf.apache.org/schemas/jaxw s.xsd

<?xml version="1.0" encoding="UTF-8"?><w eb-app xmlns:xsi="http://w w w .w 3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:w eb="http://java.sun.com/xml/ns/javaee/w eb-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/w eb-app_2_5.xsd" id="services" version="2.5">

<context-param> <param-name>w ebAppRootKey</param-name> <param-value>cxf.rest.example.root</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name>

Page 7: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

aplicações escolhido por você, aqui você pode ficar tranquilo pois a

configuração é padrão.

Neste momento temos nossa aplicação funcionando e pronta para

ser colocada para rodar. Lembra do plugin do Jetty dentro do POM do

Maven2? Iremos utilizá-lo agora. Demonstrarei rapidamente como fazer as

configurações para debugar seu projeto dentro do Eclipse.

Faça as seguintes configurações, dentro de Run Configurations no

Eclipse crie um novo Java Application e siga as instruções como nas imagens:

Não aparece as imagens no site

Acredito que com isso você consiga subir seu projeto dentro do

Eclipse e debugar sem problemas sua aplicação, você poderá consumir sua

aplicação REST a partir do link

http://localhost:8080/ServiceSample/rest/cliente/1/ por exemplo, deixo como

dica utilizar um complemento para o FireFox o RESTClient, onde você pode

consumir aplicações RESTful sem problema e analizar com clareza os

resultados obtidos e para consumir WebServices WSDL recomendo o soapUI

que possui diversas funcionalidades para testar e sobrecarregar seu servidor e

verificar o número de acessos simultâneos que ele aguenta.

É importante ressaltar que você pode escolher se deseja prover

acesso aos dois WebServices dentro da aplicação para o cliente, cabe a você

decidir o que é melhor.

Bom, aqui acaba nosso tutorial que acabou ficando maior do que eu

esperava, tomara que eu não tenha me perdido em alguma parte e caso algo

tenha ficado confuso ou passado desapercebido deixe um comentário que

tentarei esclarecer.

Espero que quem leia goste do material e por favor, comente, é

importante. Quero continuar este pequeno projeto adicionando funcionalidades

como integração do Spring com o Hiberante entre outras coisas, para

realmente ter um tutorial completo para uma aplicação robusta.

Hibernate 3 com Spring e DAO Generico

Page 8: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Bom, galera como prometido neste post irei continuar o tópico

anterior adicionando o suporte ao Hibernate em nosso WebService. O

Hibernate é um Framework poderoso de mapeamento objeto-relacional muito

conhecido e utilizado, não pretendo entrar em detalhes sobre como configurar

o Hibernate nem como mapear seus objetos para acessar o banco, porém,

caso tenha dúvidas acesse este tutorial que mostra como tirar proveito deste

Framework e caso tenha alguma dúvida deixe um comentário ou envie um

email que tentarei ajudar.

O Spring possui um módulo para acesso a banco de dados

extremamente robusto, podemos fazer controle de transações via AOP, cache,

gerenciar pool de conexões diretamente no contexto do Spring sem se

preocupar com qual tecnologia que está implementada e caso seja necessário

podemos trocar o modo de acesso sem precisar modificar todo o projeto, nos

dando assim maior mobilidade e escalabilidade. O Hibernate porém não é o

único Framework que o Spring provê integração, o Spring se integra facilmente

a diversos frameworks de persistência como JPA, iBATIS, JDBC e proprio

Hibernate que iremos demonstrar neste tutorial. Mostrarei também como

desenvolver um DAO generico para o Hibernate que nos da acesso as

principais funcões básicas de um CRUD em apenas uma interface, evitando

repetição de código. Modificaremos um pouco o projeto anterior para poder

demonstrar todas as funcionalidades dessa integração. Primeiramente

precisamos modificar nosso POM para baixar todas as dependências

necessárias:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://w w w .w 3.org/2001/XMLSchema-i xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" <modelVersion>4.0.0</modelVersion> <groupId>com.w ordpress.dchohfi</groupId> <artifactId>ServiceSample</artifactId> <packaging>w ar</packaging> <version>2.0</version> <developers> <developer> <id>dchohfi</id> <name>Diego Chohfi</name> <email>[email protected]</email> <url>http://dchohfi.w ordpress.com</url> </developer> </developers>

Page 9: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Verifique que além das dependências do Spring e do Apache CXF, temos

também as dependências do Hibernate. Note que adicionei como dependência

o commons-dbcp da Apache, iremos utiliza-lo para gerenciar nosso pool de

conexões ao banco de dados, o Hibernate por default vem com o c3p0 para

gerenciar o pool de conexões, porém eu prefiro o commons-dbcp pois já tive

problemas com o c3p0. Portanto, recomendo a vocês utilizarem. O bacana de

se utilizar o commons-dbcp é que podemos ter maior controle sobre como as

conexões são abertas e fechadas no Hibernate e também evitar que conexões

fiquem abertas sem serem utilizadas. Vamos ao arquivo de configuração do

Spring.

Leia atentamente os comentários feitos no decorrer do arquivo pois desta vez

temos uma configuração mais avançada do Spring, estamos utilizando diversos

recursos disponíveis no framework, um deles é o

PropertyPlaceholderConfigurer onde podemos montar um arquivo .properties

fora do nosso contexto do Spring e colocar diversas configurações importantes

lá, gosto deste método pois podemos colocar em uma pasta separada, por

exemplo, os dados de conexão com o banco, assim qualquer pessoa pode

modificar os dados de configuração se for necessário, sem precisar entender o

arquivo de configuração do Spring.

jdbc.properties:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://w w w .springframew ork.org/schema/beans" xmlns:context="http://w w w .springframew ork.org/schema/context" xmlns:xsi="http://w w w .w 3.org/2001/XMLSchema-instance" xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxw s="http://cxf.apache.org/jaxw s" xmlns:tx="http://w w w .springframew ork.org/schema/tx" xmlns:p="http://w w w .springframew ork.org/schema/p" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xsi:schemaLocation=" http://w w w .springframew ork.org/schema/beans http://w w w .springframew ork.org/schema/beans/spring-beans-2.5.xsd http://w w w .springframew ork.org/schema/context http://w w w .springframew ork.org/schema/context/spring-context-2.5.xsd http://w w w .springframew ork.org/schema/tx http://w w w .springframew ork.org/schema/tx/spring-tx-2.5.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd

Page 10: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

database.driver=com.mysql.jdbc.Driver

database.url=jdbc:mysql://localhost:3306/test

database.user=root

database.pass=serviceSample

database.initConnections=1

database.maxActive=10

database.maxIdle=5

database.removeAbandoned=true

A integração do Spring ao Hibernate3 começa quando configuramos nosso

sessionFactory, observe que utilizamos a classe

AnnotationSessionFactoryBean, aqui utilizamos um dataSource configurado

previamente, dizemos também ao Spring quais são as entidades anotadas com

@Entity entre outras diversas configurações disponíveis. Nós criamos então

um Bean abstrato dentro do contexto do Spring para evitar repetição de código,

nosso Bean clienteHibernateDao precisa então apenas herdar nosso bean

abstrato para obter a sessionFactory, simples não? No final do arquivo temos

também um bean de controle de transações, não pretendo aprofundar nesse

assunto pois criarei outro tutorial abordando apenas controle de transações no

Spring pois é um assunto muito bacana. Vamos ao nosso DAO generico

integrado ao Spring.

Precisamos primeiramente de uma interface contendo as operações

basicas de um CRUD(criar, ler, atualizar e deletar):

Page 11: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Agora vem a "mágica" da integração do Hibernate ao Spring e o DAO generico:

O nosso DAO generico não precisa saber qual classe ele está relacionando,

ele precisa apenas fazer as operações básicas de um CRUD. Porém com o

suporte ao Hibernate temos algo a mais além das operações básicas. Verifique

que o método findByCriteria pode receber ou não um Array de Criterion onde

podemos fazer buscas mais específicas no banco de dados.

package com.w ordpress.dchohfi.model.dao;

public interface GenericDAO<T, ID extends Serializable> { T f indById(ID id); List<T> listAll(); T save(T entity); void delete(T entity);}

package com.w ordpress.dchohfi.model.dao.hibernate;

//Adicionando herança ao HibernateDaoSupport tempos diversas funcionalidades do Spring//junto ao Hibernate, implementamos também nosso DAO generico para ter mobilidade.public class HibernateDAOGenerico<T, ID extends Serializable> extends HibernateDaoSupport implements GenericDAO<T, ID> {

private static Log LOG = LogFactory.getLog(HibernateDAOGenerico.class);

// Nosso construtor vai setar automaticamente via Reflection qual classe // estamos tratando. @SuppressWarnings("unchecked") public HibernateDAOGenerico() { this.persistentClass = (Class<T>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0];

Page 12: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Nossa implementação de ClienteHibernateDao consegue consultar por

exemplo todos os Clientes que possuem telefone, dessa forma você consegue

ter um DAO generico para as operações básicas, mas também tem a opção de

fazer buscas mais avançadas via Criteria. Agora você pode ter diversos DAO's

utilizando apenas uma classe, acredite em mim, você da pra economizar muito

tempo com isso. O Spring também nos da suporte para tratar as excecões

lançadas pelo Hibernate, fica mais fácil saber o que aconteceu e porque

aconteceu e com o controle de transações você não precisa se preocupar em

dar rollback caso algum problema aconteça.

Veja também que nossa interface de acesso ao serviço não mudou

muito:

package com.w ordpress.dchohfi.model.dao.hibernate;

public class ClienteHibernateDAO extends HibernateDAOGenerico<Cliente, Long> implements ClienteDAO {

@Override public List<Cliente> f indClietsWithPhone() { return f indByCriteria(Expression.isNotNull("telefone"), Expression.ne("telefone", "")); }}

package com.w ordpress.dchohfi.service;

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)@WebService(endpointInterface = "com.w ordpress.dchohfi.service.Service")public class ServiceImpl implements Service {

private ClienteDAO clienteDao;

@Override public Cliente getCliente(Long id) throw s ClienteException { Cliente cliente = this.clienteDao.f indById(id); if (cliente == null) throw new ClienteException("Nenhum usuario com id" + id + " encontrado!"); return cliente; }

Page 13: WebService WSDL e RESTful com Java e Apache CXF & Hibernate 3 com Spring e DAO Generico

Note como temos todas as operações de acesso a dados a partir da

assunatura da interface, nós não sabemos nem precisamos saber o que

acontece. Não se preocupe com a anotação de @Transactional pois irei

explicar em outro post, mas aguarde que o Spring vai se tornar ainda mais

interessante.

É importante entender que o nosso projeto ainda está funcionando a

partir de interfaces, você, por exemplo, não é obrigado ao utilizar o Hibernate

como framework de acesso a dados, utilizando a interface generica você pode

ter acesso via JDBC normal caso você ache necessário, modificando apenas a

parte de acesso ao dado.

Acho que isso é tudo, temos agora mais uma demonstração de

quanto o Spring Framework é poderoso, integrando ele a outros frameworks

podersos temos uma forma fácil e rápida de implementar aplicações robustas.

Utilizei o MySQL para banco de dados e caso você tenha problema com a lib

da Sun, você precisa fazer o download dela diretamente no site para aceitar os

termos. Qualquer outra dúvida deixe um comentário ou envie um email.