Dao Genérico com Spring e Hibernate

Seguindo o modelo do post anterior, podemos criar um dao que realiza as operações básicas, para que não seja necessário recriá-las em todos os lugares. Há muito material sobre isso na internet, mas acho interessante postar aqui como fica um dao genérico baseado no modelo mostrado.

package br.com.vonjuliano.springhibernatesimples.dao.hibernate;

import java.util.List;

import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;

public class DAO<T> {

    private final SessionFactory factory;
    private final Class<T> classe;

    public DAO(final SessionFactory factory, final Class<T> classe) {
        this.factory = factory;
        this.classe = classe;
    }

    public void adiciona(final T t) {
        getSession().save(t);
    }

    private Session getSession() {
        return factory.getCurrentSession();
    }

    public void remove(final T t) {
        getSession().delete(t);
   }

    @SuppressWarnings("unchecked")
    public T busca(final Long id) {
        return (T) getSession().load(classe, id);
    }

    @SuppressWarnings("unchecked")
    public List<T> lista() {
        return getSession().createCriteria(classe).list();
    }

    public void atualiza(final T t) {
        getSession().merge(t);
    }
}

Repare que essa classe não é gerenciada pelo Spring, de forma que ela precisa ser instanciada pela própria classe que a utiliza. Alterando a classe HibernateCarroDao (essa sim, gerenciada), fica assim:

package br.com.vonjuliano.springhibernatesimples.dao.hibernate;

import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import br.com.vonjuliano.springhibernatesimples.dao.CarroDao;
import br.com.vonjuliano.springhibernatesimples.model.Carro;

@Repository
public class HibernateCarroDao implements CarroDao {

    private final DAO<Carro> dao;

    @Autowired
    public HibernateCarroDao(final SessionFactory factory) {
        dao  = new DAO<Cliente>(factory, Carro.class);
    }

    public List<Carro> lista() {
        return dao.list();
    }

    @Transactional
    public void adiciona(final Carro carro) {
        dao.adiciona(carro);
    }
}

Lembrando que é na classe gerenciada pelo Spring que a anotação @Transactional deve ser utilizada.

Esse modelo é bem simplificado, e caso não esteja usando o Spring, ao invés de receber a SessionFactory, o DAO pode receber a Session diretamente, reduzindo um pouco mais o código. Com Spring esse modelo não é usado, porque ao injetar a SessionFactory ela ainda não possui Session alguma preparada, de modo que chamar getCurrentSession() para passar para o contrutor do DAO resultaria em uma HibernateException.

Há algumas alternativas, como esse hibernate-generic-dao, mas ele traz muita funcionalidade que acaba não sendo utilizada (ao menos eu não uso), creio que o DAO no modelo apresentado já é o suficiente para o que se propõe: atender as operações mais básicas.

Anúncios
Publicado em Hibernate, Spring | 4 Comentários

Integrando Spring e Hibernate

Leia esse post revisto e atualizado aqui.

Integrar Spring e Hibernate é uma tarefa muito comum, mas desde que comecei a trabalhar com essas ferramentas, a forma como isso é feito me desagradou. É muito comum encontrar classes que herdam de HibernateDaoSupport, o que cresce de forma exagerada e traz comportamento que muitas vezes a classe não deveria possuir.

Quando feito dessa forma, praticamente para qualquer operação é necessário utilizar o objeto HibernateTemplate, obtido através do método getHibernateTemplate(). Então por que não injetar apenas o HibernateTemplate e trabalhar com ele diretamente? E assim foi feito por um tempo, o que acabou com essa herança entre as classes. Então o problema passou a ser outro.

As limitações do HibernateTemplate passaram a incomodar, pois não era possível trabalhar com a Session diretamente (até era, mas assim o seu controle vinha para as mãos da aplicação), e sem ela, não podámos usar Criteria livremente, restando como alternativas DetachedCriteria, ou criar uma implementação de HibernateCallback para aí sim ter acesso direto a Session, mantendo o controle por parte do Spring.

Foi aí que notei que o Spring estava sendo intrusivo demais no design, já que ele devia apenas fornecer a Session e controlar as transações magicamente, nada mais. Comecei a procurar uma forma de fornecer a Session para os meus Daos, e ainda sim manter as vantagens que o Spring fornece, como o já citado controle de transações. E a forma que encontrei é a que será mostrada aqui.

Como a quantidade de dependências aumentou em relação às dos outros post, dessa vez vou facilitar na criação do projeto, é só fazer o download do pom.xml aqui. Se você não usa maven, pode conferir nele as dependências necessárias.

