7

我需要在另一个视图范围 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构造函数被调用并因此创建另一个实例。这是正确的行为吗?如果我想引用同一个实例而不创建一个新实例怎么办?

4

2 回答 2

14

如果您在回发中从一个视图导航到另一个视图,就会发生这种情况。视图范围的 bean 不绑定到请求,而是绑定到视图。因此,当您导航到新视图时,它将获得视图范围 bean 的全新实例。它不会重用与前一个视图关联的同一个 bean 实例。

我知道attivitabean 是在初始视图上创建的,并在回发时重用。我知道notabean 与您要导航到的新视图相关联。当注入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视图中引用所需的Attivitabean 实例 as#{nota.attivita}不是as #{attivita},因为它会给您一个新的和不同的实例,原因之前已经解释过。

于 2013-01-09T12:10:35.220 回答
1

您的attivitabean 是@ViewScoped并且不能保证您的实例将保持在会话中。你需要一颗@SessionScoped豆子。但是,如果您attivita出于某种原因需要 be @ViewScoped,那么您可以通过其他方式传递参数,例如在它们之间使用viewParam或使用其他@SessionScopedbean。

页面参数

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

于 2013-01-09T10:39:09.580 回答