我对f:event type="preRenderView"
的执行顺序和执行次数有疑问。
在我搜索期间,我发现BalusC常常在this和this帖子中找到与我的问题相关的答案 - 但它仍然为我留下了两个问题:
当我在模板文件中放置一个f:event type="preRenderView"
时(用于管理常见任务,例如关于适用于我所有视图的用户状态的检查)和每个视图中的另一个f:event type="preRenderView"
(用于处理)查看特定的初始化),我想知道为什么视图中的侦听器方法在模板之前被调用。
当我按照建议将<f:metadata><f:event [..] /></f:metadata>
放在ui:define
之后,从登录页面重定向到该页面后会调用两次,但是当我在{{{{}}之后将其放置一级以上时1}}它只被调用一次。
更新:示例
以下示例演示了上述行为:
这是模板文件ui:composition
,包含template_test.xhtml
事件的侦听器,在所有视图的处理程序中调用公共方法:
preRenderView
这是视图文件<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xml:lang="de" lang="de" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<link rel="stylesheet" type="text/css" href="../resources/css/style.css" />
</h:head>
<h:body>
<f:event type="preRenderView" listener="#{testHandler.initCommon()}" />
<div id="content">
<ui:insert name="content" />
</div>
</h:body>
</html>
,还包含调用处理程序中视图特定方法的test.xhtml
事件的侦听器以及通过处理程序方法重定向的命令按钮:
preRenderView
这是包含3种方法的处理程序类<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="template_test.xhtml">
<ui:define name="content">
<f:metadata>
<f:event type="preRenderView"
listener="#{testHandler.initIndividual()}"></f:event>
</f:metadata>
<h:form>
<h:commandButton value="Redirect" action="#{testHandler.redirect()}" />
</h:form>
</ui:define>
</ui:composition>
:
TestHandler.java
现在,这是我在tomcat日志中看到的,在请求测试页面时:
package test;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
@Named
@SessionScoped
public class TestHandler implements Serializable {
private static final long serialVersionUID = -2785693292020668741L;
public void initCommon() {
System.out.println("Common init called.");
}
public void initIndividual() {
System.out.println("Init for individual page called.");
}
public String redirect() {
return "test/test.xhtml?faces-redirect=true";
}
}
这显示没有。 1,视图中的事件处理程序在模板之前调用,而不是。 2,视图中的事件处理程序被调用两次。
它还显示了第3个点(这就是为什么我包含了一个重定向到同一页面的按钮的原因),显示了如果通过重定向请求页面会发生什么 - 单个页面被调用的次数更多:
Init for individual page called.
Common init called.
Init for individual page called.
两者都没有。可以通过将整个元数据部分放在Init for individual page called.
Common init called.
Init for individual page called.
Init for individual page called.
之上或者通过向视图的元数据部分添加虚拟参数来防止2和3,该部分未包含在URL中:
ui:define
有人可以告诉我这些案件的原因吗?
答案 0 :(得分:5)
我可以重现它。这是由于/WEB-INF/beans.xml
的存在以及CDI的隐含引起的。当您在保留beans.xml
文件的同时切换回标准JSF注释时,甚至会发生这种情况。这已经报告为issue 1771和issue 2162。然而,由于没有具体的WAR文件重现问题和低票,Mojarra开发人员并没有费心去仔细研究它。
我再次将其报告为issue 2719。可以用一个较小的例子重现该问题:
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<f:metadata>
<f:event type="preRenderView" listener="#{bean.preRenderView}" />
</f:metadata>
<h:head>
<title>preRenderView fail</title>
</h:head>
<h:body>
<p>On initial request, you'll see the listener being invoked twice instead of only once.</p>
<p>On every postback by the below button, you'll see the listener being invoked once more.</p>
<h:form>
<h:commandButton value="submit" />
</h:form>
<p>Note however that this increments every time you issue the postback.</p>
<p>If you remove <code>/WEB-INF/beans.xml</code> and redeploy, then the issue will disappear.</p>
</h:body>
</html>
和
package com.example;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class Bean {
public void preRenderView() {
System.out.println("preRenderView called");
}
}
答案 1 :(得分:1)
缺少资源也可能导致侦听器被调用两次。我在这里使用MyFaces 2.2:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:metadata>
<f:event type="preRenderView" listener="#{testController.update()}" />
</f:metadata>
<h:head>
<script type="text/javascript" src="#{resource['/js/missing.js']}" />
<title>Test</title>
</h:head>
<h:body>
<p>TestController.update() is called twice.</p>
</h:body>
</html>
显然,您不应该首先包含任何缺失或过时的资源。但是,假设您(错误地)并且您的听众被连续两次调用,您没有机会找到该问题的实际原因。 JSF不应该这样做。