Agora são necessárias as configurações para o Hibernate e para o Spring. Abaixo, o hibernate.cfg.xml:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>
        <property name="dialect">org.hibernate.dialect.Oracle9iDialect</property>

            <property name="hibernate.show_sql">true</property>
            <property name="hibernate.format_sql">true</property>

            <mapping class="br.com.vonjuliano.springhibernatesimples.model.Carro" />

    </session-factory>

</hibernate-configuration>

E para o Spring, o applicationContext.xml:

<?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:p="http://www.springframework.org/schema/p"
    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">

    <context:component-scan base-package="br.com.vonjuliano.springhibernatesimples" />

    <context:property-placeholder location="classpath:jdbc.properties" />
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
        p:driverClassName="${jdbc.driver}" p:url="${jdbc.url}"
        p:username="${jdbc.username}" p:password="${jdbc.password}">
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <tx:annotation-driven />

</beans>

Com isso, as configurações estão prontas. O DataSource utilizado é o fornecido pelo próprio Spring, que uso apenas para desenvolvimento, para produção o c3p0 é uma opção mais apropriada. Ao configurar a SessionFactory, repare que mantive o hibernate.cfg.xml, fazendo uma referência a ele. Apenas lembre que cada nova entidade do sistema deverá ser acrescentada ao mapeamento desse arquivo. Por fim, a configuração do HibernateTransactionManager, para que o Spring faça o controle de transações de forma transparente. Agora, a interface CarroDao:

package br.com.vonjuliano.springhibernatesimples.dao;

import java.util.List;

import br.com.vonjuliano.springhibernatesimples.model.Carro;

public interface CarroDao {

    List<Carro> lista();

    void adiciona(Carro carro);
}

E para eliminar todas aquelas dependências das classes do Spring, na implementação será injetada a SessionFactory:

package br.com.vonjuliano.springhibernatesimples.dao.hibernate;

import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import br.com.vonjuliano.springhibernatesimples.dao.CarroDao;
import br.com.vonjuliano.springhibernatesimples.model.Carro;

@Repository
public class HibernateCarroDao implements CarroDao {

    private final SessionFactory factory;

    @Autowired
    public HibernateCarroDao(final SessionFactory factory) {
        this.factory = factory;
    }

    public List<Carro> lista() {
        return factory.getCurrentSession().createCriteria(Carro.class).list();
    }

    @Transactional
    public void adiciona(final Carro carro) {
        factory.getCurrentSession().save(carro);
    }
}

Agora podemos trabalhar livremente com a Session, desde que ela seja obtida da SessionFactory através do método getCurrentSession(), pois dessa forma não tiramos o controle da Session das mãos do Spring, ficando com o melhor das duas ferramentas. Caso seja utilizado o getSession(), fechar a Session passa a ser responsabilidade da sua aplicação.

O método terá suas transações controladas pelo Spring, de forma que não é preciso se preocupar com ela.

Usando as ferramentas dessa forma unimos o melhor dos dois mundos, o controle de transações do Spring e a liberdade para trabalhar com a Session do Hibernate, sem grandes interferências, de forma simples!

Veja também como criar um Dao Genérico com Spring e Hibernate.

Publicado em Hibernate, Spring | 9 Comentários

Testes Unitários – Struts 2

Leia esse post revisto e atualizado aqui.

Testes são uma forma de garantir que a aplicação está funcionando corretamente, e quando é preciso alterá-la, é através deles que garantimos que ela vai continuar funcionando após feitas as alterações. Aqui vou mostrar como devem ser feitos os testes unitários das actions quando trabalhamos com Struts 2.

Serão criados aqui os testes para a CarroAction, do post Trabalhando com Struts 2 de forma simples. Primeiro, será necessário fazer uma pequena alteração na classe. O construtor da classe agora vai ter que receber o dão ao invés de criá-lo. Fica assim:

public CarroAction(final CarroDao dao) {
    this.dao = dao;
}

E para fazer os testes, serão adicionados ao projeto os jars do JUnit e do Mockito:

Jars para testes

Jars para testes

Abaixo, a classe de testes. Vou explicar todos os passos, caso o leitor não tenha conhecimento sobre JUnit ou sobre mocks.

package br.com.vonjuliano.struts2simples;

import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.when;

import java.util.Collections;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import br.com.vonjuliano.struts2simples.action.CarroAction;
import br.com.vonjuliano.struts2simples.dao.CarroDao;
import br.com.vonjuliano.struts2simples.model.Carro;

public class CarroActionTest {

    private CarroAction action;

