Top Posts

Série DesignPattern:Builder

Continue lendo

Usando Spring Core com múltiplos projects

Posted by camilolopes | Posted in Java, Spring | Posted on 14-10-2013

0

Olá Pessoal,

O post hoje é bem rápido e a ideia é compartilhar com vocês um problema comum quando temos mais de um projeto com dependência e precisamos usar o applicationContext que está em outro projeto.  São coisas que a gente não decora e que normalmente faz uma vez a cada novo projeto e que certamente esquecemos com o passar do tempo. E se algum livro fala sobre o assunto, certamente nem damos atenção à esse detalhe, pois estamos ansiosos em querer meter a mão na massa.

lets go…

 

Contexto

Recentemente tive que criar um projeto com module do maven. Veja a estrutura para ficar mais claro: 

—parent

—core

—web

–dependecy of core

 

Com o desenho simples acima estou dizendo que tenho um projeto parent (pai) que tem dois filhos: core e web. E o filho web depende do projeto core. 

No projeto core temos o back-end da aplicação, ou seja, regras de negócio e persistência vão estar nesse projeto. O projeto web vai cuidar do front-end. É nele que teremos o controller, os arquivos .html, xhtml, jsp, js etc. 

Então na prática o projeto web tem um .jar do projeto core: 

<dependency>

<groupId>com.handson.core</groupId>

<artifactId>xxx-core</artifactId>

<version>1.0.0</version>

</dependency>

 

Até aqui tudo bem. Nenhum problema, certo? 

Como falei, o projeto core tem o applicationContext do Spring, já que é lá que fazemos IoC, dizemos para o spring cuidar da sessionFactory etc. 

E qual o problema?

Quando precisamos usar o ApplicationContext no web. Esse é o problema. O código a seguir não vai funcionar quando aplicação subir:

 

 @Controller

@Path(“/user”)

public class UserController {

@Autowired

@Qualifier(“userServiceImpl”)

private UserService userService;

//código omitido

}

 

Por que não vai funcionar? Porque o applicationContext está dentro de .jar de outro projeto e ao subir a aplicação precisamos dizer isso para web.xml. Uma forma simples  é criar um arquivo applicationContext em web e importar o que temos no applicationContext no projeto core. Portanto, crie um app-context.xml em resource do projeto web:

 

springprojectwebresource

E no arquivo app-context que está no projeto web, faça isso:

<beans xmlns=”http://www.springframework.org/schema/beans”

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation=”http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd”> 

<import resource=”classpath*:/META-INF/app-context.xml”/>

</beans> 

Esse caminho acima é porque o arquivo no projeto core está assim:

springappcontextcore

 

Agora no arquivo web.xml no projeto xx-web deixe assim:

 springwebxml

Assim, ao subir a aplicação o arquivo que está dentro do .jar do projeto core será carregado. E no import que fizemos anteriormente dizemos para importar esse arquivo para o contexto da aplicação web que está sendo carregada. 

Pronto. Salve as alterações e execute mvn install. Suba a aplicação. Se o Spring não conseguir fazer o @Autowired ele irá reclamar logo que subir. Mas o esperado é que não tenha problemas. 

Abraços! Vou ficando por aqui. Espero que tenham gostado da dica de hoje.

Série Spring: JEE:CRUD Hibernate com Spring 3 + JSF 2.0

Posted by camilolopes | Posted in Series, Spring | Posted on 28-05-2013

0

 

Olá Pessoal,

Continuando a nossa série de post sobre o Spring vamos, ver hoje como fazer um simples CRUD com Spring + Hibernate + JSF.O objetivo maior, é para quem está chegando possa ver como juntar as tecnologias de maneira simples. E o melhor de tudo veremos como Spring  é uma mão na roda de verdade.

Lets go…

Starting…

A nossa aplicação será super simples, vamos fazer o cadastramento de carros, e exercitar o CRUD. Para exibição e cadastro dos veículos, vamos fazer uma página JSF de maneira mais simples possível e que seja funcional.  A seguir os requisitos:

Requisitos:

  • – MysqlSQL 5.x
  • – Hibernate 3.x
  • – Spring 3.x
  • – Tomcat 7.x
  • – JSF 2.x
  • – Jboss tools

Vou considerar que você vem acompanhando a série de posts  Spring no blog e alguns pontos que já foi tratado aqui, não estarei explicando novamente, dúvidas? Farei um link para o post referente. E sobre JSF 2.x também irei considerar que vc já brincou com o framework, mesmo que seja na versão anterior. Estou ressaltando isso, para que não entre no detalhes de cada ponto, e que o post fique mais direto e mão na massa.

 Configuração

