Aproveitando os beans do Spring em suas páginas JSF
Sunday, February 24th, 2008Esses dias estava tendo uma conversa bem produtiva com um amigo de trabalho, Tarso Bessa, o cara é muito safo em desenvolvimento e sempre me aparece com umas idéias bem bacanas. Nessa conversa ele chegou com uma idéia bem interessante sobre aproveitarmos a integração do Spring com JSF, a idéia se resume em aproveitar o variable resolver do Spring nas páginas JSF, assim poderíamos acessar qualquer bean gerenciado pelo Spring (Service, DAO, Repository, whatever) nas páginas através de JSF EL sem a necessidade de intermediar o acesso à este bean com um managed bean do JSF.
O problema
O problema realmente surgiu enquanto o Tarso implementava um mecanismo de CRUD genérico para nossa aplicação, foi aí que começamos a discutir sobre o problema e em seguida a solução.
Na verdade, no projeto que estamos desenvolvendo nós utilizamos muitas combo-boxes (tr:SelectOneChoice pois utilizamos o Myfaces Trinidad) nas nossas páginas e ter que criar um ou mais métodos nos nossos managed beans somente para popular essas combos com dados trazidos diretamente do banco de dados -sem qualquer lógica-, além de ser uma tafera repetitiva, não era nada cômodo.
No final das contas só queríamos não escrever mais código repetitivo nos nossos managed beans (principalmente os que estendiam o nosso CRUD genérico) simplemente para podermos acessar nas páginas uma lista de objetos trazidos do banco de dados.
A solução
Com a integração do Spring com JSF é possível fazer injeção de dependências (DI) dos beans do Spring dentro dos managed beans da aplicação pelo faces-config.xml, algo como:
[faces-config.xml]
<managed-bean>
<managed-bean-name>bacalhauBean</managed-bean-name>
<managed-bean-class>bean.faces.BacalhauBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>someService</property-name>
<property-class>model.service.SomeService</property-class>
<value>#{someService}</value>
</managed-property>
</managed-bean>
Imaginem que nós tenhamos um bean chamado “someService” configurado no spring-config.xml, ok?
Agora observem que o bean gerenciado pelo Spring é resolvido através da EL do JSF, #{someService}, então por que não utilizar-se disso para acessarmos diretamente este bean dentro das páginas? ![]()
Será isso que iremos fazer logo abaixo!
Imagine que nossa implementação da interface SomeService seja algo do tipo:
[SomeServiceImpl.java]
public class SomeServiceImpl implements SomerService {
// outros métodos deste serviço
public List<Foo> findAll() {
// executa a pesquisa através de um DAO, ou repositório, whatever..
}
public List<Foo> getAll() {
// faz chamada ao método findAll
return this.findAll();
}
}
Assim no código da página nós precisaríamos fazer apenas isto:
[foo.jsp]
<h:selectOneMenu id="fooId" value="#{bacalhauBean.fooId}">
<t:selectItems value="#{someService.all}" var="o" itemValue="o.id" itemLabel="o.name" />
</h:selectOneMenu>
Observem que estou passando a lista de objetos para o componente através da EL #{someService.all} que reflete o método SomeServiceImpl.getAll() do bean gerenciado pelo Spring, atentem também que estou utilizando o componente t:selectItems do Myfaces Tomahawk para que eu possa iterar uma lista de objetos comuns, pois sem ele seria necessário passar uma lista de SelectItem’s, o que não ficaria legal nas nossas classes de serviços.
O melhor de tudo é que não há a necessidade de utilizar um managed bean para intermediar a lista de dados para o componente, o EL do JSF acha o bean “someService” no contexto do Spring e faz a chamada ao método para você (é necessário que o método comece com “get” para que a EL consiga executar corretamente, por isso criamos um método chamado getAll() na classe do SomeServiceImpl.java).
Graças ao variable resolver do Spring você poderá utilizar o #{someService.all} em qualquer componente que espere uma lista de objetos, como um h:dataTable, h:selectManyMenu ou qualquer outro. Além do mais você poderá obter um objeto qualquer como um entity, ou um mapa, ou uma lista ordenada e/ou filtrada diretamente dos beans gerenciados pelo Spring e utilizá-los nas tuas páginas sem dificuldades.
Uma coincidência é que enquanto o Tarso estava fazendo os testes e implementando a solução ele caiu naquele velho probleminha do selectOneMenu, não exatamente como no cenário que eu havia blogado, mas o problema e a solução foram a mesma, e acabamos resolvendo este problema rapidamente sem perder tempo. É como eu disse no final daquele post, “[...] quem não passou provavelmente irá passar algum dia.”
O mais engraçado..
O mais engraçado disso tudo é que já temos tudo isso pronto e muito melhor implementado com o JBoss Seam, o Seam estendeu a EL do JSF e com isso conseguimos acessar qualquer componente no seu contexto através de EL, como DAOs, repositorios, serviços etc, e o melhor é que a sua EL estendida nos fornece a possibilidade de executar métodos parametrizados, ou seja, com ele podemos ter algo como isto:
<h:commandButton action="#{hotelBooking.bookHotel(hotel, user)}" value="Book Hotel"/>
Simplesmente fantástico!
Enfim, para quem não tem o JBoss Seam no projeto, pode ter um pouco do gostinho dele com o Spring.
Concluindo..
Como achei o problema e a solução interessantes eu quis compartilhar com os pouquíssimos leitores deste blog, fica aí a dica senhores.
Valeu Tarso Bessa, valeu gente.