À quoi peuvent servir <f: metadata>, <f: viewParam> et <f: viewAction>?

149

Quelqu'un peut-il clarifier comment nous pouvons utiliser en général, ou un exemple dans le monde réel, cet extrait de code?

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

Réponses:

288

Paramètres GET du processus

Le <f:viewParam>gère le réglage, la conversion et la validation des paramètres GET. C'est comme les <h:inputText>paramètres, mais alors pour GET.

L'exemple suivant

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

fait essentiellement ce qui suit:

  • Obtenez la valeur du paramètre de demande par nom id.
  • Convertissez-le et validez-le si nécessaire (vous pouvez utiliser required, validatoret des converterattributs et y imbriquer un <f:converter>et <f:validator>comme avec <h:inputText>)
  • Si la conversion et la validation réussissent, définissez-la comme propriété de bean représentée par #{bean.id}valeur, ou si l' valueattribut est absent, définissez-le comme attribut de requête sur le nom idafin qu'il soit disponible #{id}dans la vue.

Ainsi, lorsque vous ouvrez la page, foo.xhtml?id=10la valeur du paramètre est 10définie dans le bean de cette manière, juste avant le rendu de la vue.

En ce qui concerne la validation, l'exemple suivant définit le paramètre sur required="true"et autorise uniquement les valeurs comprises entre 10 et 20. Tout échec de validation entraînera l'affichage d'un message.

<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" />

Exécution d'une action commerciale sur les paramètres GET

Vous pouvez utiliser le <f:viewAction>pour cela.

<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" />

avec

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

Le <f:viewAction>est cependant nouveau depuis JSF 2.2 (il <f:viewParam>existe déjà depuis JSF 2.0). Si vous ne pouvez pas mettre à niveau, votre meilleur pari est d'utiliser à la <f:event>place.

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

Ceci est cependant invoqué à chaque demande. Vous devez vérifier explicitement si la demande n'est pas une publication:

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

Si vous souhaitez ignorer également les cas "Échec de la conversion / validation", procédez comme suit:

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

L'utilisation de <f:event>cette méthode est essentiellement une solution de contournement / hack, c'est exactement pourquoi le a <f:viewAction>été introduit dans JSF 2.2.


Passer les paramètres de vue à la vue suivante

Vous pouvez "passer" les paramètres de vue dans les liens de navigation en définissant l' includeViewParamsattribut sur trueou en ajoutant un includeViewParams=trueparamètre de requête.

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

qui génère avec l' <f:metadata>exemple ci-dessus essentiellement le lien suivant

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

avec la valeur de paramètre d'origine.

Cette approche ne nécessite que d' next.xhtmlavoir également un <f:viewParam>sur le même paramètre, sinon il ne sera pas transmis.


Utiliser les formulaires GET dans JSF

Le <f:viewParam>peut également être utilisé en combinaison avec des formulaires GET "HTML brut".

<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>

Avec essentiellement ce @RequestScopedharicot:

private String query;
private List<Result> results;

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

Notez que le <h:message>est pour le <f:viewParam>, pas le HTML pur <input type="text">! Notez également que la valeur d'entrée s'affiche #{param.query}lorsqu'elle #{bean.query}est vide, car la valeur soumise ne s'afficherait pas du tout en cas d'erreur de validation ou de conversion. Veuillez noter que cette construction n'est pas valide pour les composants d'entrée JSF (elle le fait déjà "sous les couvertures").


Voir également:

BalusC
la source
@BalusC Quelle devrait être la portée de "bean" lorsqu'il est utilisé en conjonction avec faces-redirect = true? Fonctionnera-t-il comme prévu si la portée est définie sur "@RequestScoped"?
Geek
@Geek: Une redirection crée une nouvelle requête GET. La portée du bean du bean source et cible n'est pas pertinente. Vous devez cependant prendre en compte les implications possibles d'une nouvelle requête GET pour une requête et un bean à portée de vue. Voir aussi stackoverflow.com/questions/7031885/…
BalusC
@BalusC Qu'est-ce que vous entendez exactement par "Vous devez cependant prendre en compte les éventuelles implications d'une nouvelle requête GET pour une requête et voir le bean de portée."
Geek
@Geek: Ils seront supprimés et recréés car leur portée se terminera et commencera.
BalusC du
@BalusC. Une réponse complète. "Lorsque vous avez besoin d'utiliser une fonctionnalité similaire à '@' PostConstruct pour les beans à portée de vue qui n'est pas invoquée à chaque requête, vérifiez si la requête n'est pas une publication". S'il n'est pas appelé à chaque demande, pourquoi vérifier si la demande est une publication ou non?
Uluk Biy