JavaServer Faces

Como exibir a FacesMessage depois do redirect com o escopo Flash do JSF

Você sabe como fazer para exibir as mensagens JSF na tela mesmo após um redirect?

O JSF tem uma maneira bem específica de fazer uma mensagem chegar até o usuário do sistema.

É um jeito bem legal de se fazer isso, mas que NÃO dá, por padrão, o suporte para exibição de mensagens após um redirecionamento. Inclusive, esse é justamente o assunto de agora.

Continue lendo o artigo para aprender como usar o Flash do JSF para resolver esse problema.

O problema

Não é o mais comum, mas as vezes é necessário realizar alguma ação em nosso managed bean e, logo após, fazer um redirecionamento.

Imagine que, da página formulario-pagamento.xhtml, você chama a ação realizarPagamento que redireciona para a página pagamento-sucesso.xhtml:

@ManagedBean
@ViewScoped
public class PagamentoBean {

  public void realizarPagamento() {
    FacesContext.getCurrentInstance().addMessage(
        null, new FacesMessage("Pagamento realizado com sucesso!"));

    return "pagamento-sucesso.xhtml?faces-redirect=true";
  }
}

Levando em consideração o método realizarPagamento acima, você vai querer mostrar a mensagem JSF na página pagamento-sucesso.xhtml através da tag h:messages:

<h:messages />

O que vai acontecer é que a mensagem “Pagamento realizado com sucesso!” adicionada pelo método realizarPagamento NÃO será exibida. Isso acontece porque, por padrão, só é possível exibir as mensagens do JSF dentro do mesmo ciclo em que elas foram adicionadas.

Um redirect faz com que as mensagens sejam ignoradas, ou seja, quando chegar na página de destino, elas não estarão mais disponíveis.

Uma possível solução seria trocar o escopo do managed bean para @SessionScoped e usar um atributo “mensagem” para mostrar o aviso ao usuário, como no código abaixo:

@ManagedBean
@SessionScoped
public class PagamentoBean {

  private String mensagem;

  public void realizarPagamento() {
    mensagem = "Pagamento realizado com sucesso!";

    return "pagamento-sucesso.xhtml?faces-redirect=true";
  }

  //getters e setters omitidos

}

E na página pagamento-sucesso.xhtml teríamos:

<h:outputText value="#{pagamentoBean.mensagem}" />

Alguns desenvolvedores chegam a fazer isso. Eu não considero uma solução ruim, mas, na dica de hoje, vou mostrar como postergar a disponibilidade dessas mensagens para que você consiga exibi-las, através da tag h:messages, mesmo após o redirecionamento.

Exibindo mensagens após redirecionamento

Para conseguir com que as mensagens sobrevivam ao redirecionamento, basta usar o código abaixo:

FacesContext.getCurrentInstance()
    .getExternalContext()
    .getFlash().setKeepMessages(true);

Essa linha vai fazer com que suas mensagens sejam armazenadas no escopo de Flash.

A duração desse escopo vai ser o suficiente para que você consiga exibir as mensagens adicionadas depois do redirecionamento.

O código completo do método ficaria assim:

public String realizarPagamento() {
  FacesContext.getCurrentInstance().addMessage(
        null, new FacesMessage("Pagamento realizado com sucesso!"));

  FacesContext.getCurrentInstance()
      .getExternalContext()
      .getFlash().setKeepMessages(true);

  return "pagamento-sucesso.xhtml?faces-redirect=true";
}

É bem simples. Bastaria agora ter a tag messages em sua página de destino.

<h:messages />

O que é o escopo Flash do JSF?

Como você deve ter reparado, eu citei que as mensagens são armazenadas no escopo de Flash.

Você já conhecia? Para quem nunca usou, vou explicá-lo melhor agora.

Esse escopo nos permite manter objetos disponíveis após um redirecionamento.

Tanto o redirecionamento mapeado com:

<navigation-rule>
  <from-view-id>formulario-pagamento.xhtml</from-view-id>
  <navigation-case>
    <from-outcome>pagamento-sucesso</from-outcome>
    <to-view-id>pagamento-sucesso.xhtml</to-view-id>
    <redirect />
  </navigation-case>
</navigation-rule>

… quanto da forma como vimos anteriormente:

public String realizarPagamento() {
  ...

  return "pagamento-sucesso.xhtml?faces-redirect=true";
}

A duração desses objetos será até a página de destino ser renderizada, após isso eles serão ignorados.

Seu uso mais comum é com o objetivo que mostramos aqui, ou seja, para mensagens.

Mas, é possível também colocar outros objetos criados por você.

Veja:

public String realizarPagamentoEVerResumo() {
  FacesContext.getCurrentInstance().addMessage(
      null, new FacesMessage("Pedido realizado com sucesso!"));

  FacesContext.getCurrentInstance()
      .getExternalContext()
      .getFlash().setKeepMessages(true);

  FacesContext.getCurrentInstance()
      .getExternalContext()
      .getFlash().put("rp", resumoPedido); // incluindo um objeto no escopo Flash

  return "pagamento-sucesso.xhtml?faces-redirect=true";
}

Para acessar esse objeto em sua página de destino você pode usar assim:

#{flash.rp.item}

ou assim:

#{flash['rp'].item}

Tirando o caso das mensagens, o uso desse escopo são para atividades bem pontuais.

Provavelmente você não precisará fazer um uso extenso dele, mas acredito que é bom saber que ele existe.

Conclusão

Os programadores que precisavam criar atributos em seu managed bean somente para exibir uma mensagem após o redirecionamento, agora tem uma solução bem melhor.

O JSF ainda NÃO possui uma anotação tipo:

@FlashScoped

Até porque ele não seria tão útil assim, os escopos existentes do JSF já resolvem tudo, ou quase tudo, do que precisamos.

Além do que é possível criarmos escopos customizados para nossos managed beans, e guardar as informações referentes a essa criação dentro do próprio escopo Flash do JSF, o que acabaria, claro, sendo um escopo Flash também.

Agora que você aprendeu sobre como exibir as mensagens JSF após um redirecionamento, talvez queira aprender mais sobre JSF com o livro Java EE 7 com JSF, PrimeFaces e CDI.

Você pode baixar o PDF do livro gratuitamente:

E-book Java EE 7 com JSF, Primefaces e CDI

Outra coisa importante é deixar seu comentário dizendo se gostou, se não gostou, uma opinião, crítica ou elogio. :)

Ele (o seu comentário) nos ajuda a decidir quais serão as próximas publicações.

Uma abraço e até uma próxima!

PS: o código-fonte dos exemplos desse artigo pode ser acessado em: http://github.com/algaworks/artigo-jsf-facesmessage-redirecionamento

Trabalha como programador Java há mais de uma década, principalmente com desenvolvimento de sistemas corporativos.Além de colaborar com o blog, também é instrutor de vários cursos de Java na AlgaWorks.

Olá,

o que você achou deste conteúdo? Conte nos comentários.

Junte-se a mais de 100.000 pessoas

Entre para nossa lista e receba conteúdos exclusivos e com prioridade

Você se Inscreveu com Sucesso!