我有一个名为trip.xhtml
的页面,我使用以下代码从URL中取出参数:
<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>
TripBean
看起来像这样(简化):
@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
在trip.xhtml
页面的底部,我有一个h:link
:
<h:link outcome="/customer/booking.xhtml" value="Book this trip"
includeViewParams="true" />
我期望的是,当我点击这个链接时,我得到的URL是"/customer/booking.jsf?tripid=2&seats=1"
之类的东西。只有当我在booking.xhtml
页面上放置以下代码时才会出现这种情况:
<f:metadata>
<f:viewParam name="tripid" value="#{tripBean.tripId}" />
<f:viewParam name="seats" value="#{tripBean.seats}" />
</f:metadata>
虽然我真正想要的是使用另一个bean。将代码更改为:
<f:metadata>
<f:viewParam name="tripid" value="#{bookingBean.tripId}" />
<f:viewParam name="seats" value="#{bookingBean.seats}" />
</f:metadata>
BookingBean
也有2个属性tripId
和seats
,它们与TripBean
相同,但是当我现在尝试单击链接时,我只看到一个设置为0的座位参数。("/customer/booking.jsf?seats=0"
)
有没有人知道为什么当我试图使用另一个bean来存储它们时,我似乎不能将viewparams传递到另一个页面?如果不可能将其存储在另一个bean中,我如何将TripBean
中的这些值放在BookingBean
中?
我使用的快速解决方法:不使用includeViewParams="true"
,而是手动向链接添加参数(见下文)"修复"了问题。虽然我仍然想知道为什么它不会与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
的工作原理与h:inputText
完全相同。这意味着它使用相同的表达式作为源(在呈现时)和目标(在更新模型时)。如果你有:
<h:inputText value="#{a.test}" />
你永远不会问"如何让inputText
从b.foo
读取并写入a.test
",然而每个人似乎都期望f:viewParam
有这样的行为。
无论如何,有一个简单的答案。要附加任何值到link,您只需要使用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>
与以下标签对应的链接内容:
<h:link outcome="/customer/booking.xhtml" value="Book this trip"
includeViewParams="true" />
是在trip.xhtml
视图请求的呈现-响应阶段生成的。如果您需要URL包含视图参数值,那么您必须在用于访问视图的URL中提供这些值,或者您必须在呈现-响应阶段完成之前在模型中设置这些值。如果不执行其中任何一个,生成的超链接将包含视图参数的默认值。
简单来说,你必须:
- 确保
trip.xhtml
视图使用必要的参数访问:trip.xhtml?tripid=x&seats=y
,特别是如果视图在任何时候都要使用参数访问。 - 或者必须在JSF运行时呈现链接之前执行的方法中设置值。
BookingBean
类的构造函数或类中的@PostConstruct
注释方法是设置这些值的理想场所。在视图中执行操作的情况下,您还可以在托管bean的其他方法中重置/更新bean的值。注意,JSF运行时将调用getTripId
和getSeats
,以在结果URL中包含视图参数tripId
和seats
的值,因此您也应该验证这些方法的行为。
您的问题是为什么您无法在booking.xhtml
的EL表达式中指定bookingBean
,而是要求您指定tripBean
的所谓意外值,这是由于link
标签的includeViewParams
属性将包括to-view
而不是from-view
的参数。简单地说,JSF运行时将调用bookingBean.getTripId()
和bookingBean.getSeats()
,而不是tripBean.getTripId()
和tripBean.getSeats()
。
虽然这看起来可能违反直觉,但是您应该理解JSF规范对这种场景的处理方式是完全不同的。在用户执行的大多数交互中,组件的操作URL是在用户执行操作时生成的,而不是在此之前生成的。另一方面,link
标记需要对URL进行先发制人的计算,因此JSF运行时将其视为"先发制人的导航"。在构造URL时,为了使URL有意义,与目标视图的视图参数相关的对象必须是可访问的。URL中值为0的原因是,在此评估期间创建了一个新的BookingBean
实例,并使用默认值代替。很明显,您可以通过使用TripBean
来避免这种情况(大多数includeViewParams示例都演示了这一点),或者您可以在构建BookingBean
对象期间设置值。