2013-01-09 7 views
7

Ich muss einige Daten verwenden, die in einer View-Scoped-Bean in einer anderen View-Scoped-Bean gespeichert sind.In einer anderen Ansicht wird die Bean in einer anderen Ansicht eingefügt. Die Bean im Zielbereich verursacht die Neuerstellung.

@ManagedBean 
@ViewScoped 
public class Attivita implements Serializable { 
    // 
} 

und

@ManagedBean 
@ViewScoped 
public class Nota implements Serializable { 

    @ManagedProperty("#{attivita}") 
    private Attivita attivita; 

    // Getter and setter. 
} 

Nun, vielleicht darüber meine Theorie ist immer noch ziemlich schlecht, ich habe bemerkt, dass, wenn #{attivita} injiziert wird, der Attivita Konstruktor aufgerufen wird und somit eine andere Instanz zu schaffen. Ist es das richtige Verhalten? Wie wäre es, wenn ich dieselbe Instanz referenzieren und keine neue erstellen möchte?

+0

Achten Sie darauf, die richtigen Antworten zu markieren.Beim Stack Overflow geht es nicht nur um Fragen, sondern auch um Antworten. –

Antwort

13

Dies wird geschehen, wenn Sie auf einem Postbacks von einem zum anderen Ansicht Navigation . Eine View-Scoped-Bean ist nicht an eine Anfrage, sondern an eine Ansicht gebunden. Wenn Sie also zu einer neuen Ansicht navigieren, wird eine brandneue Instanz der View-Scoped-Bean angezeigt. Es wird nicht dieselbe Bean-Instanz wiederverwenden, die einer vorherigen Ansicht zugeordnet ist.

Ich verstehe, dass die attivita Bean in der ersten Ansicht erstellt und auf Postback wiederverwendet wird. Ich verstehe, dass nota Bean mit der neuen Ansicht verknüpft ist, zu der Sie navigieren. Wenn Sie darin attivita injizieren, erhält es einfach eine neue und unterschiedliche Instanz, obwohl es in derselben Anfrage noch eine weitere Instanz gibt. Dies ist alles erwartet (und zugegebenermaßen ein wenig unintuitives) Verhalten.

Es gibt keine Standard-JSF-Lösung dafür. CDI löst das mit @ConversationScoped (die Bohne lebt so lange, wie Sie es ausdrücklich sagen zu leben) und die CDI-Erweiterung MyFaces CODI geht ein bisschen weiter mit @ViewAccessScoped (die Bohne lebt, solange die navigierte Ansicht darauf verweist).

Sie können dies jedoch umgehen, indem Sie die Bean als Attribut im Anforderungsbereich speichern.

@ManagedBean 
@ViewScoped 
public class Attivita implements Serializable { 

    public String submit() { 
     FacesContext.getCurrentInstance().getExternalContext() 
      .getRequestMap().put("attivita", this); 
     return "nota"; 
    } 

} 

und

@ManagedBean 
@ViewScoped 
public class Nota implements Serializable { 

    private Attivita attivita; 

    @PostConstruct 
    public void init() { 
     attivita = (Attivita) FacesContext.getCurrentInstance().getExternalContext() 
      .getRequestMap().get("attivita"); 
    } 

} 

Beachten Sie, dass dies eher Hacky ist. Abhängig von der konkreten funktionalen Anforderung kann es bessere Lösungen geben. Beachten Sie auch, dass Sie in der nota Ansicht die gewünschte Attivita Bean-Instanz als #{nota.attivita} und nicht als #{attivita} referenzieren sollten, weil es Ihnen aus den bereits zuvor erläuterten Gründen eine neue und andere Instanz geben würde.

+0

Das funktioniert sicher - ich hatte das gleiche Problem. Es ist jedoch sehr hacky, wie Sie gesagt haben, und ist noch ein weiteres großes Manko von JSF. Es beseitigt den Zweck von CDI oder verwalteten Eigenschaften, wenn Sie ein PostConstruct hinzufügen müssen und manuell eine Bean aus dem Faces Context ziehen müssen. Ist geplant, dass @ViewAccessScoped der Standard-JSF-API hinzugefügt wird und nicht nur als Teil von MyFaces? – GreenieMeanie

+0

@GreenieMeanie: JSF 2.2 hat '@ FlowScoped' hinzugefügt, um dies zu bedecken, aber leider erfordert es immer noch ein wenig XML-Konfiguration und automatisch generierte Request-Parameter, da es auch GET-Requests überstehen musste. Es ist, sagen wir, zwischen '@ ViewAccessScoped' und' @ SessionScoped'. Als eine wahrscheinliche "bessere Lösung" können Sie daran denken, sie einfach mit der Entitäts-ID als Parameter umzuleiten oder einen Teil der gleichen Ansicht mit einem anderen Include bedingt zu rendern. Siehe auch a.o. http://stackoverflow.com/questions/15521451/how-to-navigate-in-jsf-how-to-make-url-reflect-current-page-and-not-previous-o – BalusC

+0

Sie schlagen vor, Ansicht zu haben a.xhtml habe einen "dummy" include in b.xhtml und wickle vielleicht den gesamten Inhalt von b.xhtml in ein riesiges ui: fragment, das nur etwas rendert wenn es umgeleitet wird (via b.xhtml) und NICHT wenn es ist als Dummy-Referenz von a.xhtml enthalten? – GreenieMeanie

1

Ihre attivita Bean ist @ViewScoped und das garantiert nicht, dass Ihre Instanz in Sitzung gehalten wird. Sie benötigen eine @SessionScoped Bean. Wenn Sie jedoch attivita aus irgendeinem Grund @ViewScoped benötigen, können Sie Params auf andere Arten durch sie passieren, z. unter Verwendung viewParam oder unter Verwendung anderer @SessionScoped Bohne zwischen ihnen.

Seite Param

http://mkblog.exadel.com/2010/07/learning-jsf2-page-params-and-page-actions/

JSF 2 Managed Bean Scopes

http://balusc.blogspot.com.es/2011/09/communication-in-jsf-20.html#ManagedBeanScopes