    @Mock
    private CarroDao dao;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        action = new CarroAction(dao);
    }

    @Test
    public void deveListarTodosOsCarros() {
        when(dao.lista()).thenReturn(Collections.singletonList(new Carro()));
        action.lista();
        List<Carro> carros = action.getCarros();
        assertFalse(carros.isEmpty());
    }

    @Test
    public void deveAdicionarCarroValido() {
        action.setCarro(new Carro());
        action.adiciona();
    }
}

Primeiro é criada uma instancia de CarroAction, a qual será testada. Repare que somente essa classe deve ser testada, não precisamos que o dao efetivamente salve os objetos passados para ele onde quer que seja, mas precisamos que ele simule esse comportamento, por isso será criado um mock de CarroDao. Um mock é um objeto que simula o comportamento de um objeto real (nessa caso, do CarroDao), que vai se comportar da forma que nós determinarmos – isso será mostrado à seguir.

O método setUp é anotado com @Before, uma anotação do JUnit que indica que esse método deve ser chamado antes de cada teste. MockitoAnnotations.initMocks(this) inicializa as classes anotadas com @Mock, e isso feito, criamos uma nova action, passando o dao mockado.

Cada método anotado com @Test será um teste para o JUnit. Assim com o nome diz, nosso primeiro teste vai listar todos os carros (lembrando que nomes significativos são muito importantes!), e é aqui que devemos dizer para o dao como ele deve se comportar:

when(dao.lista()).thenReturn(Collections.singletonList(new Carro()));

O Mockito tem uma interface fluente que facilita muita a configuração dos mocks. Aqui instruímos nosso dao mockado da seguinte maneira: “quando seu método lista for chamado, retorne essa lista com um carro só”, assim conseguimos simular uma busca no banco de dados. Em um banco de dados real existem inúmeros registros, mas repare que não precisamos de mais do que um para o teste, ele só precisa retornar uma quantidade de dados suficientes para que nossa action possa trabalhar com eles. Se a action deve trazer uma lista de carros, uma lista contendo um carro é o suficiente.

O método lista retorna uma String, mas não a testei porque ela é para uso do Struts 2, e como sempre retorno “ok”, não achei necessário. Caso o método possa retornar diferentes Strings, deve ser criado um teste considerando isso.

Através do método getCarros obtemos a lista de carros, tal qual a jsp faria, e então usamos o método assertFalse da classe Assert, mostrando que o que é esperado como resultado do teste é que a lista não esteja vazia.

O segundo teste verifica se a action adiciona um novo carro sem que haja erros. Usando o método setCarro é informado para a action qual carro deve ser adicionado, e em seguida é chamado o método adiciona para efetuar essa ação. Esse teste não possui um assert, isso porque não há como verificar se o Carro foi adicionado – só é verificado que não ocorre nenhum erro durante esse processo. Ele também é bastante simples porque não há lógica no método adiciona, o Carro apenas é passado para o dao, mas poderia haver alguma lógica que lida com os dados do carro, como uma validação por exemplo. Nesse caso, seria necessário mais um teste, em que é considerada essa situação.

Um ponto importante foi a alteração no construtor da classe CarroAction, pois sem ela, não seria possível prover um mock do dao, tornando a classe intestável. Para tal, foi necessário injetar a dependência, para possibilitar o teste unitário. Mais uma vantagem de criar testes: melhorar o design das classes!

Pode parecer que criar testes aumenta o trabalho e o tempo de desenvolvimento (no começo, realmente é necessário mais tempo), mas eu diria que diminui – e muito – o retrabalho, além de outras vantagens já citadas. Tente!

Publicado em Struts 2, Testes | Deixe um comentário

Integrando JSF 2 e Spring

Leia esse post revisto e atualizado aqui.

Ao buscar por JSF2 encontrei muito material de qualidade pela internet, mas ao buscar um modo fácil de fazer a sua integração com Spring, o material que encontrei mostrava apenas como fazê-lo com XML, o que eu não gostei nada. Após um pouco mais de estudo consegui fazer a integração com anotações, e um mínimo de XML. Aqui vou apresentar como fazer essa integração de forma bem simples!

Primeiro, as configurações. Por parte do JSF, são necessários apenas dois jars:

Jars do JSF

Jars do JSF

E por parte do Spring, são os mesmos jars usados para integração com Struts.  A configuração que deve ser feita no web.xml é a seguinte:

<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<listener>
    <listener-class>
        org.springframework.web.context.request.RequestContextListener
    </listener-class>
</listener>

As tags servlet e servlet-name são para o uso “padrão” do JSF. O ContextLoaderListener é para subir o contexto do Spring, também uma configuração comum. O que merece atenção aqui é o RequestContextListener, o qual vai expor o request para manipulação do Spring, permitindo assim que ele faça as injeções no momento adequado.

