jsf-2 - method - jsf prerenderview redirect
PreRenderView invoca incrementalmente cada devoluciĆ³n de datos (2)
Un recurso faltante también puede provocar que se llame al oyente dos veces. Estoy usando MyFaces 2.2 aquí:
<!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>
Obviamente, no debe incluir ningún recurso faltante u obsoleto en primer lugar. Pero digamos que tiene (por error) y su oyente recibe una llamada dos veces seguidas, no tiene posibilidad de encontrar la causa real de ese problema. JSF no debería hacer esto.
Tengo un problema con el orden y el número de ejecuciones de un f:event type="preRenderView"
.
Durante mi búsqueda aquí, encontré las respuestas habituales de BalusC en este y en este post relacionadas con mi problema, pero aún me quedan dos preguntas:
Cuando coloco un
f:event type="preRenderView"
en el archivo de plantilla (para gestionar tareas comunes como comprobaciones sobre el estado de usuario que aplica para todas mis vistas) y otrof:event type="preRenderView"
en cada vista (para manejo ver inicializaciones específicas), me pregunto por qué el método del oyente de la vista se llama antes que el de la plantilla.Cuando pongo todo el
<f:metadata><f:event [..] /></f:metadata>
después deui:define
como se sugiere, se llama dos veces después de redireccionar a esa página desde la página de inicio de sesión, pero cuando ponlo un nivel más alto después deui:composition
, solo se llama una vez.
Actualización: Ejemplo
El siguiente ejemplo demuestra el comportamiento anterior:
Este es el archivo de template_test.xhtml
, que contiene un detector para el evento preRenderView
llamando a un método común en un controlador para todas las vistas:
<?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>
Este es el archivo de vista test.xhtml
, que también contiene un detector para el evento preRenderView
llamando a un método específico de vista en un controlador y un botón de comando redirigido a través de un método de controlador:
<?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>
Esta es la clase de controlador TestHandler.java
contiene los 3 métodos:
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";
}
}
Ahora, esto es lo que veo en mi registro de Tomcat cuando solicito la página de prueba:
Init for individual page called.
Common init called.
Init for individual page called.
Esto muestra que no. 1, que el controlador de eventos de la vista se llama antes que el de la plantilla y no. 2, que el controlador de eventos de la vista se llama dos veces.
También muestra un tercer punto (es por eso que incluí un botón con un redireccionamiento a la misma página) que muestra lo que sucede si la página es solicitada por redirección: cada página se llama aún más veces:
Init for individual page called.
Common init called.
Init for individual page called.
Init for individual page called.
Ambos no 2 y 3 pueden prevenirse colocando toda la sección de metadatos sobre la ui:define
o agregue un parámetro ficticio a la sección de metadatos de la vista que no esté incluida en la URL:
<f:metadata>
<f:viewParam name="dummyToDenySecondRedirect" />
<f:event type="preRenderView"
listener="#{testHandler.initIndividual()}"></f:event>
</f:metadata>
¿Puede alguien decirme el motivo de esos casos?
Puedo reproducirlo Esto es causado por la presencia de / /WEB-INF/beans.xml
- /WEB-INF/beans.xml
/ /WEB-INF/beans.xml
e implícitamente CDI. Incluso ocurre cuando vuelves a las anotaciones JSF estándar mientras mantienes el archivo beans.xml
. Esto ya se informó como el número 1771 y el número 2162 . Sin embargo, debido a la ausencia de un archivo WAR concreto que reproduzca el problema y los votos bajos, los desarrolladores de Mojarra no se molestaron en mirarlo de cerca.
Lo he reportado una vez más como el número 2719 . El problema se puede reproducir con un ejemplo más pequeño:
<!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>
y
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");
}
}