Olá Pessoal,
No post de hoje veremos como fazer um simples CRUD usando o Spring, integrando com Hibernate e testando via unit tests com JUNIT4. No último posts vimos apenas uma integração com o Hibernate e também um CRUD usando HibernateTemplate, esse aqui veremos que na versão 3 do Spring não precisamos mais do HiberanteTemplate e vamos testar nosso código com unit test.
Lets go…
Starting…
Primeiro passo é que estarei assumindo que você já tem .jars necessário para o ambiente. Já que esse não é o primeiro post da série, caso contrário terá que baixar os .jars para: driver Mysql 5, Hibernate 3.6, AOP, AspectJ, Spring 3.x.
Antes de começarmos a desenvolver, vamos primeiro estruturar nosso projeto e packages conforme a imagem a seguir:
Nosso CRUD será o cadastro de veículos que serão alugados. Claro que há muito mais regras de negócios do que a que veremos no exemplo a seguir, porém o nosso objetivo é explorar o framework Spring e não tratar todas as regras de negócio em um post.
- Crie a estrutura conforme a imagem acima
- Crie o arquivo de configuração de Spring, o qual chamei de springconfiguration.xml, e coloque dentro do package config.
- Agora vamos colocar a carne no nosso XML
Cabeçalho fica assim:
<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:tx=“http://www.springframework.org/schema/tx”
xmlns:aop=“http://www.springframework.org/schema/aop”
xsi:schemaLocation=“http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd”>
Estarei comentando mais na frente ou in line apenas o que ainda não foi abordado nos posts anteriores.
O cara que busca os beans:
<context:component-scan base-package=“*”/>
Colocando translation
<!– esse cara faz as traduções das exception checked para as unchecked do Spring –>
<bean class=“org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor”/>
Data source
<!– pelo nome já diz, data source para conexão com o DB –>
<bean id=“dataSource” class=“org.springframework.jdbc.datasource.DriverManagerDataSource”>
<property name=“driverClassName” value=“com.mysql.jdbc.Driver”/>
<property name=“url” value=“jdbc:mysql://localhost/test”/>
<property name=“username” value=“root”/>
<property name=“password” value=“camilo2593”/>
</bean>
Configurando a SessionFactory
<!– Aqui estamos definido como será a parte de persistêcia, e dizemos que faremos via annotation –>
<bean id=“sessionFactory” class=“org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean”>
<!– informando a quem estaremos conectado –>
<property name=“dataSource” ref=“dataSource”/>
<!– dizendo onde estão as classes dominio, ele saberá devido anotação @Entity –>
<property name=“packagesToScan” value=“br.com.camilolopes.rentcar.domain.bean”/>
<!– configurando coisas especificas do Hibernate –>
<property name=“hibernateProperties”>
<props>
<prop key=“hibernate.dialect”>org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key=“hibernate.hbm2ddl.auto”>update</prop>
</props>
</property>
</bean>
Definindo Transaction
<!– definindo quem vai gerenciar as transaction, ou seja, será o Hibernate –>
<bean id=“transactionManager” class=“org.springframework.orm.hibernate3.HibernateTransactionManager”>
<property name=“sessionFactory” ref=“sessionFactory”/>
</bean>
</beans>
Há duas formas de declararmos as transaction no Spring por XML ou Annotation. Veremos as duas formas, no nosso caso de usarmos o XML faremos com AOP e você entenderá o motivo:
Via XML
<!– todo medoto que começa com add é required uma transaction –>
<tx:advice id=“txAdvice”>
<tx:attributes>
<tx:method name=“add*” propagation=“REQUIRED”/>
<tx:method name=“update*” propagation=“REQUIRED”/>
<tx:method name=“*” propagation=“SUPPORTS” read-only=“true”/>
</tx:attributes>
</tx:advice>
<!– toda classe que extends a interface terá uma referência para o advisor –>
<aop:config>
<aop:advisor pointcut = “execution(* *..RentCar.*(..)))” advice-ref=“txAdvice”/>
</aop:config>
Em alguns contexto dessa forma é bem mais prático que usar Annotations.
Via annotation
Remove todo o código XML acima e apenas adiciona a seguinte linha:
<tx:annotation-driven/>
Claro que teremos que anotar nas classes/métodos como @Transaction e informar como esse deve se comportar , seguindo o exemplo do XML acima seria algo assim:
@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
public class myClass{ }
Normalmente você colocaria isso na camada de serviço.Mas, se você está brincando e não tem uma camada de serviço, pode colocar direto no DAO.
E o método que faria uma das operações de banco ficaria assim:
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
public void save(Car car) {
getCurrentSession().save(car);}
No nosso exemplo vamos não vamos usar Annotations e exploraremos o benefício de usar a versão do XML conforme acima, se vc deixar a tag para annotation no arquivo de configuração o Spring não vai se importar com isso.
Desenvolvimento
Após toda essa configuração, vamos agora desenvolver nossas classes .java. Começando pela classe de domínio:
@Entity
@Table(name=”CARS”)
public class Car implements Serializable{
private static final long serialVersionUID = -2896368465389020843L;
@Id
@GeneratedValue
private Long id;
private String manufacter;
private String description;
private BigDecimal marketValue;
//getters/setters omitidos
Basicamente isso .
Interface DAO
public interface RentCarDAO {
void save(Car car);
List<Car> findAll();
List<Car> findAllByDescription(String description);
void update(Car car);
void delete();
}
Implementação da Interface:
@Repository
public class RentCarDAOImpl implements RentCarDAO {
@Autowired
private SessionFactory sessionFactory;
public Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
@Override
public void save(Car car) {
getCurrentSession().save(car);
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public List<Car> findAll() {
return getCurrentSession().createCriteria(Car.class).list();
}
@Override
public List<Car> findAllByDescription(String description) {
Criteria createCriteria = getCurrentSession().createCriteria(Car.class);
createCriteria.add(Restrictions.ilike(“description”, description));
return (List<Car>) createCriteria.list();
}
@Override
public void update(Car car) {
getCurrentSession().update(car);
}
@Override
public void delete() {
Query query = getCurrentSession().createQuery(“delete from Car where id >0”);
query.executeUpdate();
}
Interface de Serviço
@Service
public interface RentCar {
void addNewCar(Car car);
List<Car> findAll();
List<Car> findCarByDescription(String description);
void updateCar(Car car);
void delete();
}
Classe que implementa o Serviço
@Service
public class RentCarServiceImpl implements RentCar {
@Autowired
private RentCarDAO rentCarDAO;
@Override
public void addNewCar(Car car) {
rentCarDAO.save(car);
}
public void setRentCarDAO(RentCarDAO rentCarDAO) {
this.rentCarDAO = rentCarDAO;
}
@Override
public List<Car> findAll() {
return rentCarDAO.findAll();
}
@Override
public List<Car>findCarByDescription(String description) {
return (List<Car>) rentCarDAO.findAllByDescription(description);
}
@Override
public void updateCar(Car car) {
rentCarDAO.update(car);
}
@Override
public void delete() {
rentCarDAO.delete();
}
}
Unit Test
Se não reparou quando criou o projeto, temos um source apenas para os unit tests, conforme a imagem a seguir:
Agora crie a classe de teste. A seguir mostrarei apenas dois simples testes, você deve criar os demais para validar os cenários, não coloquei todos para não ficar mais longo ainda o post.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={“classpath:config/springconfiguration.xml”})
public class RentCarServicesTest {
@Autowired
private RentCar rentCarServicesImpl;
private Car car;
@Before
public void setUp() throws Exception {
car = new Car();
}
@Test
public void testAddingNewCarWithSuccess(){
try{
car.setDescription(“Civic”);
car.setManufacter(“Honda”);
car.setMarketValue(new BigDecimal(740000));
rentCarServicesImpl.addNewCar(car );
}catch (Exception e) {
Assert.fail(“not expected result”);
}
}
@Test
public void testListAllCarIsNotEmpty(){
assertFalse(rentCarServicesImpl.findAll().isEmpty());
}
Resultado
Lembre-se que seu BD precisa está rodando
Ufa! Esse post foi longo heim, mas não tinha outra forma de mostrar tudo se não fosse assim, e olha que busquei resumir ao máximo possível. Enfim, vou ficando por aqui.
GitHub
Acesse o repositório no github com todos os projetos da série Spring: https://github.com/camilolopes/workspacespring
Espero que tenham gostado do post.
Abraços, see ya!!