Primeiro ponto é , criar um projeto JSF Project (é preciso ter o jboss tools instalado).

projetocrudspringcar

Escolha a opção JSF 2 na tela do assistente.  Em seguida crie os packages conforme a seguir, por enquanto eles estarão vazios, mas iremos daqui a pouco colocar carne no esqueleto : ).

Adicione os .jars na pasta lib do projeto:

webinflib

Criando o source unit/test

Observe que eu criei um source para os unit tests:

unitestscarcrud

Agora vamos criar o arquivo de configuração do Spring. Na verdade teremos dois, um para os unit tests e outro para aplicação. Apenas dupliquei, mas poderíamos otimizar o de unit tests importando apenas o que precisamos a partir do arquivo principal, mas não quis fazer isso por agora, vamos focar no CRUD.

Crie um arquivo springconfiguration.xml  dentro de WEB-INF, o nome poderia ser qualquer um, normalmente utiliza-se applicaiton-context.xml, mas quis fazer diferente para que você veja que o nome não importa.

Não irei adicionar o cabeçalho apenas o código, que não tem nada de diferente do que já vimos nos posts quando vimos hibernate com Spring.

<context:component-scan base-package=“*”/>

<tx:annotation-driven/> 

<tx:advice id=“txAdvice”>

<tx:attributes>

<tx:method name=“add*” propagation=“REQUIRED”/>

<tx:method name=“delete*” propagation=“REQUIRED”/>

<tx:method name=“read*” propagation=“REQUIRED”/>

<tx:method name=“*” propagation=“SUPPORTS” read-only=“true”/>

</tx:attributes>

</tx:advice> 

<aop:config>

<aop:advisor pointcut = “execution(* *..CarDAO.*(..)))” advice-ref=“txAdvice”/>

</aop:config> 

<bean class=“org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor”/> 

<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> 

<bean id=“sessionFactory” class=“org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean”>

<property name=“dataSource” ref=“dataSource”/>

<property name=“packagesToScan” value=“br.com.camilolopes.car.domain.bean”/>

<property name=“hibernateProperties”>

<props>

<prop key=“hibernate.dialect”>org.hibernate.dialect.MySQL5InnoDBDialect</prop>

<prop key=“hibernate.hbm2ddl.auto”>update</prop>

</props>

</property>

</bean>

<bean id=“transactionManager” class=“org.springframework.orm.hibernate3.HibernateTransactionManager”>

<property name=“sessionFactory” ref=“sessionFactory”/>

</bean>

 

Agora precisamos fazer umas configurações no arquivo web.xml

<!– dizendo onde está meu arquivo de configuração –>

 <context-param>

  <param-name>contextConfigLocation</param-name>

  <param-value>/WEB-INF/springconfiguration.xml,</param-value>

 </context-param>

 <!– configurando o context loader do Spring, esse cara permite carregar N arquivos de configuração –>

 <listener>

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

 </listener>

 <!– esse cara permite dizer ao JSF que os beans serão gerenciados pelo Spring é requerido ter essa

 configuração –>

 <listener>

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

 </listener>

 Testando.

Se você subir aplicação agora, não há nade especial, apenas vai subir o exemplo que temos no JSF Project que é criado pelo Jboss tols. Mas, é bom testar para garantir que as mudanças que fizemos no web.xml , não afetou nada da aplicação.

Arquivo de configuração do spring para unit tests

Agora vamos criar um arquivo de configuração para executar os unit tests. Mas, pq? Simplesmente pq a partir de uma classe de teste você não consegue ler um arquivo que está em web-inf, então você precisa ter o arquivo em source.

Noticia boa: o código é o mesmo que  do arquivo anterior, então duplique o XML apenas, o meu chamei de springconfiguration-test.xml e coloquei no JavaSource:

sourcespringconfiuration-test

Agora vamos começar a brincadeira, ou seja, desenvolver.

Development

Começaremos pelos testes claro. Para isso criaremos uma classe que testará o serviço que implicitamente testa as classes DAO.

Antes criaremos os testes precisamos entender que é importante entender que:

– após testes terem sido executados este deve dar rollback, para que os dados não fiquem no banco;

– os testes não podem ser dependentes de outro test, ou seja, um @Test não pode depender da execução de outro @Test

Por enquanto, ao criar os unit test é esperado que nem compile, já que não temos nenhuma classe pronto, mas é isso que queremos, que os testes nos ensinem a  desenvolver as regras de negocio que precisamos.

