JSF – Eseguire codice in ogni fase
Spesso si ha l’esigenza di compiere delle istruzioni ogni volta che viene richiamata una pagina jsf, prima o dopo della fase di request, o di response etc.. Bene, tramite l’implementazione della classe PhaseListener abbiamo una ampia possibilità di fare ttuto questo in pochissimi passi.
Ad esempio l’esigenza del codice di esempio proposto è controllare l’accesso alle pagine web prima di aver fatto effettuare il login ad un utente dell’applicazione. Il login lo rendo disponibile tramite campi di inputtext nella pagina “login.jsf” o altra estensione (dipende dalle configurazioni nel web.xml), e questa sarà l’unica pagina senza controllo. Se qualcuno cerca di raggiungere altre pagine senza essere stato autenticato, riporto l’utente alla pagina di login.
La prima cosa da fare quindi è creare una classe simile a questa:
package lorenzo.phases;
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
/**
*
* @author Lorenzo
*/
public class CheckPermsPhaseListener implements PhaseListener {
public void afterPhase(PhaseEvent event) {
FacesContext fc = event.getFacesContext();
//controllo se sono nella pagina di login
boolean loginpage = fc.getViewRoot().getViewId().lastIndexOf("login") > -1 ? true : false;
//se non sono nella pagina di login e se non sono loggato
if (!loginpage && !utility.getUserSessionBean().getLoggato()) {
NavigationHandler nh = fc.getApplication().getNavigationHandler();
nh.handleNavigation(fc, null, "logout");
}
}
public void beforePhase(PhaseEvent event) {
}
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
}
In questo esempio eseguo il codice di controllo subito dopo (metodo afterPhase) la fase di Restore View. Per far eseguire il codice in un altra fase, basta far ritornare al metodo getPhaseId un valore del tipo:
PhaseId.ANY_PHASE, PhaseId.APPLY_REQUEST_VALUES, PhaseId.INVOKE_APPLICATION, PhaseId.PROCESS_VALITATIONS, PhaseId.RENDER_RESPONSE, PhaseId.RESTORE_VIEW, PhaseId.UPDATE_MODEL_VALUES.
Creata la classe, bisogna registrarla nel file faces-config.xml, attraverso queste linee:
<lifecycle>
<phase-listener>lorenzo.phases.CheckPermsPhaseListener</phase-listener>
</lifecycle>
Ecco la sequenza delle fasi eseguite dal framework JSF:
Fasi Java ServerFaces




