Bom, tenho meu applicationContext:
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<bean id="livroDAO" class="br.com.odontonew.dao.LivroDAO"/>
<bean class="br.com.odontonew.bo.LivroBOImpl" id="livroBO">
<property name="dao" ref="livroDAO" />
</bean>
</beans>
pelo meu entendimento, posso utilizar o “livroBO” em qualquer *.xhtml, então fiz assim:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>AppJSF2</title>
</h:head>
<h:body>
<h1>Gerenciador de Livros</h1>
<h:dataTable value="#{livroBO.listar}" var="l">
<h:column>
<f:facet name="header">
<h:outputText value="Titulo" />
</f:facet>
<h:outputText value="#{l.titulo}" />
</h:column>
</h:dataTable>
</h:body>
</html>
mas simplesmente não funciona, nada acontece. Nenhum erro e nada é listado. Obs: tem dados no banco e o problema não estar na recuperação destes dados pois seu eu mudar o livroBO para livroBOImpl (que é o meu ManagedBean) funciona normal.
Vc está tentando acessar um recurso do Spring via tela diretamente. Vc deve fazer a sua view estar atrelada ao ManagedBean do JSF, e esse fazer os repasse para as outras camadas, como regra de negócio e DAO. O JSF não conhece LivroBO, e sim o ManagedBean LivroBOImpl.
Espero ter ajudado.
Bom, não ficou muito claro, vamos lá. Pelo que entendi não posso utilizar o Spring na camada View, apenas Controller e Model, ou seja, apenas nas Classes .Java
Pois bem, usando ainda o mesmo applicationContext.xml que mostrei logo acima, implementei minha classe LivroBOImpl da seguinte forma:
package br.com.odontonew.bo;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import org.apache.log4j.Logger;
import br.com.odontonew.bean.Livro;
import br.com.odontonew.dao.AbstractDAO;
import br.com.odontonew.dao.LivroDAO;
@ManagedBean(name="livroBOImpl")
@SessionScoped
public class LivroBOImpl implements BasicBO {
private Logger log = Logger.getLogger(LivroBOImpl.class);
private Livro livro;
private DataModel listaLivros;
private AbstractDAO<Livro> dao;
public AbstractDAO<Livro> getDao() {
return dao;
}
public void setDao(AbstractDAO<Livro> dao) {
this.dao = dao;
}
@Override
public DataModel getListar() {
if (log.isDebugEnabled())
log.debug("Buscando lista de livros");
listaLivros = new ListDataModel(dao.findAll());
return listaLivros;
}
@Override
public String prepararInsecao() {
livro = new Livro();
return "gerenciarLivro";
}
@Override
public String prepararAlteracao() {
livro = (Livro) listaLivros.getRowData();
return "gerenciarLivro";
}
@Override
public String adicionar() {
dao.save(livro);
return "index";
}
@Override
public String excluir() {
dao.delete(livro);
return "index";
}
@Override
public String alterar() {
dao.update(livro);
return "index";
}
public Livro getLivro() {
return livro;
}
public void setLivro(Livro livro) {
this.livro = livro;
}
}
Perceba que faço um AbstractDAO dao (getters e setters) para tentar fazer a injeção de dependência neste atributo. Porém quando inicializo minha aplicação da o seguinte erro:
java.lang.NullPointerException
br.com.odontonew.bo.LivroBOImpl.getListar(LivroBOImpl.java:38)
Acontece que a criação dos beans está sendo feita pelo JSF e não pelo Spring Framework.
Se você não setar no faces-config.xml que o Spring será o bean generator, nada funcionará.
Pesquise no google, tem um milhão de exemplos de JSF 2 + Spring Framework e em todos eles existe a configuração.
Bom, lendo os tutoriais, principalmente deste site(http://www.mkyong.com/jsf2/jsf-2-0-spring-integration-example/), percebi que o Spring vai me ajudar a instanciar atributos dentro do ManagedBean (de forma automática e transparente), mas ainda assim eu preciso explicitamente dizer através do faces-config.xml quem é o ManagedBean para ser utilizado no *.xhtml, ou seja, o spring não se comunica com o XHTML, ele se comunica com as classes Java e o JSF faz a interseção entre XHTML e Java.
Estou correto ?
[quote=rlanhellas]Bom, lendo os tutoriais, principalmente deste site(http://www.mkyong.com/jsf2/jsf-2-0-spring-integration-example/), percebi que o Spring vai me ajudar a instanciar atributos dentro do ManagedBean (de forma automática e transparente), mas ainda assim eu preciso explicitamente dizer através do faces-config.xml quem é o ManagedBean para ser utilizado no *.xhtml, ou seja, o spring não se comunica com o XHTML, ele se comunica com as classes Java e o JSF faz a interseção entre XHTML e Java.
Estou correto ?[/quote]
Tudo o que o xhtml vai apresentar precisa, obrigatoriamente, estar dentro da árvore do FacesContext. É isso que você faz quando explicita no faces-config.xml que o Spring Framework será o bean generator e, também, quando colocar os getters e setters no teu ManagedBean. Os getters tornam o objeto acessível ao xhtml e os setters permitem que você defina valores para os atributos do ManagedBean. Neste caso, a única responsabilidade do Spring Framework é dispor os objetos relacionados no MB quando a árvore de componentes do FacesContext é montada.
Obrigado pela explicação. Vou testar o projeto com a integração entre spring e jsf2 e retorno aqui assim que possível.
Caro, fiz as configurações necessárias mas não funcionou. Veja:
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
<managed-bean>
<managed-bean-name>livroBO</managed-bean-name>
<managed-bean-class>br.com.meuprojeto.LivroBOImpl</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>dao</property-name>
<value>#{livroDAO}</value>
</managed-property>
</managed-bean>
</faces-config>
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="livroDAO" class="br.com.meuprojeto.dao.LivroDAO"/>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ApplicationJSF2</display-name>
<welcome-file-list>
<welcome-file>index.jsf</welcome-file>
</welcome-file-list>
<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>*.jsf</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>
</web-app>
index.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>AppJSF2</title>
</h:head>
<h:body>
<h1>Gerenciador de Livros</h1>
<h:dataTable value="#{livroBO.listar}" var="l">
<h:column>
<f:facet name="header">
<h:outputText value="Titulo" />
</f:facet>
<h:outputText value="#{l.titulo}" />
</h:column>
</h:dataTable>
</h:body>
</html>
Eu inicio o Tomcat normalmente, porém quando acesso a página da o seguinte erro:
javax.servlet.ServletException: Não foi possível criar o bean gerenciado livroBO. Os seguintes problemas foram encontrados:
- O bean ou a classe da propriedade br.com.meuprojeto.LivroBOImpl do bean gerenciado livroBO não pôde ser encontrada.
- O bean ou a classe da propriedade br.com.meuprojeto.LivroBOImpl do bean gerenciado livroBO não pôde ser encontrada.
javax.faces.webapp.FacesServlet.service(FacesServlet.java:659)
root cause
com.sun.faces.mgbean.ManagedBeanCreationException: Não foi possível criar o bean gerenciado livroBO. Os seguintes problemas foram encontrados:
- O bean ou a classe da propriedade br.com.meuprojeto.LivroBOImpl do bean gerenciado livroBO não pôde ser encontrada.
- O bean ou a classe da propriedade br.com.meuprojeto.LivroBOImpl do bean gerenciado livroBO não pôde ser encontrada.
Note que em teu applicationContext.xml você tem apenas o objeto livroDAO (id=“livroDAO”) mapeado. Isso significa que ele será o único a ser instanciado pelo container do Spring Framework.
Se você tiver isso em teu código
LivroDAO livroDAO = new LivroDAO();
Você não está obtendo o objeto instanciado pelo Spring. Logo, isso não tem relevância.
Como eu acredito que livroDAO não é um objeto que será isolado, você vai precisar mapear os demais objetos da hierarquia. Pelo que entendi do teu modelo, o livroDAO é um atributo de LivroBOImpl. Sendo assim, você precisa ter uma entrada parecida com esta no teu applicationContext.xml:
<bean id="livroBO" class="br.com.meuprojeto.bo.LivroBOImpl">
<property name="livroDAO" ref="livroDAO"/>
<!-- Demais atributos relevantes aqui -->
</bean>
Isso fará com que, você tenha o atributo livroDAO injetado em teu livroBO. Para que o livroBO tenha utilidade, você precisará fazer o mesmo (inserir mapeamento) até chegar no ManagedBean correspondente. Aí você tem toda estrutura controlada pelo Spring.
<bean id="livroBean" class="br.com.meuprojeto.pacote.LivroBean">
<property name="livroBO" ref="livroBO"/>
</bean>
Veja que acima eu amarrei o livroBO ao livroBean. Como livroDAO está amarrado a livroBO, quando a instância de objeto referente ao atributo livroBO do livroBean for instanciada, automaticamente carregará o livroDAO consigo.
Na verdade estava errado o meu faces-config.xml eu estava chamando “br.com.meuprojeto.LivroBOImpl” quando o certo é “br.com.meuprojeto.bo.LivroBOImpl”.
Porém, testei das duas formas no applicationConext.xml e funcionou, gostaria de saber o porque:
forma 1:
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<bean id="livroDAO" class="br.com.meuprojeto.dao.LivroDAO"/>
<bean class="br.com.meuprojeto.bo.LivroBOImpl" id="livroBO">
<property name="dao" ref="livroDAO" />
</bean>
</beans>
FOrma 2:
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<bean id="livroDAO" class="br.com.meuprojeto.dao.LivroDAO"/>
</beans>
Segue meu LivroBOImpl:
package br.com.meuprojeto.bo;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import org.apache.log4j.Logger;
import sun.org.mozilla.javascript.internal.Context;
import br.com.meuprojeto.bean.Livro;
import br.com.meuprojeto.dao.AbstractDAO;
import br.com.meuprojeto.dao.LivroDAO;
public class LivroBOImpl implements BasicBO {
private Logger log = Logger.getLogger(LivroBOImpl.class);
private Livro livro;
private DataModel listaLivros;
private AbstractDAO<Livro> dao;
public AbstractDAO<Livro> getDao() {
return dao;
}
public void setDao(AbstractDAO<Livro> dao) {
this.dao = dao;
}
@Override
public DataModel getListar() {
listaLivros = new ListDataModel(dao.findAll());
if (log.isInfoEnabled())
log.info("Livros encontrados: "+listaLivros.getRowCount());
return listaLivros;
}
@Override
public String prepararInsecao() {
livro = new Livro();
return "gerenciarLivro";
}
@Override
public String prepararAlteracao() {
livro = (Livro) listaLivros.getRowData();
return "gerenciarLivro";
}
@Override
public String adicionar() {
dao.save(livro);
return "index";
}
@Override
public String excluir() {
dao.delete(livro);
return "index";
}
@Override
public String alterar() {
dao.update(livro);
return "index";
}
public Livro getLivro() {
return livro;
}
public void setLivro(Livro livro) {
this.livro = livro;
}
}
Você precisa ser coerente com o que está fazendo.
Veja que em teu applicationContext.xml você coloca:
<bean id="livroDAO" class="br.com.meuprojeto.dao.LivroDAO"/>
<bean class="br.com.meuprojeto.bo.LivroBOImpl" id="livroBO">
<property name="dao" ref="livroDAO" />
</bean>
Porém, não existe o mapeamento do teu ManagedBean. Sem isto, não funciona. Você não pode fazer, no ManagedBean:
LivroBO lb = new LivroBO();
Isto irá instanciar o objeto lb, mas não será o objeto que está sendo gerenciado pelo Spring.
Não existe mapeamento do meu ManagedBean ? Mas eu configurei isso no meu faces-config.xml, lá eu mapei todo meu managedBean.
Tirando isto
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<application>
<el-resolver> org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
</faces-config>
Qualquer outra coisa é desnecessária no faces-config.xml. Afinal, você está dizendo que quem irá gerenciar os beans é o Spring. Logo, esse mapeamento de ManagedBean aqui é tão inútil quanto não mapeá-lo.
Você precisa dizer ao Spring que o ManagedBean é um bean que ele deve criar.
Então, no meu faces-config.xml só deve ter a chamada para o EL do Spring, assim digo a aplicação quem irá ser o principal “resolvedor” de EL.
No meu applicationContext.xml faço as injeções de dependência, inclusive a criação dos meus ManagedBean que serão utilizados no meu *.XHTML.
Achei estranho isso, pois neste tutorial (http://www.mkyong.com/jsf2/jsf-2-0-spring-integration-example/) ele ensina exatamente a utilizar o mapeamento do faces-config.xml e também no applicationContext.xml