Uno dei concetti nuovi di Struts 2, rispetto alla precedente versione, è rappresentato dagli Interceptor, classi stateless (che non mantengono uno stato tra invocazioni successive) che possono essere invocate automaticamente prima e dopo una Action.
Di default, Struts 2, prevede un gruppo di interceptor, che vengono richiamati prima di invocare qualsiasi action. Il cosiddetto stack di default, prevede ben 17 interceptor che lavorano dietro le quinte per offrire vari servizi. I principali sono i seguenti:
- Exception: permette di mappare una particolare eccezione ad una vista;
- Prepare: permette di richiamamare un metodo di inizializzazione della Action nel caso questa implementi una determinata interfaccia;
- I18n: gestisce la memorizzazione del locale per l'utente corrente;
- Debugging: permette di attivare il debug delle viste;
- FileUpload: permette di gestire l'upload dei file;
- Validation: permette di eseguire la validazione dei dati forniti nella form, congruentemente al contenuto dei relativi file xml di definizione dei controlli.
Oltre agli interceptor inclusi nello stack di default, struts 2 permette di configurare ulteriori interceptor disponibili, utili soltanto in situazioni particolari.
In questo articolo, vedremo come utilizzare uno degli interceptor waitAndExecute
, che permette di fornire all'utente un messaggio di attesa qualora i dati non siano caricati.
Si pensi ad uno scenario in cui l'utente debba effettuare una ricerca all'interno del nostro portale. Qualora il sistema, per estrapolare tutti i dati corrispondenti ai filtri di ricerca impostati, necessiti di un po' di tempo di elaborazione, sarebbe carino far apparire un messaggio di attenzione che informi l'utente che la ricerca è in corso.
L'interceptor "executeAndWait
" di Struts 2, è proprio stato pensato per risolvere questo tipo di problema. Sostanzialmente questo interceptor esegue una action in background e attende per un certo tempo che la stessa termini. Se la action termina subito, l'interceptor risulta ininfluente, ma se la action richiede tempi lunghi di elaborazione, viene caricata la vista wait.
Definiamo la nostra action nel file struts.xml nel seguente modo:
<struts>
<package name="html" extends="struts-default">
<action name="RicercaAction" class="it.html.action.RicercaAction">
<interceptor-ref name="completeStack" />
<interceptor-ref name="execAndWait">
<param name="delay">1000</param>
</interceptor-ref>
<result name="success">/risultati.jsp</result>
<result name="input">/index.jsp</result>
<result name="wait">/attendere.jsp</result>
</action>
</package>
</struts>
L'interceptor execAndWait
prevede il parametro delay, che rappresenta il tempo, in millisecondi, che l'interceptor attenderà prima di richiamare la vista "wait".
Naturalmente, è necessario fornire i due forward, success e wait, che redirigono rispettivamente alla pagina dei risultati e alla pagina di attesa.
Il form di ricerca sarà semplicissimo, includiamo un semplice campo di testo: destinazione.
<s:form action="RicercaAction.action" method="POST">
<s:actionerror />
<s:textfield key="destinazione" name="destinazione" />
<s:submit key="ricerca" />
</s:form>
Naturalmente, per studiare il comportamento dell'interceptor, dobbiamo far sì che l'operazione di ricerca richieda un bel po' di tempo. Per far questo, utilizziamo il metodo sleep della classe Thread.
public class RicercaAction extends ActionSupport{
private static final long serialVersionUID = -6822656588379793714L;
private String destinazione;
public String execute() throws Exception {
for (int i=0; i< 40; i++){
try{
Thread.sleep(400);
}
catch (InterruptedException e){
e.printStackTrace();
}
}
return ActionSupport.SUCCESS;
}
public String getDestinazione() {
return destinazione;
}
public void setDestinazione(String destinazione) {
this.destinazione = destinazione;
}
}
Come abbiamo già detto, qualora l'action impieghi più di 1000 millisecondi per completare l'operazione, l'interceptor chiamerà la vista wait. Nella pagina JSP corrispondente, è necessario richiamare la action ogni n secondi. Per fare ciò utilizziamo il meta tag refresh, che permette di richiamare automaticamente dopo n secondi, un URL specificata.
<s:i18n name="Messaggi">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="refresh" content='5;url=<s:url includeParams="all"/>' />
<title><s:text name="titolo" /></title>
</head>
<body>
<s:text name="attenderePrego" />
</body>
</html>
</s:i18n>