Por fim, há mais uma alteração que deve ser colocada no faces-config.xml:

<application>
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>

JSF faz uso de Expression Language (EL) para determinar a qual classe você se refere quando ela é apontada na página xhtml. Fazendo uso de uma classe chamada ELResolver ele pega a String passada, a interpreta e faz a referência adequada. A classe SpringBeanFacesELResolver proporciona a integração entre os dois frameworks interceptando a requisição e passando-a para o contexto do Spring, o qual a manipula para prover as dependências requeridas pelos ManagedBeans, que em seguida a passa para o ELResolver do próprio JSF.

Para ficar mais claro, vamos ao código. Primeiro, o Service gerenciado pelo Spring:

@Service("carroService")
public class DefaultCarroService implements CarroService {

    // métodos aqui
}

Ao utilizar a anotação @Service, se houver apenas uma implementação para CarroService, geralmente para o Spring não é necessário que um nome seja especificado, mas ele se faz necessário quando trabalhamos com JSF:

@ManagedBean
public class CarroBean {

    @ManagedProperty(name = "service", value = "#{carroService}")
    private CarroService service;

    public void setService(final CarroService service) {
        this.service = service;
    }
}

Agora a anotação @ManagedProperty será usada não apenas para se referir ao que está no escopo web, mas também para lidar com os beans do Spring. A propriedade name é usada para indicar o nome do campo do managedBean, para que o JSF chame o set adequado, enquanto a propriedade value vai ser usada para referenciar o nome do bean, no caso o carroService anteriormente especificado.

E é só isso. Fazendo uso do fluxo do próprio JSF, e com algumas poucas configurações, o Spring proporciona uma integração simples e bastante natural, que não altera em nada a forma de trabalhar com JSF.

Publicado em JSF, Spring | 17 Comentários

Código Limpo

Leia esse post revisto e atualizado aqui.

Estive presente no Agile Brazil 2011, e dentre as várias palestras que assisti, uma que me fez pensar bastante foi a do Vinicius Teles, intitulada “O dia em que a Terra acabou parou, porque o software travou” . De forma bastante resumida, Vinicius disse que vários dos problemas que encaramos diariamente é culpa nossa, dos desenvolvedores, e ele tem razão. Vide os problemas  (seja lentidão ou dificuldade de utilização) dos sistemas dos correios, aeroportos ou bancos, os quais geram filas quilométricas que todos temos que enfrentar. Ou seja, todos pagam pelos bugs dos sistemas que nós criamos!

Ele sugeriu um novo manifesto, o Manifesto Vergonha Na Cara, que estabelece que Código de verdade é código testado e limpo! Como também estou cansado de enfrentar código de péssima qualidade, resolvi fazer uma pequena contribuição; durante a palestra, foi sugerido como um dos primeiros passos a leitura do livro Clean Code do Uncle Bob, e como muita gente ainda não leu esse livro, criei um pequeno resumo, o qual, espero, desperte o interesse pelo mesmo, levando os leitores à produzir código limpo, já que, como foi muito falado durante o evento, programador profissional é aquele que produz código limpo e testado!

O resumo que fiz aqui é referente a apenas alguns tópicos do livro, os quais acho que devem ser os primeiros passos para um código melhor.

Nomes significativos

Nomes de classes, variáveis, métodos, etc, devem ser significativos, indicando claramente o que um método faz ou o que um atributo representa. A intenção deve ser visível através dos nomes. Crie nomes pronunciáveis para facilitar a comunicação, evite acrônimos e siglas.

Evite nomes confusos, os quais podem levar quem lê o código a conclusões erradas.

Use nomes que refletem o domínio do sistema, o contexto e os problemas que devem ser resolvidos.

Funções

Funções devem ser pequenas. Aliás, elas devem ser ainda menores. Deve haver apenas um nível de abstração por função.

Funções devem fazer uma coisa, e apenas uma. Novamente, utilize um nome que descreva bem o que a função faz. Utilize o menor número de argumentos possível, fazendo o máximo para que não passem de três.

Cuidado com “efeitos colaterais”, funções não podem fazer nada “escondido”. Use exceções ao invés de códigos de erro, e considere que tratar exceções é uma coisa.

Comentários

Comentários não salvam um código ruim. Procure explicar o que o código faz COM CÓDIGO.

Crie nomes de métodos e de variáveis informativos, ao invés de explicar com um comentário o que um método com um nome ruim faz. Use comentários para deixar uma expressão complexa mais clara, para avisar sobre as possíveis conseqüências de uma alteração, ou para ressaltar a importância de certo ponto do código.