O primeiro teste vai nos permitir  testar o salvarOrUpdate  da nossa aplicação, poderia ter separado em dois testes um para save e outro para update, mas não quis entrar muito detalhes sobre testes aqui, senão o post ia fica 2x maior e sinceramente não curto muito posts grandes.

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations={“classpath:springconfiguration-test.xml”})

@TransactionConfiguration(transactionManager=”transactionManager”,defaultRollback=true)

@Transactional

public class CarServiceImplTest {

      @Autowired

      private CarServices carServices;

      private Car car;

      @Before

      public void setUp() throws Exception {

      car = new Car();

      car.setDescription(“ferrari”);

      car.setPriceSale(BigDecimal.ZERO);

      car.setYear(“2010”);

      }

      @Test

      public void testSaveOrUpdate() {

            try{

                  carServices.saveOrUpdate(car);

            }catch (Exception e) {

                  fail(“not expected result”);

            }

      }

 

Observe que configuramos o rollback igual a true para tudo, então sempre será feito rollback e nada é inserido no banco. Mas,se você quer inserir no banco para um método especifico, basta anotarmos  no método assim: @Rollback(false) //isso faz inserir no banco 

Note: nesse exemplo não estou usando um banco em memória, então  é preciso que o Mysql esteja rodando para que os testes possam ser executados, o ideal é era fazer os testes rodarem em um banco em memória assim, não teríamos essa dependência, pois o banco seria iniciado sempre que os testes fossem executados.

Agora vamos criar as classes que o Eclipse está reclamando, vamos começar pela entidade Car:

@Entity(name=”SALE_CARS”)

public class Car implements Serializable{

      private static final long serialVersionUID = 2792374994901518817L;

      @Id

      @GeneratedValue

      private Long id;

      private String description;

      private BigDecimal priceSale;

      private String year;

//getters/setters omitidos

 

Services

Vamos criar os serviços, mas antes precisamos ter uma interface para os nossos serviços CRUD então:

public interface CarServices {

      void saveOrUpdate(Car car);

      void delete(Car car);

      List<Car> listAll();

}

 Agora vamos criar a classe em si:

@Service

public class CarServiceImpl implements CarServices {

      @Autowired

      private CarDAO carDAO;     

      public void saveOrUpdate(Car car) {

            carDAO.addCar(car);

      }

//setters CarDAO omitido. Não é preciso criar get.

DAO Interface

Também criaremos uma interface para o DAO e em seguida a implementação do método save

public interface CarDAO {

      void addCar(Car car);

      List<Car> readAll();

      void deleteCar(Long id);     

}

@Repository

public class CarDAOImpl implements CarDAO {

      @Autowired

      private SessionFactory sessionFactory;

           private Session getCurrentSession(){

            return sessionFactory.getCurrentSession();

      }

      public void addCar(Car car) {

            getCurrentSession().saveOrUpdate(car);

      }

//setters sessionFactory ommitido, não é preciso cria get.

Claro que os demais métodos da interface estarão sem código por enquanto, pois o objetivo agora é testar o create do CRUD.

Testando via Unit Tests

Agora vamos rodar o nosso teste e ver o resultado, se você não adicionou o JUNIT4 ao seu projeto, o Eclipse vai fazer a sugestão.

Note: Ao rodar o unit tests e você ter a exceção:

org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available

faça o download http://cglib.sourceforge.net/ e adicione a lib ao seu projeto na pasta web-inf/lib

O resultado

saveorupdategreen

Agora precisamos desenvolver o RUD.  A seguir os testes que foram criados e depois, o código com a resolução:

 @Test

public void testDelete() {

            try{carServices.saveOrUpdate(car);

                  carServices.delete(car);

            }catch (Exception e) {

String notExpectedResult = “Not expected result “+ e.getMessage();

                  fail(notExpectedResult);

            }

      }

      @Test

      public void testListAll() {

            carServices.saveOrUpdate(car);

            assertFalse(carServices.listAll().isEmpty());

      }

 Classe DAO

public List<Car> readAll() {

            return getCurrentSession().createCriteria(Car.class).list();

      } 

      public void deleteCar(Long id) {

            Criteria criteria = getCurrentSession().createCriteria(Car.class);

            criteria.add(Restrictions.eq(“id”, id));

            Car car = (Car) criteria.uniqueResult();

            getCurrentSession().delete(car);

      }

 Classe de Serviço:

      public void delete(Car car) {

            carDAO.deleteCar(car.getId());

      } 

      public List<Car> listAll() {     

            return carDAO.readAll();

      } 