Ciao
Ti faccio una domanda.Alla riga:
if (!loginpage && !utility.getUserSessionBean().getLoggato()) )
ti rifai alla proprietà getLoggato() di utility.getUserSessionBean().
Come va implementata questa classe? Io non riesco a capire come fare queste due cose con JSF:
1. mettere oggetti in SESSIONE
2. utilizzare oggetti presente in SESSIONE (ovviamente)
Spero in un aiuto,ho le idee molto confuse a riguardo.
Saluti,antonio
Ciao, hai ragione, nel codice ho menzionato l’uso di una classe della quale però non faccio riferimento. Semplicemente è un bean a livello sessione che mi tiene in memoria quello che mi serve per tutto il tempo in cui un utente è collegato all’applicazione (tra cui un boolean, ‘loggato’, che mi dice se in quella sessione un utente si è autenticato correttamente e risulta presente come utente della applicazione, nel mio caso ho un database alle spalle di solito).
In JSF si usa il file di configurazione faces-config.xml, e per dichiarare un bean a livello sessione basta inserire al suo interno un codice del tipo(levare gli spazi accanto le parentesi angolari <> ):
< managed-bean >
< description >bean per gestire l'utente di sessione collegato < /description >
< managed-bean-name >userSessionBean< /managed-bean-name >
< managed-bean-class >mioPackage.ClasseUser< /managed-bean-class >
< managed-bean-scope >session< /managed-bean-scope >
< /managed-bean >
a questo punto nelle tue pagine web puoi usare la sintassi EL di JSF per richiamare metodi ed oggetti di questo bean:
#{UserSessionBean.proprieta}
ricordando che nella classe ci deve essere il metodo ‘getProprieta()’.
Se vuoi invece utilizzare oggetti di sessione, ma non nelle pagine, ma direttamente nelle altre classi java (che possono essere usate come bean a livelli request o session), puoi usare le istruzioni che seguono:
ClasseUser ilBean = ((ClasseUser) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("userSessionBean"));
Spero di essere stato abbastanza chiaro, ma dato che, pensandoci, non sei il primo ad avermi chiesto queste perplessità, credo che scriverò un tutorial a tal proposito. Ti ringrazio per l’idea, anzi, ti invito a lasciarmi più spesso commenti ed idee.
Saluti
Lorenzo
Ciao,grazie per la risposta,sono riuscito a buttare giu un pò di codice,ovviamente non funzionante
Intanto ti do un link dove ho postato il codice,magari riesci a dargli un occhiata:
http://www.friendpaste.com/6f4VNxH71K61pKFhpci14q
Ti spiego la mia situazione: Ho una pagina di login logIn.jspx nella root delle pagine web.Poi ho delle pagine a cui si può accedere solo se il login va a buon fine che sono nella cartella /secure.
logIn.jspx
SECURE
|_____ index.jspx
|_____ mostraAuto.jspx
|_____ inserisciAuto.jspx
Utilizzo un backing bean “LogIn.java” per effettuare il binding tra la proprietà di questo bean e i valori inseriti dall’utente nella pagina logIn.jspx. in questo backingbeans vi è un’action che effettua le operazioni di business(ovvero controllare se l’utente ha inserito credenziali giuste per fare il login).
Questo backing bean è però di tipo request.Infatti per memorizzare le info di un utente in sessione,mi servo di un managed bean chiamato SessionBean che è di tipo session,che utilizzo nella Action che controlla le credenziali utente,se queste sono esatte.
//se le credenziali sono esatte
FacesContext context = FacesContext.getCurrentInstance();
SessionBean sessionBean = (SessionBean)context.getApplication().evaluateExpressionGet(context,”#{sessionBean}”,SessionBean.class);
sessionBean.setUsername(this.getUsername());
sessionBean.setIsLoggato(true);
Quindi ho creato il Filtro seguendo le tue istruzioni,ed effettivamente il filto prova a fare quello che deve fare,però,provando ad accedere direttamente ad una pagina “sicura” senza effettuare il login,jboss mi segnala un’eccezione alla riga:
if (!loginpage && !SessionUtility.getSessionBean().getIsLoggato())
AVVERTENZA: phase(RESTORE_VIEW 1,com.icesoft.faces.context.BridgeFacesContext@fc644a) threw exception: java.lang.NullPointerException null
E in effetti è giusto,in quanto se non mi sono loggato,non esiste alcun “sessionBean”,da questo la null pointer exception.
Se provo a loggarmi,invece niente eccezione,ma niente filtro funzionante.
Ciao,come non detto,ho risolto.
Ti ringrazio molto per le spiegazioni e per il tutorial che mi ha dato lo spunto per mettermi sulla buona strada.Continuerò a seguirti.
Antonio
Mi fa piacere che i miei appunti siano serviti per il tuo lavoro. Grazie
A presto
Lorenzo
Ciao Lorenzo,
vorrei chiederti se è possibile recuperare il backing bean associato alla view per poter invocare un metodo ad esempio “init()”.
Il mio obiettivo è invocare un metodo per gestire automaticamente l’inizializzazione dei componenti ad ogni RESTORE_VIEW
Ciao Lorenzo,
innanzitutto bel tutorial, però ho un problema nel farmi ritornare la viewroot, fc.getViewRoot()… praticamente ritorna null.
Tu sai cosa potrebbe essere?
@Fra
Ciao.
L’oggetto “fc” invece è correttamente istanziato?
Che versione di jsf stai usando? considera che questo codice si riferisce a un esempio in jsf 1.2, anche se non credo che questa gestione sia cambiata per le 2.0.
Lorenzo
Uso le JSF 2 e fc lo ottengo come te, con event.getFacesContext();
Ho controllato, fc non è null.
In alternativa tu sapresti consigliarmi un sistema simile, cioè mi interessa controllare se un utente è loggato e se non lo è ridirezionarlo ancora alla pagina di login, conosci un sistema analogo?
Ciao grazie per il tutorial, mi sono avvicinato proprio ora a JSF e me ne sono innamorato e la prima cosa che mi sono chiesta e se c’era la possibilità di eseguire determinare operazioni subito prima di una request o una response e pum! esce fuori il tuo blog
Grazie ancora!