View parameters in different beans
I've got a page called trip.xhtml
where I take parameters out of the URL using the following code:
<f:metadata>
<f:viewParam name="tripid" value="#{tripBean.tripId}" />
<f:viewParam name="seats" value="#{tripBean.seats}" />
<f:event type="preRenderView" listener="#{tripBean.processParams}" />
</f:metadata>
The TripBean
looks like this (simplified):
@ManagedBean
@RequestScoped
public class TripBean implements Serializable {
private static final long serialVersionUID = -4885781058258859229L;
private Long tripId;
private int seats;
// Getters and setters for tripId and seats
On the bottom of the trip.xhtml
page I have a h:link
:
<h:link outcome="/customer/booking.xhtml" value="Book this trip"
includeViewParams="true" />
What I expect is that the URL I get when I click this link is something like "/customer/booking.jsf?tripid=2&seats=1"
. This is only the case when I put the following code on my booking.xhtml
page:
<f:metadata>
<f:viewParam name="tripid" value="#{tripBean.tripId}" />
<f:viewParam name="seats" value="#{tripBean.seats}" />
</f:metadata>
Although what I actually want is to use another bean. Changing the code to:
<f:metadata>
<f:viewParam name="tripid"开发者_运维技巧 value="#{bookingBean.tripId}" />
<f:viewParam name="seats" value="#{bookingBean.seats}" />
</f:metadata>
The BookingBean
also has 2 properties tripId
and seats
which are identical to the TripBean
, but when I try to click the link now, I only see a seats-parameter which is set to 0. ("/customer/booking.jsf?seats=0"
)
Does anyone have any idea why I can't seem to pass the viewparams to the other page when I'm trying to use another bean to store them in? And IF it is impossible to store it in another bean, how can I put those values from TripBean
in BookingBean
?
Quick work-around I used:
Not using includeViewParams="true"
, but adding parameters to the link manually (see below) "fixes" the problem. Although I'm still wondering why it won't work with includeViewParams
!
<h:link outcome="/customer/booking.xhtml" value="#{msg['page.trip.booking']}">
<f:param name="tripid" value="#{tripBean.tripId}" />
<f:param name="seats" value="#{tripBean.seats}" />
</h:link>
f:viewParam
works exactly like h:inputText
. This means that it uses the same expression as a source (when rendering) and as a target (when updating the model). If you had:
<h:inputText value="#{a.test}" />
You would never ask "how to make the inputText
read from b.foo
and write to a.test
", yet everyone seems to expect such behavior from f:viewParam
.
Anyway, there is a simple answer. To append any values to link, you just need to use f:param
:
<h:link outcome="/customer/booking.xhtml" value="Book this trip" >
<f:param name="tripid" value="#{bookingBean.tripId}" />
<f:param name="seats" value="#{bookingBean.seats}" />
</h:link>
The link content corresponding to the following tag:
<h:link outcome="/customer/booking.xhtml" value="Book this trip"
includeViewParams="true" />
is generated during the render-response phase of the request for the trip.xhtml
view. If you need the URL to contain the view parameter values, then you must provide these values in the URL used to access the view, or you must set these values in the model, before the render-response phase is complete. If you do not perform either of these, the generated hyperlink will contain the default values for the view parameters.
In simpler words, you must:
- either ensure that the
trip.xhtml
view is accessed with the necessary parameters:trip.xhtml?tripid=x&seats=y
, especially if the view is to be accessed with parameters at all times. - or you must set the values in a method that gets executed before the link is rendered by the JSF runtime. The constructor of the
BookingBean
class or a@PostConstruct
annotated method in the class would be ideal places to set the values. You could also reset/update the values of the bean in other methods of your managed bean, in the event of actions being performed in the view. Note, that JSF runtime will invokegetTripId
andgetSeats
to include the values of the view parameterstripId
andseats
in the resulting URL, so you ought to verify the behavior of these methods as well.
Your question on why you are unable to specify bookingBean
in the EL expression for booking.xhtml
, instead requiring you to specify the supposedly unexpected value of tripBean
is due to the fact that the includeViewParams
attribute of the link
tag, will include the parameters of the to-view
and not the from-view
. Simply put, the JSF runtime will invoke bookingBean.getTripId()
and bookingBean.getSeats()
and not tripBean.getTripId()
and tripBean.getSeats()
.
While this might seem counter-intuitive, you ought to understand that the JSF specification treats this scenario quite differently. In most interactions performed by a user, the action URL of a component is generated when the user performs the action and not until then. The link
tag on the other hand, requires preemptive computation of the URL, and hence the JSF runtime treats this quite differently as "pre-emptive navigation". When the URL is being constructed, the objects pertaining to the view parameters of the target view must be accessible, in order for the URL to be meaningful. The reason for the values being 0 in the URL, is that a new BookingBean
instance is created during this evaluation and the default values are being used instead. You can quite obviously avoid this by using the TripBean
instead (and most examples of includeViewParams demonstrate this), or you can set values during the construction of the BookingBean
object.
精彩评论