2. Un primo esempio
La maggior parte dei nostri esempi si limiterà al solo livello web implementato con Struts 2:
![]() |
Una volta acquisite le nozioni di base, analizzeremo un esempio più complesso con un’architettura a più livelli.
2.1. Generazione dell’esempio
Costruiamo la nostra prima applicazione.
![]() |
- in [1], creiamo un nuovo progetto
- in [2], si seleziona il tipo Java Web / Web Application
- in [3], si assegna un nome al progetto
- in [4], si indica la posizione del progetto.
- in [5], si imposta il nuovo progetto come progetto principale.
![]() |
- in [6], si sceglie il server Tomcat. Durante l'installazione di NetBeans 7.01, sono stati installati due server: Apache Tomcat e GlassFish 3.1.
- In [7], si specifica che si lavorerà con il framework Struts 2. È l’installazione del plugin per Struts 2 che ci offre questa possibilità. Senza il plugin, il framework Struts 2 non ci viene proposto.
- In [8] viene richiesta la creazione del progetto di esempio che andremo a studiare.
- In [9] è possibile verificare quali librerie Struts 2 verranno utilizzate.
![]() |
- in [10], il progetto generato. Ci torneremo più avanti.
- in [11], le librerie del progetto. Sono state integrate dal plugin Struts 2. Se non si dispone del plugin, è possibile trovare queste librerie nella cartella [lib] della distribuzione Struts 2 scaricata. Si seguiranno quindi i passaggi 12 e 13.
2.2. Il progetto generato nel sistema di file
![]() |
- in [1], la scheda [Projects] presenta una vista "sviluppatore" del progetto
- in [2], la scheda [Files] mostra la cartella del progetto nel sistema di file
- in [2A], il ramo [Web Pages] è rappresentato in [2] dalla cartella [web] [2B]
- in [3A], il ramo [Source Packages] è rappresentato in [2] dalla cartella [java] [3B]
2.3. Il file di configurazione [META-INF/context.xml]
![]() |
Questo file è il seguente:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/exemple-01"/>
La riga 2 indica che il contesto dell'applicazione web è /exemple-01. Tutti i file URL del tipo [http://machine:port/exemple-01/...] saranno elaborati da questa applicazione. È possibile trovare questo contesto nelle proprietà del progetto [2]: clic con il tasto destro del mouse sul progetto / Proprietà / Esecuzione.
2.4. Il file di configurazione [WEB-INF/web.xml]
![]() |
Ogni applicazione web viene configurata tramite il file [web.xml] presente nella cartella [WEB-INF] dell'applicazione. Il file generato è il seguente:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<URL-pattern>/*</URL-pattern>
</filter-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>example/HelloWorld.JSP</welcome-file>
</welcome-file-list>
</web-app>
- le righe 3-6 definiscono un filtro implementato dalla classe [org.apache.struts2.dispatcher.FilterDispatcher] di Struts 2. È questa classe che svolgerà il ruolo di controller C del modello MVC.
- Righe 7-10: definiscono un collegamento tra un modello URL e il filtro che deve elaborare i URL che seguono tale modello. Qui si specifica che ogni URL (modello /*) deve essere elaborato dal filtro denominato struts2. Si tratta del filtro definito alle righe 3-6. Pertanto, in questo caso, tutte le URL passeranno attraverso il controller Struts 2.
- Righe 11-15: definiscono la durata di una sessione utente, in questo caso 30 minuti. Durante le diverse richieste, un utente viene tracciato tramite un token di sessione che gli è stato assegnato alla sua prima richiesta e che invia poi sistematicamente ad ogni nuova richiesta. Ciò consente al server web di riconoscerlo e di gestire una “memoria” per l’utente, denominata sessione. Se tra due richieste trascorrono più di 30 minuti, viene generato un nuovo token di sessione per l’utente, che perde così la sua “memoria” e ne ricomincia una nuova.
- righe 16-18: definiscono il file da visualizzare quando l’utente interroga l’applicazione web senza richiedere alcun documento. Pertanto, quando il file richiesto URL sarà [http://machine:port/exemple-01], il file fornito URL sarà [http://machine:port/exemple-01/example/HelloWord.JSP].
2.5. Il file di configurazione [struts.xml]
![]() |
Il file [struts.xml] è il file di configurazione di Struts 2. Può trovarsi in qualsiasi posizione all’interno del ClassPath del progetto. Nel progetto NetBeans sopra riportato, il ClassPath del progetto è costituito da due rami:
- Pacchetti sorgente
- Librerie
Qualsiasi cartella o libreria situata in questi due rami fa quindi parte del ClassPath del progetto. È consuetudine collocare il [struts.xml] nel <default package>. In questo caso, il suo contenuto è il seguente:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="example.xml"/>
<!-- Configurazione per il pacchetto predefinito. -->
<package name="default" extends="struts-default">
</package>
</struts>
- righe 5 e 10: il tag radice del documento è il tag <struts>
- riga 6: il file [example.xml] viene inserito qui. Porta quindi con sé la propria configurazione. Ci torneremo più avanti.
- righe 8-9: definiscono un pacchetto denominato qui "default". Un pacchetto consente di configurare un gruppo di azioni Struts 2 che condividono lo stesso URL. Ad esempio [/chemin/Action1] e [/chemin/Action2]. È quindi possibile definire un pacchetto per queste azioni:
<package name="employes" namespace="/employes" extends="struts-default">
... configuration
</package>
Il pacchetto sopra riportato si chiama "dipendenti" e configura le azioni di URL e /employes/Action. Il pacchetto può ereditare da un altro pacchetto tramite la parola chiave "extends". Nell’esempio sopra riportato, il pacchetto employes eredita dal pacchetto struts-default. Questo pacchetto si trova nel file [struts-default.xml] della libreria struts2-core.jar:
![]() |
Il pacchetto "struts-default" definito nel file [struts-default.xml] configura diversi elementi, tra cui un elenco di intercettatori eseguiti al momento della chiamata a un'azione. Torniamo alla struttura MVC di un'applicazione Struts 2:
![]() |
Per elaborare una URL della forma [http://machine:port/.../Action], il controller [FilterDispatcher] istanzierà la classe che implementa l’azione richiesta ed eseguirà uno dei suoi metodi, per impostazione predefinita un metodo denominato execute. La chiamata a questo metodo execute passerà attraverso una serie di intercettatori:
![]() |
Gli intercettatori e l’azione gestiscono tutti la stessa richiesta. L'elenco degli intercettatori definito nel pacchetto struts-default è sufficiente nella maggior parte dei casi. Pertanto, i nostri pacchetti Struts estenderanno sempre il pacchetto struts-default. Per sapere cosa fanno i diversi intercettatori, si consulti il capitolo 4 di [ref2].
Torniamo al file di configurazione struts.xml:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="example.xml"/>
<!-- Configurazione per il pacchetto predefinito. -->
<package name="default" extends="struts-default">
</package>
</struts>
- riga 8: il pacchetto denominato default ha un ruolo particolare. Gestisce le azioni che non sono state configurate negli altri pacchetti. Qui, nelle righe 8-9, non è stata effettuata alcuna configurazione per il pacchetto default. Si potrebbe quindi eliminare la definizione di questo pacchetto.
Vediamo ora il file [example.xml] incluso alla riga 6 del file [struts.xml]:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="HelloWorld" class="example.HelloWorld">
<result>/example/HelloWorld.JSP</result>
</action>
</package>
</struts>
- riga 8: definisce un pacchetto denominato example che estende il pacchetto struts-default. Questo pacchetto gestisce i URL del tipo /example/Action (namespace /example).
- righe 9-11: definiscono un'azione denominata HelloWorld (attributo name) che corrisponde quindi a URL /example/Helloworld. Questa azione viene gestita da un'istanza della classe example.HelloWorld (attributo class).
- Il controller [FilterDispatcher] farà eseguire il metodo execute di questa classe.
- Questo metodo restituirà una stringa denominata «chiave di navigazione».
- Le diverse chiavi di navigazione devono essere definite tramite i tag <result name="chiave"/> (riga 10). In assenza dell’attributo name, viene utilizzata per impostazione predefinita la chiave success. È il caso dell’esempio sopra riportato. Pertanto, il metodo execute della classe example.HelloWorld deve restituire al controller [FilterDispatcher] la chiave success.
- Il controller [FilterDispatcher] provvede quindi a visualizzare la pagina [/example/HelloWorld.JSP] (riga 10).
Se uniamo i due file [struts.xml] e [example.xml] ed eliminiamo il pacchetto default che sembra superfluo, tutto avviene come se il file [struts.xml] fosse stato ridotto al solo file [example.xml].
2.6. L'azione HelloWorld
![]() |
In base al file [struts.xml] esaminato, l'azione HelloWorld viene attivata quando l'URL richiesto dal client è /example/HelloWorld. Viene quindi eseguito il suo metodo execute, che deve restituire una chiave di navigazione. Abbiamo visto che ce n'era solo una: success e che quindi era la pagina /example/HelloWorld.JSP a essere inviata in risposta all'utente.
Il codice dell’azione HelloWorld è il seguente:
- riga 5: la classe HelloWorld deriva dalla classe ActionSupport di Struts 2. È quasi sempre così. Ciò consente di avvalersi di alcuni metodi, come il metodo getText alla riga 8.
- righe 7-10: il metodo execute, che viene eseguito quando viene richiamato il controller Struts. Sappiamo che deve restituire una stringa di caratteri, da cui la sua firma alla riga 7. In questo caso restituirà la costante SUCCESS, definita anch’essa in ActionSupport. Altre costanti sono definite in questo modo per il risultato del metodo execute:
SUCCESS | "success" |
ERROR | "error" |
INPUT | "input" |
LOGIN | "login" |
Quindi, in questo caso, il metodo execute restituisce la stringa success. Se ci si riferisce al file [struts.xml], sarà quindi la pagina /example/HelloWorld.JSP a essere restituita come risposta all'utente.
- riga 8: il metodo execute inizializza il campo message della riga 14 con il valore di getText(" HelloWorld.message "). Il metodo getText appartiene alla classe padre ActionSupport. Consente di recuperare un testo da un file in base alla lingua utilizzata. Per impostazione predefinita, verrà utilizzato il file package.properties situato nello stesso pacchetto dell’azione. Esso è disponibile in due versioni:
Il file [package.properties] è il seguente:
Si tratta di una sequenza di righe di testo del tipo clé=valeur. Se si utilizza questo file, getText("HelloWorld.message") assumerà il valore "Struts is up and running ..."
Il file [package_es.properties] è invece il seguente:
Se la lingua utilizzata dal browser del cliente è lo spagnolo (attributo es, in package_es.properties), getText("HelloWorld.message") avrà come valore ¡Struts está bien! ... In tutti gli altri casi, verrà utilizzato il file [package.properties].
2.7. La vista HelloWorld.JSP
![]() |
È l’ultimo tassello del puzzle Struts. È la vista che viene visualizzata quando viene richiesta la pagina /example/HelloWorld tramite URL. Abbiamo visto attraverso quale labirinto è passata la richiesta iniziale per arrivare infine a visualizzare questa risposta. Il codice della pagina è il seguente:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="HelloWorld.message"/></title>
</head>
<body>
<h2><s:property value="message"/></h2>
<h3>Languages</h3>
<ul>
<li>
<s:url id="URL" action="HelloWorld">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{URL}">English</s:a>
</li>
<li>
<s:url id="URL" action="HelloWorld">
<s:param name="request_locale">es</s:param>
</s:url>
<s:a href="%{URL}">Espanol</s:a>
</li>
</ul>
</body>
</html>
- la pagina utilizza tag HTML (righe 5, 6, ...) e tag di una libreria definita dalla riga 3. Tutti i tag <s:xx> appartengono a questa libreria.
- riga 7: il tag <s:text> consente di visualizzare un testo diverso a seconda della lingua del browser del client. L’attributo name indica la chiave da cercare nei file dei messaggi. Anche in questo caso, verranno utilizzati i file package_xx.properties. Ricordiamo che contengono un unico messaggio con chiave HelloWorld.message.
- riga 11: il tag <s:property name="proprietà"> consente di scrivere il valore di una proprietà di un oggetto denominato ActionContext. In questo oggetto si trovano:
- le proprietà dell’azione che è stata eseguita. name="message" visualizzerà il valore del campo message dell’azione corrente. Sono i metodi get e set associati al campo che vengono utilizzati per ottenerne il valore o per inizializzarlo. Questi metodi devono quindi esistere.
- gli attributi della richiesta corrente indicati con <s:property name="#request['clé']">
- gli attributi della sessione dell’utente contrassegnati con <s:property name="#session['clé']">
- gli attributi dell'applicazione stessa contrassegnati con <s:property name="#application['clé']">
- i parametri inviati dal browser client contrassegnati con <s:property name="#parameters['clé']">
- la notazione <s:property name="#attr['clé']"> visualizza il valore di un oggetto ricercato nella pagina, nella richiesta, nella sessione e nell'applicazione, in quest'ordine.
- righe 16-18: il tag <s:url > serve a definire una URL. L'attributo id assegna un nome all'URL che verrà creato. Questo nome viene poi utilizzato alla riga 19. L'attributo action indica a quale azione deve puntare l'URL.
- riga 17: il tag <s:param ..> consente di aggiungere parametri all'URL nella forma ?param1=valeur1¶m2=valeur2&.... In questo caso, il parametro aggiunto sarà ?request_locale=es.
Alla fine, il file URL generato sarà il seguente:
Per comprendere questo URL, occorre ricordare che la pagina [HelloWorld.JSP] viene visualizzata in due casi:
- (continua)
- su richiesta diretta dell’URL [/exemple-01/example/HelloWorld.JSP]
- su richiesta dell’azione [/exemple-01/example/HelloWorld.action]
In entrambi i casi, il percorso di URL è /exemple-01/example.. Il tag <s:url action= "... "> aggiunge a questo percorso l'azione definita dall'attributo action. Si ottiene così /esempio-01/example/HelloWorld. Aggiunge quindi il suffisso .action al precedente URL, nonché i parametri del URL, se presenti. Il file URL ottenuto /esempio-01/esempio/HelloWorld.action?request_locale=en richiamerà l'azione HelloWorld definita nel file [struts.xml], passando il parametro request_locale=en. Quest'ultimo non verrà elaborato dall'azione HelloWorld, ma da uno degli intercettatori di Struts, ovvero quello che gestisce l'internazionalizzazione delle pagine. Il parametro request_locale verrà riconosciuto ed elaborato. La lingua delle pagine diventerà l'inglese (en).
- riga 19: definisce un link HTML. L'attributo href del tag <a> richiede una stringa di caratteri. In questo caso, si desidera utilizzare il valore di URL definito alla riga 16 e con id URL. A tal fine, si scrive href="%{URL}". La variabile URL viene valutata e il suo valore assegnato all'attributo href. Nella maggior parte dei casi, la valutazione delle variabili è implicita. Ad esempio, quando si scrive
viene visualizzato il valore della proprietà message e non la stringa " message ". In altri casi, tuttavia, è necessario forzare la valutazione delle variabili o delle proprietà. Se avessimo scritto href="URL", sarebbe stata assegnata la stringa URL all’attributo href.
- righe 23-27: creano un link HTML per cambiare la lingua delle pagine in spagnolo.
2.8. Esecuzione dell’applicazione
Avviamo l’esecuzione del progetto:
![]() |
- in [1], si avvia l'esecuzione del progetto [exemple-01]. Il server web Tomcat viene quindi avviato automaticamente, se non era già in esecuzione. Viene richiesta la pagina URL [/exemple-01] [3]. Viene quindi utilizzato il file [web.xml]:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<URL-pattern>/*</URL-pattern>
</filter-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>example/HelloWorld.JSP</welcome-file>
</welcome-file-list>
</web-app>
- poiché nel file URL richiesto ([/exemple-01]) non è specificata alcuna pagina, Tomcat utilizzerà il tag <welcome_file-list> delle righe 16 e 18. Sarà quindi visualizzata la pagina URL /esempio-01/example/HelloWorld.JSP.
- Poiché Struts 2 elabora tutte le URL (righe 8 e 9), questa URL verrà filtrata da Struts. Poiché non corrisponde a un’azione ma a una pagina JSP, quest’ultima verrà visualizzata.
- Quello che vediamo in [2] è quindi la pagina HelloWorld.JSP che abbiamo esaminato.
- In [4], si nota che né il tag <title><s:text name="HelloWorld.message"/></title> né il tag <h2><s:property value="message"/></h2> hanno prodotto il loro effetto. Il motivo è che non è stata richiamata alcuna azione. L’elenco degli intercettatori che vengono eseguiti prima dell’azione non è stato quindi eseguito, in particolare quello che gestisce l’internazionalizzazione. Il tag di internazionalizzazione <s:text ...> non è stato elaborato correttamente. Inoltre, la proprietà message che fa riferimento al campo message della classe Action1 non esiste. Da qui l'assenza di visualizzazione.
Ora seguiamo il link [English]. Otteniamo la seguente pagina:
![]() |
- in [1], ovvero il URL richiesto. Abbiamo spiegato la formazione di questo URL. Questa volta viene richiesta un’azione Struts: l’azione HelloWorld definita in [example.xml].
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="HelloWorld" class="example.HelloWorld">
<result>/example/HelloWorld.JSP</result>
</action>
</package>
</struts>
- è stato eseguito il metodo execute di questa azione. Abbiamo visto che restituiva la chiave success. Dalla riga 4 sopra riportata, si deduce che la pagina /example/HelloWorld.JSP viene restituita come risposta al client. È ciò che vediamo in [3].
- In [1], vediamo che la pagina URL richiesta è configurata dal parametro request_locale=en. La lingua delle pagine sarà d'ora in poi l'inglese. Infatti, questa scelta di lingua viene memorizzata nella sessione dell'utente, che manterrà tale impostazione fino a quando non la modificherà.
- Nei tag [2] e [3] si vede l'internazionalizzazione all'opera. I tag <title><s:text name="HelloWorld.message"/></title> e <h2><s:property value="message"/></h2> questa volta hanno sortito l'effetto desiderato.
Se ora selezioniamo il link [Espanol], otteniamo la pagina in spagnolo:
![]() |
2.9. Conclusion
Abbiamo esaminato un esempio generato automaticamente dal plugin Struts 2 per NetBeans. Abbiamo constatato che era piuttosto difficile seguire l’elaborazione di una richiesta. Sono coinvolti i seguenti elementi:
- la configurazione [web.xml], [struts.xml]
- l'azione eseguita: intercettatori e metodo execute.
All’inizio, il funzionamento di Struts 2 può sembrare complesso. Ci vuole un po’ di tempo per abituarsi. Presenteremo ora una serie di esempi che illustrano ciascuno un aspetto specifico di Struts.