Comentários ruins também poluem o código. Não escreva comentários redundantes, inúteis, ou pior, com falsas informações. Também não deve ser usado para indicar quando ou por quem foi alterado, para isso temos ferramentas de controle de versão. Não escreva comentários confusos ou grandes demais.

Não comente código que não será mais usado, simplesmente remova-o.

Objetos e estruturas de dados

Siga a Lei de Demeter. Faça boa abstração e encapsulamento. Não crie objetos burros.

Tratamento de erro

Use exceções ao invés de códigos de erro. Use exceções não checadas, e utilize mensagens de erro informativas.

Não retorne e nem passe null.

Testes

Siga as 3 leis do TDD.

Use uma assertiva por teste, e teste um conceito por vez.

Os testes devem ser rápidos, independentes, reprodutíveis em qualquer ambiente, auto-validáveis e escritos no momento certo. Mantenha o código de seus testes limpo.

Classes

Classes devem ser pequenas e seguir o princípio da responsabilidade única. Devem ser coesas,  essa coesão resulta em classes pequenas. Classes devem ser criadas visando a mudança, então programe orientado à interface.

Outros pontos que não posso deixar de citar são: Todos os testes devem estar passando; refatoração deve ser feita constantemente, visando à melhoria contínua; código duplicado deve ser evitado a todo custo; classes e métodos devem ser pequenos; o código deve ser o mais expressivo possível.

Esse resumo é um levantamento de alguns pontos importantes, tanto que aqui é mostrado o que deve ser feito, não o porquê ou o como, isso pode ser encontrado no livro. Esse post é o primeiro passo, espero que todos dêem continuidade lendo esse livro e muitos outros, buscando criar um código melhor. Eu não quero mais código sujo atrapalhando a minha vida. E você?

Publicado em Agile | 6 Comentários

Trabalhando com Spring MVC 3 de forma simples

Leia esse post revisto e atualizado aqui.

Recentemente me foi proposto encontrar uma ferramenta para usarmos no lugar do Struts 2 nos novos projetos, a qual deveria substituí-lo suprindo as suas falhas. Até aqui, sem problemas, o que complicou foi o seguinte requerimento: deve rodar no JBoss 4.0.3, o que matou a possibilidade de adotar o JSF2. A próxima opção foi o Spring MVC, e descobri nela uma ótima ferramenta! Muito completa e fazendo o que deve fazer de forma bem simples!

Durante os estudos, não encontrei muito material sobre o Spring MVC 3, mas encontrei muito sobre a versão 2.5. Aqui vou mostrar como trabalhar com a versão 3 adotando todos os seus recursos .

Como sempre, começo pela configuração. E dessa vez, tem um pouco mais do que de costume. As libs primeiro:

Libs do Spring MVC

Com as libs no local, vamos à configuração que deve ser incluída no web.xml:

<servlet>
    <servlet-name>springMvcSimples</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>springMvcSimples</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <servlet-name>springMvcSimples</servlet-name>
</filter-mapping>

DispatcherServlet é a classe que habilita o uso Spring MVC, a qual vai lidar com as requisições. HiddenHttpMethodFilter é usado para habilitar o suporte RESTful do Spring. Falarei sobre isso mais tarde.

Por padrão, o Spring vai buscar o arquivo de configurações na pasta WEB-INF, com o nome do arquivo baseado no nome da DispatcherServlet, acrescentando –servlet.xml, então vamos ver a configuração do arquivo springMvcSimples-servlet.xml:

<?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:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
    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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="br.com.vonjuliano.springmvcsimples" />

    <mvc:annotation-driven />

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

Aqui estão alguns itens de configuração muito importantes, context:component-scan vai buscar todas as classes anotadas no local indicado por base-package, procurando em todos os seus pacotes e subpacotes.

A tag mvc:annotation-driven ativa os beans do Spring necessários para direcionar as requisições recebidas para os Controllers, além de configurar esses beans para que forneçam alguns serviços padrões, entre eles:

  • Serviço de conversão de dados, quando for informado, por exemplo, um número (que é na verdade enviado como String), ele já faz a conversão automaticamente;
  • Formatação de números e datas (esse último, caso o Joda Time esteja no classpath);
  • Validação (caso uma implementação da JSR-303 esteja no classpath, como Hibernate Validator);
  • Suporte a XML (caso JAXB esteja no classpath);
  • Suporte a JSON (caso Jackson esteja no classpath).

A classe InternalResourceViewResolver é usada para estabelecer alguns padrões: a propriedade prefix indica que as views vão ficar em /WEB-INF/jsp/ (uma boa prática recomendada, já que assim as jsps não podem ser acessadas diretamente), e a propriedade suffix indica que todas terão .jsp no fim de seu nome, de forma que quando essa classe recebe “lista”, ela faz redirecionamento para /WEB-INF/jsp/lista.jsp.

