JSF Request Scope und createValueBinding()

Status
Nicht offen für weitere Antworten.

luc4

Neues Mitglied
Hallo zusammen,

Ich beschäftige mich seit kurzem mit Java Server Faces und bin gerade dabei meine ersten praktischen Gehversuche mit mit Apache Myfaces-1.1.6 und Facelets-1.1.4 zu machen.

Ich habe ein einfaches Master/Detail Szenario umgesetzt (User Liste -> Detailansicht eines Users).
Was soweit auch wunderbar funktioniert, und genau das ist es was mich gerade etwas stutzig macht. 😉

Ansatz:
Ich verwende zwei Managed Beans (UserMasterHandler, UserDetailHandler). Der UserMasterHandler enthält ein ListDataModel um eine List<User> in einem <h:datatable> darzustellen. Die einzelnen Einträge der Tabelle werden als <h:commandlink> dargestellt. Der commandlink verweisst auf eine action Methode (UserMasterHandler.showDetail()), die über createValueBinding() den aktuell gewählten User an die DetailUserBean bindet und als Rückgabewert einen String liefert, der auf die Detailansicht Seite "weiterleitet" (Navigationsregel in der faces-config.xml).

Ich habe diesen Ansatz teilweise aus einem Buch und habe ihn etwas abgewandelt (Unter anderem den Scope der Beans auf Request gesetzt). Was mich etwas wundert ist der Punkt, dass soweit ich das verstanden habe, Beans, die von JSF "gemanaged" werden bei einem ersten Zugriff initialisiert werden. In meinem Fall würde der UserDetailHandler durch createValueBinging von UserMasterBean.showDetail() zum ersten mal initialisiert werden. Da die Bean allerdings im Request Scope "lebt" müsste sie doch eigentlich neu initialisiert werden, sobald im nächsten Request (weiterleiten auf userDetail.xhtml) wieder auf sie zugegriffen wird. Das heißt eigentlich dürfte der gebundene User nicht mehr in der Bean existieren, da es sich ja um einen neuen Request und somit eine neue Instanz von UserDetailHandler handelt, oder? Oder befinde ich mich beim Aufruf von UserMasterHandler.showDetail() schon im Request für die Detailansicht?


Über Tipps, wie man solche Master/Detail Szenarien mit JSF elegant umsetzten kann wäre ich ebenfalls dankbar.

Gruß Luca


UserMasterHandler.java
Code:
public class UserMasterHandler
{
	
	private DataModel users = new ListDataModel();

	public UserMasterHandler()
	{
		List<User> userList = new ArrayList<User>();
		userList.add(new User("sebie"));
		userList.add(new User("peter"));
		userList.add(new User("max"));
		
		users.setWrappedData(userList);	
	}

       //geter & seter
	
	public String showDetail()
	{
		User usr = (User)users.getRowData();
		FacesContext fc = FacesContext.getCurrentInstance();
		fc.getApplication().createValueBinding("#{userDetailHandler.user}").setValue(fc, usr);
		return "showDetail";
	}

UserDetailHandler.java:
Code:
public class UserDetailHandler
{
	private User user;
	
	public UserDetailHandler()  { }

       //geter & seter
}

userOverview.xhtml:
Code:
<ui:composition template="/pages/layout/main.xhtml">
	<ui:define name="title">
		User Overview
	</ui:define>
	
	<ui:define name="content">
	<h:form>
		<h:dataTable value="#{userMasterHandler.users}" var="userItem" style="border:1px solid #000000">
			<h:column>
				<f:facet name="header">User Name:</f:facet>
				<h:commandLink action="#{userMasterHandler.showDetail}" value="#{userItem.name}"/>

			</h:column>
		</h:dataTable>
	</h:form>
	</ui:define>
</ui:composition>

userDetail.xhtml:
Code:
<ui:composition template="/pages/layout/main.xhtml">
	<ui:define name="title">
	</ui:define>

	<ui:define name="content">
		<h:outputText value="#{userDetailHandler.user.name}"/>

		

		<h:form>
			<h:commandButton action="#{userDetailHandler.back}" value="Back"/>
		</h:form>
	</ui:define>
</ui:composition>

faces-config.xml
Code:
<faces-config>
	<application>
		<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>    
	</application> 
	
	<navigation-rule>
        <from-view-id>/pages/userMaster.xhtml</from-view-id>
        <navigation-case>
            <from-outcome>showDetail</from-outcome>
            <to-view-id>/pages/userDetail.xhtml</to-view-id>
        </navigation-case>
	</navigation-rule>
	
	<navigation-rule>
        <from-view-id>/pages/userDetail.xhtml</from-view-id>
        <navigation-case>
            <from-outcome>back</from-outcome>
            <to-view-id>/pages/userMaster.xhtml</to-view-id>
        </navigation-case>
	</navigation-rule>

	<managed-bean>
		<managed-bean-name>userMasterHandler</managed-bean-name>
		<managed-bean-class>jsf.handler.UserMasterHandler</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
	</managed-bean>
	
	<managed-bean>
		<managed-bean-name>userDetailHandler</managed-bean-name>
		<managed-bean-class>jsf.handler.UserDetailHandler</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
	</managed-bean>
	
</faces-config>
 
Es ist einiger Monate her, als ich zuletzt mit JSF gearbeitet hatte. Soweit ich mich erinnern kann, ist genau das von dir befürchtete Phänomen aufgetreten: Beim Request-Scope befand sich die Bean zwei Mal im Speicher. Einmal durch das createValueBinding() erzeugt und ein zweites Mal beim Zugriff durch die eine Komponente der folgenden Page. Ich meine jedenfalls, dieses Verhalten im Debugger beobachtet zu haben.

Unter dem folgendem Link werden aber einige Möglichkeiten beschrieben, Daten von Request zu Request zu übertragen und auch weitere sehr hilfreiche Tipps bzgl. JSF-Kommunikation.

balusc.blogspot.com/2006/06/communication-in-jsf.html#PassingObjectsFromRequestToRequest

Titus
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben