Para que podem ser utilizados <f: metadata>, <f: viewParam> e <f: viewAction>?

149

Alguém pode esclarecer como podemos usar em geral, ou um exemplo do mundo real, esse trecho?

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

Respostas:

288

Parâmetros GET do processo

O <f:viewParam>gerencia a configuração, conversão e validação dos parâmetros GET. É como o <h:inputText>, mas depois para os parâmetros GET.

O exemplo a seguir

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

faz basicamente o seguinte:

  • Obtenha o valor do parâmetro de solicitação pelo nome id.
  • Converta e valide-o, se necessário (você pode usar required, validatore converteratributos, e aninhar um <f:converter>e <f:validator>nele como em <h:inputText>)
  • Se a conversão e a validação forem bem-sucedidas, configure-a como uma propriedade de bean representada por #{bean.id}valor ou, se o valueatributo estiver ausente, configure-o como atributo de solicitação no nome, idpara que fique disponível #{id}na visualização.

Portanto, quando você abre a página foo.xhtml?id=10, o valor do parâmetro 10é definido no bean dessa maneira, imediatamente antes da exibição da renderização.

Quanto à validação, o exemplo a seguir define o parâmetro como required="true"e permite apenas valores entre 10 e 20. Qualquer falha na validação resultará na exibição de uma mensagem.

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

Executando ação de negócios nos parâmetros GET

Você pode usar o <f:viewAction>para isso.

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

com

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

No <f:viewAction>entanto, isso é novo desde o JSF 2.2 (o <f:viewParam>já existe desde o JSF 2.0). Se você não puder atualizar, sua melhor aposta será usar <f:event>.

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

No entanto, isso é invocado em cada solicitação. Você precisa verificar explicitamente se a solicitação não é uma postagem:

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

Quando você também quiser pular os casos "Falha na conversão / validação", faça o seguinte:

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

Usar <f:event>esta maneira é, em essência, uma solução alternativa / hack, é exatamente por isso que <f:viewAction>foi introduzido no JSF 2.2.


Passar os parâmetros da visualização para a próxima visualização

Você pode "passar" pelos parâmetros de exibição nos links de navegação, definindo o includeViewParamsatributo trueou adicionando o includeViewParams=trueparâmetro de solicitação.

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

que gera com o <f:metadata>exemplo acima basicamente o seguinte link

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

com o valor do parâmetro original.

Essa abordagem requer apenas que tambémnext.xhtml tenha um no mesmo parâmetro, caso contrário, ela não será repassada.<f:viewParam>


Use formulários GET no JSF

O <f:viewParam>também pode ser usado em combinação com formulários GET "HTML simples".

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

Com basicamente esse @RequestScopedbean:

private String query;
private List<Result> results;

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

Observe que o <h:message>é para o <f:viewParam>HTML, e não para o HTML <input type="text">! Observe também que o valor de entrada é exibido #{param.query}quando #{bean.query}está vazio, porque, caso contrário, o valor enviado não seria exibido quando houvesse um erro de validação ou conversão. Observe que essa construção é inválida para os componentes de entrada JSF (isso já está "oculto").


Veja também:

BalusC
fonte
@BalusC Qual deve ser o escopo de "bean" quando usado em conjunto com faces-redirect = true? Funcionará como esperado se o escopo estiver definido como "@RequestScoped"?
Geek
@ Geek: Um redirecionamento cria uma nova solicitação GET. O escopo do bean de origem e de destino é irrelevante. No entanto, você deve levar em conta as possíveis implicações de uma nova solicitação GET para uma solicitação e exibir o bean com escopo definido. Veja também stackoverflow.com/questions/7031885/…
BalusC
@BalusC O que exatamente você quer dizer com "No entanto, você deve levar em consideração as possíveis implicações de uma nova solicitação GET para uma solicitação e exibir o bean com escopo definido".
Geek
@ Geek: Eles serão descartados e recriados porque seu escopo terminará e começará.
BalusC
@BalusC. Uma resposta abrangente. "Quando você precisar usar um recurso '@' PostConstruct como para exibir beans de escopo que não são chamados em todas as solicitações, verifique se a solicitação não é uma postagem". Se não for chamado em todas as solicitações, por que verificar se a solicitação é uma postagem ou não?
22613 Uluk Biy