我需要在另一个视图范围的bean中使用保存在视图范围bean中的一些数据。
@ManagedBean
@ViewScoped
public class Attivita implements Serializable {
//
}
和
@ManagedBean
@ViewScoped
public class Nota implements Serializable {
@ManagedProperty("#{attivita}")
private Attivita attivita;
// Getter and setter.
}
现在,也许我关于它的理论仍然很差,我注意到当注入#{attivita}
时,会调用Attivita
构造函数,从而创建另一个实例。这是正确的行为吗?如果我想引用同一个实例而不是创建一个新实例呢?
答案 0 :(得分:13)
如果您在回发中从一个视图导航到另一个视图,则会发生这种情况。视图范围bean不依赖于请求,而是绑定到视图。因此,当您导航到新视图时,它将获得视图范围bean的全新实例。它不会重用与先前视图关联的相同bean实例。
我知道attivita
bean是在初始视图上创建的,并在回发时重用。我知道nota
bean与您导航到的新视图相关联。在其中注入attivita
时,即使在同一个请求中有另一个实例,它也只会获得一个新的独特实例。这是所有预期的(并且无可否认地有点不直观)行为。
没有标准的JSF解决方案。 CDI用@ConversationScoped
来解决这个问题(只要你明确告诉它存在,bean就存在),CDI扩展MyFaces CODI与@ViewAccessScoped
相比更进一步(只要导航视图引用,bean就会存在)它)。
但是,您可以通过将bean存储为请求范围中的属性来解决此问题。
@ManagedBean
@ViewScoped
public class Attivita implements Serializable {
public String submit() {
FacesContext.getCurrentInstance().getExternalContext()
.getRequestMap().put("attivita", this);
return "nota";
}
}
和
@ManagedBean
@ViewScoped
public class Nota implements Serializable {
private Attivita attivita;
@PostConstruct
public void init() {
attivita = (Attivita) FacesContext.getCurrentInstance().getExternalContext()
.getRequestMap().get("attivita");
}
}
请注意,这是相当hacky。根据具体的功能要求,可能有更好的解决方案。另请注意,您应该在nota
视图中将所需的Attivita
bean实例引用为#{nota.attivita}
而将不引用为#{attivita}
,因为它会为您提供由于之前已经解释过的原因,一个新的和不同的实例。
答案 1 :(得分:1)
您的attivita
bean是@ViewScoped
,并不保证您的实例将在会话中保留。你需要一个@SessionScoped
bean。但是,如果由于某种原因attivita
需要@ViewScoped
,那么您可以通过其他方式传递参数,例如使用viewParam
或在它们之间使用其他@SessionScoped
bean。
Page Params
http://mkblog.exadel.com/2010/07/learning-jsf2-page-params-and-page-actions/
JSF 2托管Bean范围
http://balusc.blogspot.com.es/2011/09/communication-in-jsf-20.html#ManagedBeanScopes