      public void setCarDAO(CarDAO carDAO) {

            this.carDAO = carDAO;

      }

Rodando todos os testes:

reusultadoAlltestescrud

Há um detalhe que fiz de propósito, observe que não tem um teste para validar o update, deixarei esse como motivação para você brincar mais com unit test  : ).

 

resultdbcrudspringunittests

Observe que nosso banco está vazio, ou seja, nada foi adicionado.

JSF

Agora que já sabemos que o nosso CRUD está funcionando, vamos trazer isso para o nosso front-end com JSF.:

Crie uma classe controller

@Controller

public class CarController {

      @Autowired

      private CarServices carServices;

      private Car car;     

      private List<Car> listCars;     

      public CarController() {

            car = new Car();

      }     

      public void save(){

            carServices.saveOrUpdate(car);

            car = new Car();

      } 

      public void delete(){

            carServices.delete(car);

            car = new Car();

      }     

      public List<Car> getListCars() {

            listCars = carServices.listAll();

            return listCars;

      }

                //setters/getters omitidos

Observe que nosso controller conecta com o nosso service. Só isso que precisamos. Se você já brinca com JSF nada de especial por aqui.

Criando  .xhtml

Na verdade vamos alterar o index.xhtml que foi criado por default pelo jboss tools:

<html><head><meta http-equiv=“Refresh” content=“0; URL=pages/sales-car.jsf”/></head></html>

 

Apenas fizemos um redirecionamento para uma página que vamos criar.

sales-car.xhtml

Crie um xhtml, com suporte facelets e adicione o código a seguir:

<body>

<h:form>

<h:commandLink action=“form-car” value=“::Cadastro”/>

</h:form>

</body>

 

Essa página vai levar para a tela de cadastro:

form-car.xhtml

Vamos por parte:

Primeiro temos o código do form:

<h:form>

<h:panelGrid columns=“2”>

<h:outputLabel value=“Car Description: “/>

<h:inputText value=“#{carController.car.description}”/>

<h:outputLabel value=“Sale Price: “/>

<h:inputText value=“#{carController.car.priceSale}” converter=“javax.faces.BigDecimal”/>

<h:outputLabel value=“year:”/>

<h:inputText value=“#{carController.car.year}”/>

<h:commandButton value=“Save” actionListener=“#{carController.save}”/>

</h:panelGrid>

Agora vamos ter o código de uma tabela que exibi o usuário adicionado e permite editar/deletar :

<h:dataTable id=“cartable” value=“#{carController.listCars}” var=“car” cellpadding=“10”>

<h:column>

<f:facet name=“header”>

<h:outputText value=“Id”/>

</f:facet>

#{car.id}

</h:column>

<h:column>

<f:facet name=“header”>

<h:outputText value=“Description”/>

</f:facet>

#{car.description}

</h:column>

<h:column>

<f:facet name=“header”>

<h:outputText value=“Sale Price”/>

</f:facet>

<h:outputText value=“#{car.priceSale}”>

<f:convertNumber type=“currency” maxFractionDigits=“3”/>

</h:outputText>

</h:column> 

<h:column>

<f:facet name=“header”>

<h:outputText value=“Year”/>

</f:facet>

#{car.year}

</h:column> 

<h:column>

<f:facet name=“header”>

<h:outputText value=“Action”/>

</f:facet>

<h:commandLink value=“Delete” action=“#{carController.delete}”>

<f:setPropertyActionListener target=“#{carController.car}” value=“#{car}”/>

</h:commandLink>

<h:commandLink value=” | Edit “>

<f:setPropertyActionListener target=“#{carController.car}”  value=“#{car}”/>

</h:commandLink>

</h:column> 

</h:dataTable>

</h:form>

 

Pronto. Esse é o nosso front-end para testarmos o CRUD, vamos subir aplicação, clique com o botão direito  no projeto e escolha  Run as >> Run on Server

Note: Caso não tenha um servidor selecionado com o projeto o Eclipse vai solicitar que escolha um, no meu caso escolhi o tomcat e informei o local de instalação. Se der tudo certo você terá a tela a seguir:

screenaddjsfcars

Vamos para tela de cadastro clicando no botão “Cadastro”

 

cadcarscreenspring

addingcar

 

carsresultscreen

Verificando no bd:

 

checkingbdcars

Editando:

 

carrdseditjsf

Resultado Edição:

editresultjsfspring

E no banco:

 

editbdcars

 

Ufa! Post longo heim, e olha que reduzir. Mas, vou ficando por aqui. E espero que tenham gostado.

Abraços, see ya!!!