Aggiunta di messaggi volti a una pagina reindirizzata utilizzando ExternalContext.redirect ()

Sto usando ExternalContext.redirect (String); metodo per redirect l’utente ad un’altra pagina:

FacesContext.getCurrentInstance().addMessage(new FacesMessage("Bla bla bla...")); FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(true); ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); ec.redirect(ec.getRequestContextPath() + "/scenario.xhtml"); 

Come ha detto Matt Handy nella sua risposta, ho usato Flash.setKeepMessages (true); ma non sembra funzionare con ExternalContext.redirect. (Sebbene funzioni quando reindirizzamento restituendo il nome di una pagina dal metodo di azione di bean).

Ora, come posso aggiungere FacesMessage in modo che sia visibile nella pagina reindirizzata (scenario.xhtml)?

Questo sembra essere un problema di temporizzazione. Questo metodo listener viene richiamato durante l’evento preRenderView . Secondo il codice sorgente di ELFlash (l’implementazione di Flash di Mojarra restituita da ExternalContext#getFlash() ) si scopre che non imposterà il cookie flash quando ci si trova nella fase di risposta del rendering e il cookie flash non ha stato impostato per la richiesta corrente:

Ecco le righe pertinenti di ELFlash :

 if (currentPhase.getOrdinal() < PhaseId.RENDER_RESPONSE.getOrdinal()) { flashInfo = flashManager.getPreviousRequestFlashInfo(); } else { flashInfo = flashManager.getNextRequestFlashInfo(this, true); maybeWriteCookie(context, flashManager); } 

Il maybeWriteCookie imposta il cookie solo quando il cookie flash deve essere passato per la seconda volta (cioè quando la pagina reindirizzata a sua volta reindirizza a un'altra pagina).

Questo è un caso d'angolo sfortunato. Questa logica ELFlash ha senso, ma questo non è ciò che in realtà desideri. Fondamentalmente è necessario aggiungere il messaggio durante la fase INVOKE_APPLICATION . Non c'è tuttavia alcun evento come postInvokeAction . Con il nuovo JSF 2.2 dovrebbe essere ansible poiché viene eseguito realmente durante la fase di dell'applicazione.

  

Finché non sei ancora su JSF 2.2, dovresti cercare modi alternativi. Il modo più semplice sarebbe creare un ComponentSystemEvent .

 @NamedEvent(shortName="postInvokeAction") public class PostInvokeActionEvent extends ComponentSystemEvent { public PostInvokeActionEvent(UIComponent component) { super(component); } } 

Ora hai bisogno di un hook per pubblicare questo evento. Il posto più sensato è un ascolto PhaseListener dopo la fase di INVOKE_APPLICATION .

 public class PostInvokeActionListener implements PhaseListener { @Override public PhaseId getPhaseId() { return PhaseId.INVOKE_APPLICATION; } @Override public void beforePhase(PhaseEvent event) { // NOOP. } @Override public void afterPhase(PhaseEvent event) { FacesContext context = FacesContext.getCurrentInstance(); context.getApplication().publishEvent(context, PostInvokeActionEvent.class, context.getViewRoot()); } } 

Se lo registri come segue in faces-config.xml

  com.example.PostInvokeActionListener  

allora sarai in grado di utilizzare il nuovo evento come segue

  

L'aggiornamento è disponibile anche nella libreria delle utility JSF OmniFaces , quindi non è necessario utilizzare l'homebrew l'uno e l'altro. Vedi anche l' esempio di vetrina InvokeActionEventListener .

Usa il flash per mantenere i messaggi su un reindirizzamento.

Aggiungi queste due linee al tuo codice prima di redirect:

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

Si noti che ci sono alcuni problemi con l’implementazione del flash scope di Mojarra . Tienilo a mente se lo usi.