¿Para qué se pueden usar <f: metadata>, <f: viewParam> y <f: viewAction>?

149

¿Alguien puede aclarar cómo podemos usar en general, o en un ejemplo del mundo real, este fragmento?

<f:metadata>
    <f:viewParam id="id" value="#{bean.id}" />
    <f:viewAction action="#{bean.init}" />
</f:metadata>
Hanynowsky
fuente

Respuestas:

288

Procesar parámetros GET

El <f:viewParam>gestiona la configuración, conversión y validación de los parámetros GET. Es como el <h:inputText>, pero luego para los parámetros GET.

El siguiente ejemplo

<f:metadata>
    <f:viewParam name="id" value="#{bean.id}" />
</f:metadata>

hace básicamente lo siguiente:

  • Obtenga el valor del parámetro de solicitud por nombre id.
  • Convierte y validarlo si es necesario (se puede utilizar required, validatory converterlos atributos y un nido <f:converter>y <f:validator>en ella, como al igual que con <h:inputText>)
  • Si la conversión y la validación tienen éxito, configúrelo como una propiedad de bean representada por #{bean.id}valor, o si el valueatributo está ausente, configúrelo como atributo de solicitud en el nombre idpara que esté disponible #{id}en la vista.

Entonces, cuando abre la página, foo.xhtml?id=10el valor del parámetro 10se establece en el bean de esta manera, justo antes de que se visualice la vista.

En cuanto a la validación, el siguiente ejemplo establece el parámetro en required="true"y permite solo valores entre 10 y 20. Cualquier falla de validación dará como resultado que se muestre un mensaje.

<f:metadata>
    <f:viewParam id="id" name="id" value="#{bean.id}" required="true">
        <f:validateLongRange minimum="10" maximum="20" />
    </f:viewParam>
</f:metadata>
<h:message for="id" />

Realizar acciones comerciales sobre parámetros GET

Puedes usar el <f:viewAction>para esto.

<f:metadata>
    <f:viewParam id="id" name="id" value="#{bean.id}" required="true">
        <f:validateLongRange minimum="10" maximum="20" />
    </f:viewParam>
    <f:viewAction action="#{bean.onload}" />
</f:metadata>
<h:message for="id" />

con

public void onload() {
    // ...
}

Sin <f:viewAction>embargo, es nuevo desde JSF 2.2 (el <f:viewParam>ya existe desde JSF 2.0). Si no puede actualizar, entonces su mejor opción es usar en su <f:event>lugar.

<f:event type="preRenderView" listener="#{bean.onload}" />

Sin embargo, esto se invoca en cada solicitud. Debe verificar explícitamente si la solicitud no es una devolución de datos:

public void onload() {
    if (!FacesContext.getCurrentInstance().isPostback()) {
        // ...
    }
}

Cuando desee omitir también los casos de "Error de conversión / validación", haga lo siguiente:

public void onload() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    if (!facesContext.isPostback() && !facesContext.isValidationFailed()) {
        // ...
    }
}

Usar <f:event>esta forma es, en esencia, una solución alternativa / pirateo, es exactamente por eso que <f:viewAction>se introdujo en JSF 2.2.


Pase los parámetros de vista a la vista siguiente

Puede "pasar" los parámetros de vista en los enlaces de navegación configurando el includeViewParamsatributo trueo agregando el includeViewParams=trueparámetro de solicitud.

<h:link outcome="next" includeViewParams="true">
<!-- Or -->
<h:link outcome="next?includeViewParams=true">

que genera con el <f:metadata>ejemplo anterior básicamente el siguiente enlace

<a href="next.xhtml?id=10">

con el valor del parámetro original.

Este método sólo requiere que next.xhtmltiene también una <f:viewParam>en el mismo parámetro, de lo contrario no puede pasar a través.


Use formularios GET en JSF

El <f:viewParam>también se puede utilizar en combinación con las formas "GET HTML simplificada".

<f:metadata>
    <f:viewParam id="query" name="query" value="#{bean.query}" />
    <f:viewAction action="#{bean.search}" />
</f:metadata>
...
<form>
    <label for="query">Query</label>
    <input type="text" name="query" value="#{empty bean.query ? param.query : bean.query}" />
    <input type="submit" value="Search" />
    <h:message for="query" />
</form>
...
<h:dataTable value="#{bean.results}" var="result" rendered="#{not empty bean.results}">
     ...
</h:dataTable>

Con básicamente este @RequestScopedfrijol:

private String query;
private List<Result> results;

public void search() {
    results = service.search(query);
}

Tenga en cuenta que <h:message>es para el <f:viewParam>HTML, no para el HTML simple <input type="text">. También tenga en cuenta que el valor de entrada se muestra #{param.query}cuando #{bean.query}está vacío, porque de lo contrario el valor enviado no se mostraría en absoluto cuando hay un error de validación o conversión. Tenga en cuenta que esta construcción no es válida para los componentes de entrada JSF (ya lo está haciendo "bajo las cubiertas").


Ver también:

BalusC
fuente
@BalusC ¿Cuál debería ser el alcance de "bean" cuando se usa junto con faces-redirect = true? ¿Funcionará como se espera si el alcance se establece en "@RequestScoped"?
Geek
@ Geek: Una redirección crea una nueva solicitud GET. El alcance del bean del bean de origen y destino es irrelevante. Sin embargo, debe tener en cuenta las posibles implicaciones de una nueva solicitud GET para una solicitud y ver el bean de ámbito. Ver también stackoverflow.com/questions/7031885/…
BalusC
@BalusC ¿Qué quiere decir exactamente con "Sin embargo, debe tener en cuenta las posibles implicaciones de una nueva solicitud GET para una solicitud y ver el bean de ámbito".
Geek
@ Geek: serán destruidos y recreados porque su alcance terminará y comenzará.
BalusC
@BalusC. Una respuesta integral. "Cuando necesite usar una característica similar a '@' PostConstruct para ver beans de ámbito que no se invocan en cada solicitud, verifique si la solicitud no es una devolución de datos". Si no se invoca en cada solicitud, ¿por qué verificar si la solicitud es una devolución o no?
Uluk Biy