2. Un primo esempio
La maggior parte dei nostri esempi si limiterà al livello web implementato con Struts 2:
![]() |
Una volta trattate le nozioni di base, esamineremo un esempio più complesso con un'architettura multilivello.
2.1. Generazione dell'esempio
Stiamo realizzando la nostra prima applicazione.
![]() |
- In [1], creiamo un nuovo progetto
- In [2], selezioniamo il tipo Java Web / Applicazione Web
- In [3], assegniamo un nome al progetto
- In [4], specificare la posizione del progetto.
- In [5], impostiamo il nuovo progetto come progetto principale.
![]() |
- In [6], selezionare il server Tomcat. Quando è stato installato NetBeans 7.01, sono stati installati due server: Apache Tomcat e GlassFish 3.1.
- In [7], specificare che si lavorerà con il framework Struts 2. Questa opzione è disponibile perché è stato installato il plugin Struts 2. Senza il plugin, il framework Struts 2 non viene offerto.
- In [8], richiediamo la creazione del progetto di esempio che studieremo.
- 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 file system
![]() |
- In [1], la scheda [Progetti] mostra una vista "sviluppatore" del progetto
- In [2], la scheda [Files] mostra la cartella del progetto nel file system
- In [2A], il ramo [Pagine Web] è rappresentato in [2] dalla cartella [web] [2B]
- In [3A], il ramo [Pacchetti sorgente] è 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 è /example-01. Tutti gli URL del tipo [http://machine:port/exemple-01/...] saranno gestiti da questa applicazione. Questo contesto si trova nelle proprietà del progetto [2]: clicca con il tasto destro sul progetto / Proprietà / Esegui.
2.4. Il file di configurazione [WEB-INF/web.xml]
![]() |
Ogni applicazione web viene configurata dal file [web.xml] presente nella cartella [WEB-INF] dell'applicazione. Quello 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 Struts 2 [org.apache.struts2.dispatcher.FilterDispatcher]. Questa classe funge da Controller (C) nel modello MVC.
- Righe 7–10: definiscono una mappatura tra un modello di URL e il filtro che deve gestire gli URL corrispondenti a tale modello. Qui si specifica che qualsiasi URL (modello /*) deve essere gestito dal filtro denominato struts2. Si tratta del filtro definito nelle righe 3–6. Pertanto, tutti gli URL passeranno attraverso il controller Struts 2.
- Righe 11–15: definiscono la durata di una sessione utente, qui impostata a 30 minuti. Durante le varie richieste, un utente viene tracciato da un token di sessione assegnatogli al momento della sua prima richiesta, che poi invia sistematicamente con ogni nuova richiesta. Ciò consente al server web di riconoscere l'utente e di gestire una "memoria" per lui, nota come sessione. Se tra due richieste trascorrono più di 30 minuti, viene generato un nuovo token di sessione per l'utente, che in tal modo perde la sua "memoria" e ne avvia una nuova.
- Righe 16–18: definiscono il file da visualizzare quando l'utente accede all'applicazione web senza richiedere un documento. Pertanto, quando l'URL richiesto è [http://machine:port/exemple-01], l'URL servito 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 punto 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. È prassi comune collocare [struts.xml] nel <pacchetto predefinito>. Qui, 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"/>
<!-- Configuration for the default package. -->
<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. Torneremo su questo punto più avanti.
- Righe 8–9: qui si definisce un pacchetto denominato "default". Un pacchetto consente di configurare un gruppo di azioni Struts 2 che condividono lo stesso URL. Ad esempio, [/path/Action1] e [/path/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 "employees" e configura le azioni con l'URL /employees/Action. Un pacchetto può ereditare da un altro pacchetto utilizzando la parola chiave "extends". Nell'esempio sopra riportato, il pacchetto "employees" eredita dal pacchetto "struts-default". Questo pacchetto si trova nel file [struts-default.xml] all'interno della libreria struts2-core.jar:
![]() |
Il pacchetto "struts-default" definito nel file [struts-default.xml] configura vari elementi, tra cui un elenco di intercettatori eseguiti quando viene chiamata un'azione. Torniamo alla struttura MVC di un'applicazione Struts 2:
![]() |
Per elaborare un URL del tipo [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 chiamato execute. La chiamata a questo metodo execute passerà attraverso una serie di intercettatori:
![]() |
Gli intercettatori e l'azione elaborano tutti la stessa richiesta. L'elenco degli intercettatori definiti 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 vari intercettatori, consultare 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"/>
<!-- Configuration for the default package. -->
<package name="default" extends="struts-default">
</package>
</struts>
- Riga 8: Il pacchetto denominato "default" ha un ruolo speciale. Gestisce le azioni che non sono state configurate negli altri pacchetti. Qui, nelle righe 8–9, non è specificata alcuna configurazione per il pacchetto "default". Potremmo quindi rimuovere la definizione di questo pacchetto.
Ora diamo un'occhiata al 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 gli URL del tipo /example/Action (namespace /example).
- Righe 9–11: definiscono un'azione denominata HelloWorld (attributo name) che corrisponde all'URL /example/HelloWorld. Questa azione è gestita da un'istanza della classe example.HelloWorld (attributo class).
- Il controller [FilterDispatcher] eseguirà il metodo execute di questa classe.
- Questo metodo restituirà una stringa denominata chiave di navigazione.
- Le varie chiavi di navigazione devono essere definite utilizzando i tag <result name="key"/> (riga 10). Se l'attributo name viene omesso, viene utilizzata per impostazione predefinita la chiave success. Questo è il caso sopra riportato. Pertanto, il metodo execute della classe example.HelloWorld deve restituire la chiave success al controller [FilterDispatcher].
- Il controller [FilterDispatcher] visualizza quindi la pagina [/example/HelloWorld.jsp] (riga 10).
Se uniamo i due file [struts.xml] e [example.xml] e rimuoviamo il pacchetto predefinito, che sembra superfluo, è come se avessimo ridotto il file [struts.xml] al solo file [example.xml].
2.6. L'azione HelloWorld
![]() |
Secondo il file [struts.xml] che abbiamo esaminato, l'azione HelloWorld viene attivata quando l'URL richiesto dal client è /example/HelloWorld. Viene quindi eseguito il suo metodo execute. Deve restituire una chiave di navigazione. Abbiamo visto che ce n'era solo una: success, e che la pagina /example/HelloWorld.jsp veniva inviata in risposta all'utente.
Il codice per l'azione HelloWorld è il seguente:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorld extends ActionSupport {
public String execute() throws Exception {
setMessage(getText(MESSAGE));
return SUCCESS;
}
public static final String MESSAGE = "HelloWorld.message";
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
- Riga 5: La classe HelloWorld estende la classe ActionSupport di Struts 2. Questo avviene quasi sempre. Ciò ci permette di utilizzare determinati 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, da qui la sua firma alla riga 7. Qui, restituisce la costante `SUCCESS`, che è definita anche in `ActionSupport`. Altre costanti sono definite allo stesso modo per il risultato del metodo `execute`:
SUCCESS | "success" |
ERRORE | "errore" |
IMMESSIONE | "input" |
LOGIN | "login" |
Quindi, in questo caso, il metodo execute restituisce la stringa "success". Facendo riferimento al file [struts.xml], ciò significa che all'utente verrà restituita la pagina /example/HelloWorld.jsp.
- Riga 8: Il metodo `execute` inizializza il campo `message` alla riga 14 con il valore restituito da `getText("HelloWorld.message")`. Il metodo `getText` appartiene alla classe padre `ActionSupport`. Esso recupera il testo da un file in base alla lingua utilizzata. Per impostazione predefinita, verrà utilizzato il file `package.properties` situato nello stesso pacchetto dell'azione. Questo file è disponibile in due versioni:
Il file [package.properties] è il seguente:
È costituito da una serie di righe di testo nel formato chiave=valore. Se si utilizza questo file, getText("HelloWorld.message") restituirà il valore Struts è attivo e funzionante ...
Il file [package_es.properties] è il seguente:
Se la lingua utilizzata dal browser del cliente è lo spagnolo (l'attributo "es" in package_es.properties), getText("HelloWorld.message") restituirà il valore ¡Struts está bien! ... In tutti gli altri casi, verrà utilizzato il file [package.properties].
2.7. La vista HelloWorld.jsp
![]() |
Questo è l'ultimo tassello del puzzle Struts. È la vista che viene visualizzata quando viene richiesta l'URL /example/HelloWorld. Abbiamo visto il percorso che la richiesta iniziale ha seguito per visualizzare infine 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 provenienti da una libreria definita alla 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 specifica la chiave da cercare nei file dei messaggi. Anche in questo caso verranno utilizzati i file package_xx.properties. Ricordiamo che contengono un solo messaggio con la chiave HelloWorld.message.
- Riga 11: Il tag <s:property name="property"> viene utilizzato per scrivere il valore di una proprietà di un oggetto chiamato ActionContext. Questo oggetto contiene:
- le proprietà dell'azione che è stata eseguita. name="message" visualizzerà il valore del campo message dell'azione corrente. I metodi get e set associati al campo vengono utilizzati per recuperarne il valore o per inizializzarlo. Questi metodi devono quindi esistere.
- gli attributi della richiesta corrente indicati come <s:property name="#request['key']">
- gli attributi della sessione dell'utente, indicati come <s:property name="#session['key']">
- gli attributi dell'applicazione stessa, indicati come <s:property name="#application['key']">
- i parametri inviati dal browser del client, indicati come <s:property name="#parameters['key']">
- La notazione <s:property name="#attr['key']"> visualizza il valore di un oggetto cercato nella pagina, nella richiesta, nella sessione e nell'applicazione, in quest'ordine.
- Righe 16–18: Il tag <s:url> viene utilizzato per definire un URL. L'attributo id assegna un nome all'URL che verrà creato. Questo nome viene poi utilizzato alla riga 19. L'attributo action specifica a quale azione deve puntare l'URL.
- Riga 17: Il tag <s:param ..> consente di aggiungere parametri all'URL nel formato ?param1=value1¶m2=value2&... In questo caso, il parametro aggiunto sarà ?request_locale=es.
Alla fine, l'URL generato sarà il seguente:
Per comprendere questo URL, ricorda che la pagina [HelloWorld.jsp] viene visualizzata in due casi:
- su richiesta diretta dell'URL [/example-01/example/HelloWorld.jsp]
- quando viene richiesta l'azione [/example-01/example/HelloWorld.action]
In entrambi i casi, il percorso dell'URL è /example-01/example. Il tag <s:url action= "... "> aggiunge a questo percorso l'azione definita dall'attributo action. Il risultato è /example-01/example/HelloWorld. Aggiunge quindi il suffisso .action all'URL precedente, insieme a eventuali parametri URL, se presenti. L'URL risultante /example-01/example/HelloWorld.action?request_locale=en richiamerà l'azione HelloWorld definita nel file [struts.xml] passando il parametro request_locale=en. Questo parametro non verrà elaborato dall'azione HelloWorld ma da uno degli intercettatori di Struts, in particolare quello che gestisce l'internazionalizzazione delle pagine. Il parametro request_locale verrà riconosciuto ed elaborato. La lingua della pagina passerà all'inglese (en).
- Riga 19: definisce un link HTML. L'attributo href del tag <a> richiede una stringa. Qui, vogliamo utilizzare il valore dell'URL definito alla riga 16 con l'id "url". Per farlo, scriviamo href="%{url}". La variabile url viene valutata e il suo valore viene assegnato all'attributo href. Nella maggior parte dei casi, la valutazione delle variabili è implicita. Ad esempio, quando scriviamo
<s:property name="message"/>
viene visualizzato il valore della proprietà message, non la stringa "message". Ma in altri casi, è necessario forzare la valutazione delle variabili o delle proprietà. Se avessimo scritto href="url", la stringa "url" sarebbe stata assegnata all'attributo href.
- Righe 23–27: creano un link HTML per cambiare la lingua della pagina in spagnolo.
2.8. Esecuzione dell'applicazione
Avviamo il progetto:
![]() |
- In [1], eseguiamo il progetto [example-01]. Il server web Tomcat viene quindi avviato automaticamente, se non lo era già. Viene richiesta l'URL [/example-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é l'URL richiesto [/example-01] non specifica una pagina, Tomcat utilizzerà il tag <welcome_file-list> alle righe 16 e 18. Pertanto, verrà servito l'URL /example-01/example/HelloWorld.jsp.
- Poiché Struts 2 elabora tutti gli URL (righe 8 e 9), questo URL verrà filtrato da Struts. Dato che non corrisponde a un'azione ma a una pagina JSP, verrà visualizzata quest'ultima.
- Quello che vediamo in [2] è quindi la pagina HelloWorld.jsp che abbiamo studiato.
- In [4], vediamo che il tag <title><s:text name="HelloWorld.message"/></title> non ha avuto effetto, né il tag <h2><s:property value="message"/></h2>. Il motivo è che non è stata chiamata 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 ha potuto essere elaborato correttamente. Inoltre, la proprietà message, che fa riferimento al campo message della classe Action1, non esiste. Da qui la mancata visualizzazione.
Ora, seguiamo il link [English]. Otteniamo la seguente pagina:
![]() |
- in [1], l'URL richiesto. Abbiamo spiegato come si forma 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>
- Il metodo execute di questa azione è stato eseguito. Abbiamo visto che ha restituito la chiave "success". Dalla riga 4 sopra, possiamo dedurre che la pagina /example/HelloWorld.jsp viene restituita al client. Questo è ciò che vediamo in [3].
- In [1], vediamo che l'URL richiesto è impostato dal parametro `request_locale=en`. La lingua delle pagine sarà ora l'inglese. Infatti, questa scelta di lingua viene memorizzata nella sessione dell'utente, che manterrà questa scelta fino a quando l'utente non la modificherà.
- In [2] e [3], vediamo l'internazionalizzazione in azione. I tag <title><s:text name="HelloWorld.message"/></title> e <h2><s:property value="message"/></h2> hanno avuto effetto questa volta.
Se ora selezioniamo il link [Espanol], otteniamo la pagina in spagnolo:
![]() |
2.9. Conclusione
Abbiamo esaminato un esempio generato automaticamente dal plugin Struts 2 per NetBeans. Abbiamo riscontrato che era piuttosto difficile seguire l'elaborazione di una richiesta. Sono coinvolti i seguenti elementi:
- la configurazione [web.xml], [struts.xml]
- l'azione eseguita: gli intercettatori e il 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, ciascuno dei quali illustra un aspetto specifico di Struts.















