Maven, Hibernate, Spring, CXF e MySql rodando no Jboss 7
Este post demonstra como usar de maneira prática o Hibernate com Spring publicando um Web Services utilizando com o Apache CXF, no Jboss 7 AS.
O primeiro passo é configurar o Maven, que irá auxiliar na automação do projeto. Acredito que é a parte mais complicada deste tutorial, já que encontrar todas as bibliotecas e dependências necessárias não é uma tarefa fácil. O pom.xml (arquivo de configuração do Maven) abaixo funciona perfeitamente para a configuração feita no nosso application-context.xml que você irá ver a seguir, você poderá fazer download da versão completa deste projeto no fim deste post.
...
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.1.ga</version>
<exclusions>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm-attrs</artifactId>
</exclusion>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.8</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.1_3</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.2.0.ga</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unitils</groupId>
<artifactId>unitils</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
</dependencies>
...
Vamos começar a fazer nosso serviço que irá retornar informações sobre Clubes de Futebol. Vamos mapear o Bean referente a tabela TB_CLUBES.
package com.lucianosilva.lab.entity;
@Entity
@Table(name = "TB_CLUBES")
public class Clube implements BaseEntity<Long> {
private static final long serialVersionUID = 5541457395540986982L;
@Id
@Column(name = "ID_CLUBE", nullable = false)
private Long idClube;
@Column(name = "NOME", nullable = true)
private String nome;
@Column(name = "NOME_POP", nullable = true)
private String nomePopular;
@Column(name = "FUNDACAO", nullable = true)
private Date dataFundacao;
/* (non-Javadoc)
* @see com.lucianosilva.lab.core.BaseEntity#getId()
*/
@Override
public Long getId() {
//
return this.idClube;
}
/* (non-Javadoc)
* @see com.lucianosilva.lab.core.BaseEntity#setId(java.lang.Object)
*/
@Override
public void setId(Long id) {
//
this.idClube = id;
}
//... getters and setters
}
Agora podemos construir o acesso aos dados, que faz uso de Generic DAO ocultado neste post, não se preocupe é uma prática comum, no fim do post estão os arquivos para download.
Essa classe básicamente define o que vamos ter no serviço, duas operações de retorno filtrando pelo ID e Nome.
package com.lucianosilva.lab.dao;
public class ClubesDao extends HibernateGenericRepository<Clube, Long> {
/* (non-Javadoc)
* @see com.lucianosilva.lab.repository.HibernateGenericRepository#findById(java.io.Serializable)
*/
@Override
public Clube findById(Long id) {
return super.findById(id);
}
public ClubesDao(){
super(Clube.class);
}
/**
*
* @param name
* @return
*/
public List<Clube> findByName( String name ){
return super.findByCriteria(Expression.like("nome", name, MatchMode.ANYWHERE));
}
}
A definição deste serviço é tão simples quanto a construção do DAO acima, não foi feito o tratamento customizado das exceções já que o objetivo não é esse e, sim demonstrar a integração dos frameworks e como devem ser configurados, nada impede de você mesmo evoluir este código.
package com.lucianosilva.lab.webservices;
@WebService
public interface ClubeService {
@WebMethod(operationName="ListAllClubes")
@WebResult(name = "Clube")
public List<Clube> listAll();
@WebMethod(operationName="FindByClubeName")
@WebResult(name = "Clube")
public List<Clube> findByName(@WebParam(name = "clubeName") String name);
}
Implementação do serviço.
package com.lucianosilva.lab.webservices.impl;
import java.util.List;
import javax.jws.WebService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.lucianosilva.lab.dao.ClubesDao;
import com.lucianosilva.lab.entity.Clube;
import com.lucianosilva.lab.webservices.ClubeService;
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
@WebService(endpointInterface="com.lucianosilva.lab.webservices.ClubeService")
public class ClubeServiceImpl implements ClubeService {
private ClubesDao clubesDao; // configuracao no application-context
public List<Clube> findByName(String name) {
return clubesDao.findByName(name);
}
public List<Clube> listAll() {
//
return clubesDao.listAll();
}
/**
* @return the clubesDao
*/
public ClubesDao getClubesDao() {
return clubesDao;
}
/**
* @param clubesDao the clubesDao to set
*/
public void setClubesDao(ClubesDao clubesDao) {
this.clubesDao = clubesDao;
}
}
Bem, até aqui nada de novo, pelo contrário tudo muito trivial. A configuração desta aplicação (application-context.xml) é o “pulo-do-gato”.
Adicionei comentários no bloco abaixo, para explicar cada parte da configuração.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd"
default-dependency-check="none" default-lazy-init="false">
<!-- arquivo separado para a configuração dos EndPoints (WebServices) CXF veja mais abaixo -->
<import resource="cxf-beans.xml" />
<!-- Bean abstrato para evitar repetição de código -->
<bean id="baseSessionFactory" abstract="true">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- IoC - Implementação da interface ClubesDAO -->
<bean id="clubesDao" class="com.lucianosilva.lab.dao.ClubesDao"
parent="baseSessionFactory" />
<!-- Configuração do DataSource para o Connection Pool - Este JNDI name está seguindo o padrão do JBoss -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:/Laboratorio</value>
</property>
</bean>
<!-- Configurações de uma Session Factories -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="annotatedClasses">
<list>
<value>com.lucianosilva.lab.entity.Clube</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
Bem, lá no começo do application-context.xml fizemos o import da configuração do CXF, segue a descrição do arquivo cxf-beans.xml.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- Configurações do Apache CXF --> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <!-- Configurações do endpoint WSDL --> <jaxws:endpoint id="clubeService" depends-on="clubeServiceImpl" implementor="#clubeServiceImpl" address="/ClubeService"> </jaxws:endpoint> <!-- Bean que implementa o endpoint do nosso webservice --> <bean id="clubeServiceImpl" class="com.lucianosilva.lab.webservices.impl.ClubeServiceImpl"> <property name="clubesDao" ref="clubesDao" /> </bean> </beans>
Compile, empacote e faça deploy no Jboss, agora vamos ver o serviço rodando no soapUI.
Por fim, você viu a configuração de um serviço simples, com acesso ao banco de dados utilizando DataSource, a qual considero importantíssimo como exemplo, já que NÍNGUEM utiliza a configuração do application-context informando os parâmetros do banco de dados (exceto para o uso do JUnit).
Você pode evoluir este código implementando o controle de erros com WebFault e também utilizando o Autowired no Spring, aumentando o controle da sua aplicação e diminuindo a configuração manual.
Download