Ao trabalhar com Spring, é comum a utilização de Controllers, Services e Daos, onde nos Controllers fica a lógica de manipulação de dados para exibição, no Services a lógica de negócio que não podem ficar no próprio modelo de domínio e nos Daos a lógica para acesso ao banco de dados. Aqui o Controller vai receber um Service, e vou parar por aí, pois a interação entre o Service e o Dao será mostrado em outro post.

Abaixo, o CarroController:

package br.com.vonjuliano.springmvcsimples.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import br.com.vonjuliano.springmvcsimples.model.Carro;
import br.com.vonjuliano.springmvcsimples.service.CarroService;

@Controller
@RequestMapping("/carro")
public class CarroController {

    private final CarroService service;

    @Autowired
    public CarroController(CarroService service) {
        this.service = service;
    }

    @RequestMapping(value = "/lista", method = RequestMethod.GET)
        public List<Carro> lista() {
        return service.lista();
    }

    @RequestMapping(value = "/novo", method = RequestMethod.GET)
        public ModelAndView novo() {
        return new ModelAndView("carro/novo", "carro", new Carro());
    }

    @RequestMapping(value = "/novo", method = RequestMethod.POST)
    public String novo(Carro carro) {
        service.adiciona(carro);
        return "redirect:lista";
    }

    @RequestMapping(value = "/editar/{id}", method = RequestMethod.GET)
    public ModelAndView editar(@PathVariable Long id) {
        Carro carro = service.busca(id);
        return new ModelAndView("carro/editar", "carro", carro);
    }

    @RequestMapping(value = "/editar", method = RequestMethod.PUT)
    public String editar(Carro carro) {
        service.atualiza(carro);
        return "redirect:lista";
    }
}

Trabalhando com Spring MVC é muito simples manter as operações referentes ao Carro na mesma classe. Vamos por partes:

