JSF中的f:event preRenderView在模板f:metadata中,listener没有在每个页面访问时被调用。

3

根据Netbeans7.1附带的Glassfish3.1.1,Mojarra-2.1.3可用。

我有一个@SessionScoped后备bean Tracker,其中包含一个监听器void reset()。

以下内容在所有使用template.xhtml的XHTML页面的f:metadata中正常工作,例如/block/view.xhtml,该页面还接受查询参数id:

<f:view>
    <f:metadata>
        <f:viewParam name="id" value="#{blockManager.id}"/>
        <f:event type="preRenderView" listener="#{tracker.reset}"/>            
    </f:metadata>
</f:view>

<ui:composition template="/template.xhtml">

如预期,每当我加载(GET)或重新加载页面时,无论id查询参数是什么,#{tracker.reset}监听器都会被调用(通过调试日志揭示)。
然而,必须在每个XHTML页面中包含f:event很麻烦(我有数百个页面),我首先尝试将其放在template.xhtml的f:metadata中。但是当我这样做时,出现了奇怪的情况。它只在第一次加载/block/view.xhtml时调用#{tracker.reset}(无论id查询参数是什么),之后直到我加载具有不同viewId的另一个页面(例如/actor/view.xhtml、/block/list.xhtml或/index.html)才再次调用。
我在template.xhtml中使用#{facesContext.viewRoot.viewId}检查了viewId。从viewId的角度来看,id查询参数对于区分使用不同id查询参数调用的不同block/view.xhtml?id=[id]页面并没有起到任何作用,viewId始终只是'/block/view.xhtml'。
在撰写本stackoverflow帖子期间,我发现了解决我的问题的方法:只需将f:event放在template.xhtml的f:metadata之外即可(我在template.xhtml中使用f:metadata进行f:event的分组)。这在template.xhtml中有效。
<f:metadata>
..
</f:metadata>
<f:event type="preRenderView" listener="#{tracker.reset}"/>
<h:head>

但我仍有以下问题:

问:在模板中是否将f:event放置在f:metadata内部是否有区别?

我提出这个问题的原因是,在Stackoverflow上有很多例子,既有在template.xhtml中使用f:metadata的例子,也有在模板中使用f:metadata内的f:event的例子。

BalusC在When to use f:viewAction / preRenderView versus PostConstruct?中指出:

preRenderView事件在每个HTTP请求上被调用。

只有当我在最终的XHTML页面的f:metadata中或者在模板的f:metadata之外拥有preRenderView f:event时,它才似乎是真实存在的(按预期工作), 但是如果它位于模板的f:metadata内部,则不起作用。

关于是否应该在模板的f:metadata中具有f:event,或者根本不使用模板的f:metadata,存在一些争议。

JSF2 Complete Reference (Burns and Schalk) p.540指出:

标签封装了一组元素,用于指定Facelets视图的元数据,因此必须是f:view标签的子元素,不能出现在模板中。从JSF2.0开始,此标签的唯一目的是封装f:viewParam标签。但是,在Stackoverflow上有很多f:metadata在模板内使用的示例,也有很多f:event在f:metadata内使用的示例。这里也讨论了这个问题:是否将f:event放置在f:metadata内很重要? BalusC在这里给出了有益的解释:“..<f:event>不一定非要放在<f:metadata>内。它可以附加到任何组件上。..当您有一堆<f:viewParam>并想要挂钩一个<f:event>在所有这些视图参数设置后调用操作时,它确实为纯自我文档目的放置在<f:metadata>内。..”
但是我的经验表明,将f:event放置在模板的f:metadata中会产生略微不同(奇怪)的行为。为什么?
1个回答

10

<f:metadata> 只能在模板客户端中使用,而不能在主模板中使用。也就是说,它必须声明在实际通过URL请求的页面上,而不是在<ui:composition template>后面的页面中,否则它会被忽略。这个特定的限制与<f:event>无关。

另请参阅:


1
感谢您的回复,我已经完全从我的模板中删除了f:metadata,只留下f:event项在h:head之前,现在它们可以正常工作了。如果一个人错误地将f:event放置在模板中不允许的f:metadata中(这是我的原始问题,但现在不再相关,因为这是对f:metadata的病态使用),那么奇怪的行为发生也无关紧要了,所以我会将其视为完全回答。 - Webel IT Australia - upvoter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接