[RESOLVIDO] Como manter o estado de um managedBean entre duas páginas com JSF 2?

Pessoal, comecei agora a ver JSF 2, sempre trabalhei com o 1 e me deparei com um problema que já pesquisei e não consegui resolver ainda. Como faço pra manter o estado de um bean, ou seja manter a instância de uma managedBean entre duas páginas que usam o mesmo managedBean? No 1, usando rich usando richfaces bastava um a4j:keepAlive que já resolvia. Agora não estamos mais usando o richfaces e sim o primefaces, então como posso fazer isso? Tenho uma página e quero ir para outra página que usa o mesmo managedBean e manter a instância desse MB. O jsf está criando uma nova instância.

Já dei uma olhada nos escopos do JSF 2 e vi que tem um @ViewScoped mas ele só faz o trabalho do keepAlive em parte pois só funciona para a mesma página pois se mudar de página uma nova instância é criada. Preciso manter a mesma enquanto o managedBean estiver sendo usado.

Obrigado!

Na verdade o @ViewScoped funciona quando você utiliza CDI, se você utilizar ManagedBean normal mesmo ele não funciona.

O que você pode fazer é:

  1. Colocar seu MB como SessionBean
  2. Carregá-lo sempre de um para o outro e manter o MB como request. Por exemplo você tem o objeto Arvore na tela A. No managedBean você teria um get/set. E vai para tela B. Nessa tela B vc coloca todos os campos lá e get/set no novo mangedBean. E assim vai. [=

[quote=jakefrog]Na verdade o @ViewScoped funciona quando você utiliza CDI, se você utilizar ManagedBean normal mesmo ele não funciona.

O que você pode fazer é:

  1. Colocar seu MB como SessionBean
  2. Carregá-lo sempre de um para o outro e manter o MB como request. Por exemplo você tem o objeto Arvore na tela A. No managedBean você teria um get/set. E vai para tela B. Nessa tela B vc coloca todos os campos lá e get/set no novo mangedBean. E assim vai. [=[/quote]

Obrigado pela resposta, cara colocar como session resolve mas não é o que eu quero. Isso vai fazer com que o bean esteja vivo sempre na sessão mesmo quando este não estiver sendo usado. Sem contar que será uma instância para cada sessão de usuário. Esse não é o comportamento que eu gostaria.

A sua segunda alternativa pelo que entendi foi o que pensei em fazer também, mas acredito que deve haver uma forma mais simples e prática de fazer isso. Se não tiver como fazer de uma forma simples no JSF 2 é uma pena, pois eles poderiam ter colocado um scopo desse, tipo conversation entre as paginas enquanto o bean estiver sendo usado, quando for pra uma pagina que não use esse bean então descarta essa instância.

Se não tiver, vou parar em breve e estudar uma forma de implementar algo que faça e seja algo simples de ser usado ai vou publicar como um simples jar para quem quiser usar. Penso algo como um novo scopo tipo @blablabla que vc vai colocar no seu bean e ele vai funcionar assim. Se realmente nao tiver, vou estudar bem como funciona o JSF 2, seus pontos de extensão e eu vou fazer isso.

Existir existe, que é o @ViewScope. Mas você terá que utilizar por CDI (que é a nova “vibe” do JSF). [=

Pode fazer uma conversação.

[code]import java.io.Serializable;

import javax.annotation.ManagedBean;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;

@ManagedBean
@ConversationScoped
public class UsuarioBean implements Serializable {
@Inject
private Conversation conversation;

public String begin() {
    this.conversation.begin();
    return "pagina-de-inicio-da-conversacao";
}

public String end() {
    this.conversation.end();
    return "pagina-final-da-conversacao";
}

}[/code]

[quote=lsjunior]Pode fazer uma conversação.

[code]import java.io.Serializable;

import javax.annotation.ManagedBean;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;

@ManagedBean
@ConversationScoped
public class UsuarioBean implements Serializable {
@Inject
private Conversation conversation;

public String begin() {
    this.conversation.begin();
    return "pagina-de-inicio-da-conversacao";
}

public String end() {
    this.conversation.end();
    return "pagina-final-da-conversacao";
}

}[/code][/quote]

Obrigado pela dica cara, mas testei aqui da forma como você falou e não funciona. Ele simplesmente quando eu mudo de página cria uma nova instância do managedBean então eu perco o estado do bean. Só pra contar, estou usando CDI.

Amigos, aproveitando o gancho do tópico, o ViewScoped não é apenas para persistir o bean na mesma pagina? Achava que ele mantinha o estado ENQUANTO as requests feitas fossem para a mesma página…não é isso?

Ao colega lindberg713, o Seam tem o escopo Conversation, que faz isso que voce quer. Pode ser uma opção.

[quote=alias]Amigos, aproveitando o gancho do tópico, o ViewScoped não é apenas para persistir o bean na mesma pagina? Achava que ele mantinha o estado ENQUANTO as requests feitas fossem para a mesma página…não é isso?

Ao colega lindberg713, o Seam tem o escopo Conversation, que faz isso que voce quer. Pode ser uma opção.[/quote]

Eu conheço o Seam mas o nosso projeto aqui não usa. Estou lendo a documentação aqui do CODI. Que é a extensão do apache myfaces do CDI e que tem um escopo ViewAccessScoped que faz exatamente isso que quero. Se eu conseguir resolver usando isto eu posto aqui.

Fiz um projeto bem simples com 3 xhtml e um bean, vê se é mais ou menos isso que vc quer.

O anexo é um projeto Eclipse Web, testei no JBoss AS 7.0.2.

[quote=lsjunior]Fiz um projeto bem simples com 3 xhtml e um bean, vê se é mais ou menos isso que vc quer.

O anexo é um projeto Eclipse Web, testei no JBoss AS 7.0.2.[/quote]

Vou testar, obrigado!

Resolvido.

Adicionei o apache myfaces CODI (http://myfaces.apache.org/extensions/cdi/) que é uma extensão do CDI e que adiciona novos escopos de beans. O CODI provê dentro vários recursos e escopos de beans o escopo @ViewAccesScoped que é exatamente o que preciso. Enquanto o usuário estiver em uma página que use o managedBean o estade deste bean é mantido.

Para maven basta adicionar as dependencias abaixo (caso esteja usando JSF 2):

org.apache.myfaces.extensions.cdi.modules myfaces-extcdi-jsf20-module-api 1.0.1 compile
	<dependency>
		<groupId>org.apache.myfaces.extensions.cdi.modules</groupId>
		<artifactId>myfaces-extcdi-jsf20-module-impl</artifactId>
		<version>1.0.1</version>
		<scope>runtime</scope>
	</dependency>
	
	<dependency>
		<groupId>org.apache.myfaces.extensions.cdi.core</groupId>
		<artifactId>myfaces-extcdi-core-api</artifactId>
		<version>1.0.1</version>
		<scope>compile</scope>
	</dependency>

	<dependency>
		<groupId>org.apache.myfaces.extensions.cdi.core</groupId>
		<artifactId>myfaces-extcdi-core-impl</artifactId>
		<version>1.0.1</version>
		<scope>runtime</scope>
	</dependency>

Sensacional essa feature cara, muito bom, mas nao entendi o funcionamento, voce diz que enquanto o managed bean for usado na pagina X o estado será mantido, e quando o usuario for pra pagina Y, que era o que voce queria? O mesmo estado é mantido? Ele usa a sessão pra fazer isso?

O funcionamento é o seguinte. Enquanto o usuário estiver navegando em alguma pagina que uso aquele bean ele mantem o estado. Por exemplo, o usuário ta na pagina A que usa o bean X. Entao muda pra pagina B que também usa o bean X. Então de A para B o estado do bean X é mantido. Da mesma forma, se ele for de B para C e C tb usar o bean X o estado continua. Agora se por exemplo ele for para pagina D e esta não faz qualquer referencia ao bean X, então é estado do bean é destruido.

Como ele faz eu não sei pois não me aprofundei na implementação deste recurso, mas dei uma olhada na documentação e é muito boa.

[quote=lindberg713]O funcionamento é o seguinte. Enquanto o usuário estiver navegando em alguma pagina que uso aquele bean ele mantem o estado. Por exemplo, o usuário ta na pagina A que usa o bean X. Entao muda pra pagina B que também usa o bean X. Então de A para B o estado do bean X é mantido. Da mesma forma, se ele for de B para C e C tb usar o bean X o estado continua. Agora se por exemplo ele for para pagina D e esta não faz qualquer referencia ao bean X, então é estado do bean é destruido.

Como ele faz eu não sei pois não me aprofundei na implementação deste recurso, mas dei uma olhada na documentação e é muito boa.[/quote]

Entendi, legal…mas suponho que ele use a sessão para armazenar isso, ao menos nao vejo outra forma de fazer. De qualquer forma, deveras útil.

olá lindberg bom dia,
quanto ao Apache CODI vc só baixou os jars pelo mavem e adiciou-los no classpath ou tem que fazer alguma configuração a mais tipo no web.xml ou outro arquivo?é só baixar e usare?
tipo não gosto do maven quero baixar manualmente ,quais são os jars necessários??

aguardando a resposta!
vlw ! obrigado!

[quote=rjpereira1000000]olá lindberg bom dia,
quanto ao Apache CODI vc só baixou os jars pelo mavem e adiciou-los no classpath ou tem que fazer alguma configuração a mais tipo no web.xml ou outro arquivo?é só baixar e usare?
tipo não gosto do maven quero baixar manualmente ,quais são os jars necessários??

aguardando a resposta!
vlw ! obrigado![/quote]

Bom dia cara, eu só declarei no meu pom.xml do meu maven e pronto. Ele já sobe junto com a aplicação. Dei uma olhada rapida aqui pra ver se precisei fazer mais alguma coisa e nao me recordei de nada a mais. Caso não funcione fala ai. Como uso o maven, ele ja baixa as dependencias necessárias então não preciso me preocupar. Neste caso como nao vai usar, empacotei os jars do myfaces-codi que vao dentro do meu war a partir do maven. Então se falatar alguma dependencia fala ai tb, mas acredito que ta tudo ai pois dei uma olhada na hierarquia de dependencias do maven para o codi e só tem isso que to te mandando. Coloquei os jars num .zip no link abaixo. Baixa ai rapido que mais tarde vou remover desse link. Abraço.

www.lindbergframework.org/diversos/codi.zip

[quote=lindberg713][quote=rjpereira1000000]olá lindberg bom dia,
quanto ao Apache CODI vc só baixou os jars pelo mavem e adiciou-los no classpath ou tem que fazer alguma configuração a mais tipo no web.xml ou outro arquivo?é só baixar e usare?
tipo não gosto do maven quero baixar manualmente ,quais são os jars necessários??

aguardando a resposta!
vlw ! obrigado![/quote]

Bom dia cara, eu só declarei no meu pom.xml do meu maven e pronto. Ele já sobe junto com a aplicação. Dei uma olhada rapida aqui pra ver se precisei fazer mais alguma coisa e nao me recordei de nada a mais. Caso não funcione fala ai. Como uso o maven, ele ja baixa as dependencias necessárias então não preciso me preocupar. Neste caso como nao vai usar, empacotei os jars do myfaces-codi que vao dentro do meu war a partir do maven. Então se falatar alguma dependencia fala ai tb, mas acredito que ta tudo ai pois dei uma olhada na hierarquia de dependencias do maven para o codi e só tem isso que to te mandando. Coloquei os jars num .zip no link abaixo. Baixa ai rapido que mais tarde vou remover desse link. Abraço.

www.lindbergframework.org/diversos/codi.zip[/quote]

Fiz melhor, coloquei no 4shared.com no link abaixo, ai fica disponível sempre pra todo mundo que precisar.

http://www.4shared.com/file/yKurRw7B/apache-myfaces-codi.html?

obrigado por compartilhar,obrigado mesmo!!

Olá pessoal, estou com o mesmo problema no meu projeto, estou utilizando o JSF 2 + Primefaces 3 + Spring + Tomcat. Na versão antiga eu resolvia esse problema utilizando o KeepAlive mas nesse nova versão eu não tenho essa possibilidade, desta forma, lendo o post do lindberg71, resolvi adicionar ao meu projeto o apache CODI para poder utilizar o ViewAccessScoped e adicionei os jars disponibilizados pelo lindberg71, entretanto, ao levantar minha aplicação está dando um erro:

com.sun.faces.config.ConfigurationException: Factory ‘javax.faces.context.FacesContextFactory’ was not configured properly.
at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:292)
at com.sun.faces.config.processor.FactoryConfigProcessor.process(FactoryConfigProcessor.java:209)
at com.sun.faces.config.ConfigManager.initialize(ConfigManager.java:332)
at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:220)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4723)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5226)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5221)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: javax.faces.FacesException: org.apache.myfaces.extensions.cdi.jsf2.impl.listener.request.CodiFacesContextFactory
at javax.faces.FactoryFinder.getImplGivenPreviousImpl(FactoryFinder.java:589)
at javax.faces.FactoryFinder.getImplementationInstance(FactoryFinder.java:468)
at javax.faces.FactoryFinder.access$400(FactoryFinder.java:135)
at javax.faces.FactoryFinder$FactoryManager.getFactory(FactoryFinder.java:792)
at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:302)
at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:290)

Precisa fazer alguma configuração no web.xml ?? O meu está assim:

<?xml version="1.0" encoding="UTF-8"?>
<display-name>cubo</display-name>

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

<context-param>
	<param-name>javax.faces.PROJECT_STAGE</param-name>
	<param-value>Development</param-value>
</context-param>

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

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

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

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:applicationContext.xml</param-value>
</context-param>

<context-param>
	<param-name>primefaces.skin</param-name>
	<param-value>none</param-value>
</context-param>

Olá lindberg713.

Estou com o mesmo problema!

Adicionei os Jars do CDI e configurei meu bean conforme abaixo:

import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.ViewAccessScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@ViewAccessScoped
public class beanMB{
...
}

Na view eu tenho um rich:tabPanel com várias páginas, sendo que, a primeira é a pequisa. O usuário efetua a pesquisa na primeira tab e clica em editar, com isso a segunda e terceira tabs são desbloquedas. Na segunda tab tudo funciona normamente, porém na terceira existe uma opção de um relatório e quando eu clico no botão para imprimir o relatório (em outra janela), o bean é recriado.

Com o KeepAlive funcionava normalmente.

Alguém sabe a causa desse problema?