@Controller
@RequestMapping("/carro")
public class CarroController {

A anotação @Controller é usada para dizer ao Spring que a classe é um Controller, e @RequestMapping indica que  ele vai atender à requisições que contenham /carro na url, o que aqui é usado da mesma forma que o @Namespace do Struts 2. Mas quem efetivamente atende a requisição são os métodos:

@RequestMapping(value = "/lista", method = RequestMethod.GET)
public List<Carro> lista() {
    return service.lista();
}

Combinando o value desse @RequestMapping com o existente no nome da classe, esse método vai atender a url … /carro/lista. Todas as demais são feitas dessa mesma forma.

Aqui é feito uso do suporte ao RESTful do Spring, através do parâmetro method é informado o método HTTP utilizado, de forma que o método lista atenderá apenas um método GET. Ele vai retornar uma lista com todos os carros existentes no banco e enviá-la para a jsp. Para qual jsp? Por convenção, caso não seja explicitamente informado para onde ir, o Spring vai considerar a url usada para definir isso; /carro/lista fará com que ele procure por /WEB-INF/jsp/carro/lista.jsp

E para exibir a lista na jsp, por padrão o Spring vai nomeá-la como “conteúdo da lista + List”, nesse caso, a lista será chamada de carroList, que pode ser acessado com jstl:

<c:forEach items="${carroList}" var="carro">

O Spring permite que os métodos devolvam diferentes tipos de retorno, e uma pequena variação deles será mostrada aqui. Todos os tipos de retorno permitidos podem ser vistos na documentação.

Abaixo, os métodos para inserção de um carro:

@RequestMapping(value = "/novo", method = RequestMethod.GET)
public ModelAndView novo() {
    return new ModelAndView("carro/novo", "carro", new Carro());
}

Esse método leva para a página com o formulário de cadastro de um novo carro. Aqui faço uso da classe ModelAndView para informar para o Spring para onde ir (carro/novo), o nome que será usado para referenciar o objeto na página (“carro”, que se não for informado, por padrão será “command”), e o objeto propriamente dito. Com isso, o jsp saberá com qual classe está lidando, o que facilita para o próximo método:

@RequestMapping(value = "/novo", method = RequestMethod.POST)
public String novo(Carro carro) {
    service.adiciona(carro);
    return "redirect:lista";
}

Os métodos da classe possuem o mesmo nome, mas devido aos métodos HTTP para acesso a cada um deles, o Spring sabe exatamente qual chamar. O método recebe um Carro, já que no método anterior foi informado para o Spring que era com esse objeto que ele deveria trabalhar. Assim ele já faz as conversões necessárias e seta os valores no objeto. Simples não?

O retorno da String diz ao Spring que ele deve redirecionar para o controller indicado após a palavra redirect, assim ele vai chamar o controller que lista todos os carros.

Por fim, os métodos de edição:

@RequestMapping(value = "/editar/{id}", method = RequestMethod.GET)
public ModelAndView editar(@PathVariable Long id) {
    Carro carro = service.busca(id);
    return new ModelAndView("carro/editar", "carro", carro);
}

Esse método busca o Carro para edição através do id, o qual é informado na url. /editar/{id} indica o formato da url, de forma que uma chamada válida seria /editar/2. O parâmetro id recebido no método deve ser anotado com @PathVariable para que o Spring saiba que o valor informado na url deve ser associado a esse método. As novidades nesse método acabam aqui, já que o uso do ModelAndView é feito da mesma forma do método de inserção.

@RequestMapping(value = "/editar", method = RequestMethod.PUT)
public String editar(Carro carro) {
    service.atualiza(carro);
    return "redirect:lista";
}

Esse é o método que vai salvar as alterações na base de dados. Aqui faço uso do método HTTP PUT. O DispatcherServlet do Spring suporta os seguintes métodos HTTP: GET, POST, HEAD,  PUT e DELETE, onde, por convenção, GET é usado para buscar informações, POST para enviar informações, PUT para alterar informações e DELETE para removê-las. É semelhante às operações de um CRUD.

Voltando ao método, uso o PUT para alterar os dados do carro, o que quando é feito, é redirecionado com a String informada.

Aqui vale citar que os Browsers compreendem apenas os métodos GET e POST, então para indicar que o método é PUT é necessário declará-lo como POST e criar um campo oculto de nome _method com o valor PUT (o processo é o mesmo para o caso do método DELETE). Felizmente, não é necessário fazer isso na mão, pois o Spring possui uma tag que já faz esse trabalho:

<form:form action="../editar" method="put" commandName="carro">

Essa tag, ao gerar o HTML final vai criar o campo oculto. As demais tags que o Spring proporciona podem ser vistas aqui.

Apenas fazer uso da tag não é o suficiente para que o Spring interprete o método que deve ser utilizado, e é aí que entre o HiddenHttpMethodFilter, o qual foi incluído no web.xml no começo da configuração, que é quem faz esse trabalho de encaminhar a requisição com o método HTTP adequado.

Abaixo, os códigos das jsps, para completar o que foi apresentado.

lista.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

<html>
    <head>
        <title>Spring MVC 3 Simples</title>
    </head>
    <body>
        <h3>Lista de carros</h3>
        <table border="1">
            <tr>
                <td>Id</td>
                <td>Nome</td>
                <td>Ano de fabricação</td>
            </tr>
            <c:forEach items="${carroList}" var="carro">
                <tr>
                    <td>${carro.id}</td>
                    <td>${carro.nome}</td>
                    <td>${carro.ano}</td>
                    <td><a href="editar/${carro.id}">Editar</a></td>
               </tr>
            </c:forEach>
        </table>
        <br>
        <h5><a href="novo">Novo</a></h5>
    </body>
</html>

novo.jsp

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

<html>
    <head>
        <title>Spring MVC 3 Simples</title>
    </head>
    <body>
        <h3>Novo Carro</h3>
        <form:form action="novo" method="post" commandName="carro">
            <table>
                <tr>
                    <td>Nome: <form:input path="nome" /></td>
                    <td>Ano: <form:input path="ano" /></td>
                    <td><input type="submit"></td>
                </tr>
            </table>
        </form:form>
    </body>
</html>

editar.jsp

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

<html>
    <head>
        <title>Spring MVC 3 Simples</title>
    </head>
    <body>
        <h3>Editar Carro</h3>
        <form:form action="../editar" method="put" commandName="carro">
            <form:hidden path="id" />
            <table>
                <tr>
                    <td>Nome: <form:input path="nome" /></td>
                    <td>Ano: <form:input path="ano" /></td>
                    <td><input type="submit"></td>
                </tr>
            </table>
        </form:form>
    </body>
</html>

E a classe Carro.

public class Carro {

 private Long id;
 private String nome;
 private int ano;

// gets e sets
}

Aqui foi apresentada uma forma simples que encontrei de trabalhar com Spring MVC 3, o qual é um framework muito poderoso, simples, que possuí inúmeras ferramentas para ajudar no desenvolvimento, e que funciona muito bem em servidores mais antigos, como o JBoss 4.

Publicado em Spring | 10 Comentários

Integrando Struts 2 e Spring

Leia esse post revisto e atualizado aqui.

No meu primeiro post sobre Struts 2 comentei que utilizar um container de injeção de dependência era o ideal para fazer o controle das dependências de cada classe no projeto. Aqui vou mostrar como integrar o Spring, o mais famoso container feito em java com o Struts 2 de uma maneira bem simples. Para isso, eu simplesmente fiz com que a utilização dos dois juntos ficasse o mais próximo possível de como é trabalhar com outro framework MVC (o qual considero mais simples de se trabalhar do que o Struts), o VRaptor.

Vou usar o mesmo exemplo da aplicação de carros que foi apresentada no post citado, para deixar o mais claro possível os ganhos que o Spring traz para a aplicação.

Como de costume, começo com a configuração. Além das costumeiras libs do Struts 2, será necessária mais uma, que é usada para integração com o Spring:

E por parte do Spring, devem ser adicionadas as seguintes libs:

Com isso feito, além da configuração do Struts, é necessário adicionar uma configuração para o Spring no web.xml:

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Quando trabalhamos com o Spring, é necessário informá-lo quais objetos ele terá que administrar, referenciados por ele como beans. Isso pode ser feito através de anotações, programaticamente ou através da forma clássica, um arquivo XML, que por padrão tem o nome applicationContext.xml. Aqui serão utilizadas anotações, mas muitas vezes é bem prático usar esse XML, por exemplo quando usamos classes do próprio Spring. Aqui ele será usado para informar ao Spring onde procurar as classes, as quais ele vai identificar por meio das anotações:

<?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"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:component-scan base-package="br.com.vonjuliano.strutsspringsimples" />

</beans>

Indicando um determinado pacote, o Spring vai buscar nele e em todos os seus subpacotes por classes anotadas com @Component e suas especializações, e quando encontrar, vai adicioná-las ao container.

Sei que no outro post evitei o uso do XML do Struts, mas aqui ele se faz necessário. Para realizar a integração com o Spring, será preciso indicar ao Struts que o Spring é que fará a instanciação de objetos. Para isso será criado o arquivo struts.xml dentro da pasta src, com o seguinte conteúdo:

<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <constant name="struts.objectFactory" value="spring" />
</struts>

A parte da configuração termina aqui.

Agora é hora de fazer as anotações. Aqui só é necessário fazê-lo para duas classes, a CarroAction e a JdbcCarroDao, lembrando que a action depende do dao. O Spring possui uma anotação geral @Component que pode ser usada para anotar as classes, mas eu prefiro suas especializações; para a action, será usada a anotação @Controller, que indica que ela é uma controladora:

import org.springframework.stereotype.Controller;

@Controller
@Namespace(value = "/carro")
public class CarroAction {

E para o caso do dao, a anotação usada será @Repository, a qual indica que a classe é um “repositório”, ou um Dao (nomes diferentes para o mesmo conceito):

import org.springframework.stereotype.Repository;

@Repository
public class JdbcCarroDao implements CarroDao {

Para terminar, falta informar ao Spring que ele deve injetar o dao na action. Isso pode ser feito de três formas: através de um método set, através do construtor ou diretamente no campo. Essa última forma eu desaconselho fortemente, já que o Spring simplesmente injeta o valor do campo passando por cima de qualquer outra prática ou princípio, o que dificultaria um teste unitário. Usar o set é uma forma muito comum, mas creio que usar o construtor é a forma mais adequada, pois assim fica evidente que a action depende do dao, garantindo programaticamente que ela não possa ser instanciada sem ele.

Dessa forma, o construtor da classe CarroAction fica assim:

import org.springframework.beans.factory.annotation.Autowired;

public class CarroAction {

    private CarroDao dao;

    @Autowired
    public CarroAction(CarroDao dao) {
        this.dao = dao;
    }

Assim o Spring vai injetar o dao pelo construtor. É possível fazer isso sem a anotação, mesmo sem ela o Spring vai procurar uma forma de injetar a dependência (nesse caso, através do construtor, mas ele também procura por um método set) e também funcionaria corretamente, mas creio que fazer uso dela deixa o código muito mais claro.

O grande ganho de fazer o uso do Spring nesse exemplo é o desacoplamento: repare que agora CarroAction faz referencia apenas à interface CarroDao, ela não tem conhecimento algum de sua implementação. A grande vantagem é que agora é possível mudar a implementação do dao sem que a action seja afetada, seria só o caso de informar ao Spring que o componente injetado agora é outro. Poderia, por exemplo, criar uma nova implementação de CarroDao com Hibernate, HibernateCarroDao, e essa substituição seria transparente para a CarroAction. Para isso seria necessário uma outra integração, dessa vez entre o Spring e o Hibernate, mas isso é assunto para um próximo post.

Publicado em Spring, Struts 2 | 4 Comentários