Sei sulla pagina 1di 42

Guida Apache Struts

Indice generale

Introduzione.....................................................................................................................................4

Perché usare Struts...........................................................................................................................4 Il design pattern MVC.....................................................................................................................4 Componenti e gestione delle richieste in Struts...............................................................................5 Il ciclo di vita delle richieste............................................................................................................6 Creare un progetto Struts con Eclipse..............................................................................................7 Struttura di una semplice applicazione............................................................................................7 Il deployment descriptor per Struts..................................................................................................9 Configurare la ActionServlet.........................................................................................................10 Il mapping delle servlet..................................................................................................................11 La taglib.........................................................................................................................................11 Pagina di benvenuto ed errori........................................................................................................11 Il file di configurazione 'struts-config.xml'....................................................................................11

global-forwards..............................................................................................................................12

form-beans.....................................................................................................................................13

action-mappings.............................................................................................................................13

message-resources.........................................................................................................................14

plug-in............................................................................................................................................14

File di configurazione multipli......................................................................................................15 Hello World con Struts...................................................................................................................15 Regole e consigli per scrivere applicazioni con Struts..................................................................17 Processo di sviluppo......................................................................................................................18 Scrivere il markup solo nelle viste.................................................................................................18 Tutte le Action finiscono con il .do................................................................................................18 Sui jar.............................................................................................................................................18 Test e configurazione.....................................................................................................................19

ActionServlet.................................................................................................................................19

La classe ActionServlet e il RequestProcessor..............................................................................19 Configurare l'ActionServlet...........................................................................................................20 Le Action........................................................................................................................................21 Creare una Action..........................................................................................................................21 Il metodo execute()........................................................................................................................22 Azioni HTTP e Custom.............................................................................................................22

ActionForward...............................................................................................................................22

Configurazione della classe Action................................................................................................23

DispatchAction..............................................................................................................................24

LookupDispatchAction..................................................................................................................26

Forward Action..............................................................................................................................29

Esempio.........................................................................................................................................29

Link a forward globali...................................................................................................................30 Forward Attribute vs. ForwardAction............................................................................................31 Forward per accesso Legacy..........................................................................................................31 MappingDispatchAction e altre Action già pronte........................................................................33

MappingDispatchAction................................................................................................................33

BaseAction.....................................................................................................................................34

IncludeAction.................................................................................................................................34

Il RequestProcessor........................................................................................................................34 I Plugin...........................................................................................................................................36

init()...............................................................................................................................................36

destroy().........................................................................................................................................36

Creare un Plugin............................................................................................................................37 Le taglib di struts...........................................................................................................................38 Jsp Custom Tag..............................................................................................................................38 Utilizzare una taglib.......................................................................................................................39 La HTML taglib.............................................................................................................................39 Tag generici per la formattazione e la navigazione.......................................................................39 Il tag <html:html>.....................................................................................................................40 Tag per i form................................................................................................................................40 Il tag <html:form>.....................................................................................................................40 Gli eventi JavaScript......................................................................................................................41 Bean taglib e gestione dei messaggi..............................................................................................41 Bean taglib e gestione dei messaggi...................................................................................................41 Il tag <bean:message>: la gestione dei messaggi..........................................................................41

Introduzione

Apache Struts è un progetto open source sponsorizzato dalla Apache Software Foundation ed è un'implementazione Java server-side del design pattern MVC (Model View Controller).

Il progetto Struts è nato con l'intenzione di implementare un framework open-source per la creazione di applicazioni Web che permettesse la separazione del livello di presentazione e che fosse, allo stesso tempo, astratto dai vari livelli di dati e dalle transazioni.

Nato nel 2000 per opera di Craig R. McClanahan (http://blogs.sun.com/craigmcc/), la popolarità del framework è cresciuta enormemente nel corso degli ultimi anni. Dopo il rilascio di Struts 1.1, nel giugno 2003, Struts è diventato uno degli scenari più importanti per lo sviluppo di complesse applicazioni web basate su JSP.

Nel 2008 nasce Struts 2, che si differenzia parecchio dalla prima versione: questa release non segue infatti il progetto originale, ma è una evoluzione di WebWork (http://www.opensymphony.com/webwork/), il framework open source, parte del progetto OpenSymphony. Per questo motivo la migrazione tra la versione 1 e la versione 2 non è semplice. In questa guida ci occuperemo della versione 1 del progetto e analizzeremo la versione 2 per differenze con la prima.

Perché usare Struts

Questo framework semplifica notevolmente la vita di un programmatore, sia in fase di sviluppo, che di revisione e di configurazione delle proprie applicazioni.

L'utilizzo di Struts supporta vantaggi significativi in termini del progetto:

Modularità e Riusabilità: i diversi ruoli dell'applicazione sono affidati a diversi

componenti. Ció consente di sviluppare codice modulare e più facilmente riutilizzabile Manutenibilità: l'applicazione è costituita da livelli logici ben distinti. Una modifica in uno

dei livelli non comporta modifiche negli altri Rapidità di sviluppo: è possibile sviluppare in parallelo le varie parti dell'applicazione, logica di business e di view

Il design pattern MVC

Iniziamo esaminando le 3 componenti alla base del design pattern MVC:

Componente

Descrizione

Model

Rappresenta i dati, tipicamente persistenti su database, attraverso oggetti, questa rappresentazione ci permette di manipolare e il modello dei dati in modo semplificato

View

È lo strato più esterno, quello di presentazione. È qui che definiamo l'interfaccia utente, forniamo una rappresentazione del modello dei dati e riceviamo richieste dall'esterno.

Controller

È il componente che contiene la logica di business. Qui gestiamo le interazioni con l'interfaccia, istradiamo le richieste, preleviamo i dati dal Model e stabiliamo quale View dovrà rappresentarli e come.

Figura 1. Model View Controller

Questo approccio si preoccupa di separare la responsabilità nelle web application. Una richiesta client viene intercettata

Questo approccio si preoccupa di separare la responsabilità nelle web application. Una richiesta client viene intercettata dal Controller, attraverso il Model vengono forniti tutti i metodi per accedere ai dati dell'applicazione e quindi per elaborare la risposta e visualizzarla attraverso i componenti View.

Il componente più importante è quindi il Controller ed è la parte fondamentale del framework. La potenza di questo sistema sta, infatti, nella possibilità di scegliere diverse tecnologie per implementare le classi del Model (dal più comune dei DAO a ORM di vario genere come Hibernate (http://java.html.it/articoli/leggi/2421/introduzione-ad-hibernate/)) e il View Engine che si preferisce (JSP, Velocity, etc.).

Nel corso della guida analizzeremo i principali componenti di un'applicazione basata su Struts suddividendoli in componenti model, view e controller; poi passeremo alla configurazione di un applicazione web, descriveremo le funzionalità più importanti offerte da questo framework e infine analizzeremo i concetti principali della nuova versione del progetto.

Componenti e gestione delle richieste in Struts

Struts, come ogni application framework, è un insieme di classi e interfacce che costituiscono lo scheletro per costruire le nostre Web application. In questa lezione iniziamo ad esaminare i componenti fondamentali e il ciclo di vita delle richieste.

Componente

ActionServlet

struts-config.xml

Action

ActionMapping

ActionForm

ActionForward

Descrizione

È la servlet di controllo che gestisce tutte le richieste dell'applicazione. Come tutte le servlet estende la classe javax.servlet.http.HttppServlet e quindi implementa tutti i metodi di lifecycle, incluso init(), doGet(), doPost() ed il destroy È il cuore di tutta l'applicazione. In questo file XML possiamo definire i vari elementi dell'applicazione e le loro associazioni. Viene letto in fase di start-up dell'applicazione dalla ActionServlet Le Action sono le classi alle quali le ActionServlet delegal'elaborazione della richiesta Contiene gli oggetti associati ad una Action nello struts-config come ad esempio gli ActionForward Sono considerati dei veri contenitori di dati. Fanno riferimento ad uno specifico form e vengono popolati automaticamente dal framework con i dati contenuti nella request HTTP Contengono i path ai quali la servlet di Struts inoltra il flusso in base alla logica

Custom-tags

dell'applicazione

Sono tag particolari forniti dal framework Struts per assolvere a molti dei più comuni compiti delle pagine JSP

Il ciclo di vita delle richieste

Vediamo questi componenti all'opera, esaminando il flusso elaborativo che viene innescato in Struts da una richiesta. Per farlo ci serviamo di un semplice schema:

Figura 1. Flusso Elaborativo di Struts

Custom-tags dell'applicazione Sono tag particolari forniti dal framework Struts per assolvere a molti dei più comuni

Come abbiamo detto il controller ha la responsabilità di ricevere l'input da un client, invocare le operazioni necessarie alla logica applicativa e coordinare la vista da restituire al client. In altre parole contiene tutte la logica di business.

Il componente Model fornisce gli oggetti necessari alla logica di business per astrarre la persistenza dei dati. Infine le view rappresentano il modo di interagire dell'applicazione con l'utente sia in fase di richiesta che in fase di risposta.

I dati per la configurazione sono stati letti dallo struts-config.xml in fase di startup (0

)

il Client invia una richiesta HTTP (1)

la richiesta quale viene ricevuta dalla servlet di Struts che provvede a popolare l'ActionForm

associato alla richiesta con i dati della request (2) e l'ActionMapping associata alla richiesta (4) L'Action Servlet delega l'elaborazione dati alla relativa Action (3) passandole in input gli

oggetti con request e response HTTP, l'ActionForm e l'ActionMapping precedentemente valorizzati La Action compie la logica di business e rende permanente lo stato dell'applicazione

colloquiando con il Model (5) Al termine dell'elaborazione restituisce alla ActionServlet un ActionForward (6) contenente il

path della vista da fornire all'utente La Action esegue il forward alla vista specifica nell'ActionForward (7)

Questo flusso di operazioni non è completo e in prima battuta sembra un po' confusionario, ma ci sarà utile come mappa, per avere presenti gli attori che vengono coinvolti nella elaborazione delle richieste in un'applicazione.

Creare un progetto Struts con Eclipse

Nelle prime lezioni abbiamo fornito una visone d'insieme del framework, che ci sarà utile per approfondire i concetti nel corso della guida. In questa lezione iniziamo a prendere confidenza con l'infrastruttura di Struts e ci cimentiamo con un primo, semplice, progetto.

Prima di iniziare con la configurazione della nostra prima applicazione, è utile ricordare che esistono due filoni di sviluppo del framework corrispondenti alle versioni 1 e 2 Struts. Tratteremo delle differenze tra le due versioni in seguito, per ora concentriamoci sulla prima, che sarà argomento predominante della guida. Per prima cosa quindi scarichiamo l'ultima release di Struts 1

(http://struts.apache.org/download.cgi#struts1310).

Figura 2. Download della versione 1.3.10

Questo flusso di operazioni non è completo e in prima battuta sembra un po' confusionario, ma

Struts è distribuito sia sotto forma di codice sorgente (source), sia tramite i "file binari" (full distribution). Scaricare il codice sorgente garantisce un maggior controllo sull'ambiente in cui si effettua la compilazione, ma non è adatto ai principianti. Se non si hanno particolari esigenze (come la modifica o l'inclusione di una classe java nella propria installazione), si può tranquillamente usare la distribuzione binaria.

Per i nostri esempi utilizziamo la "distribuzione binaria". Possiamo quindi cliccare sul link sotto Full Distribution.

Una volta estratto l'archivio, troviamo diverse cartelle. Il framework è composto da circa 300 classi Java, divise in otto package principali (il numero delle classi è approssimativo perché il framework subisce di continuo aggiunte e aggiustamenti).

Struttura di una semplice applicazione

Per esaminare la struttura delle cartelle di una semplice applicazione Struts possiamo servirci dei

file .war di esempio che troviamo nella cartella apps dell'archivio estratto.

Questi esempi risultano parecchio interessanti soprattutto per chi inizia. Infatti, per entrare nella logica di Struts e applicare il ciclo di vita delle richieste, che abbiamo mostrato nella lezione precedente, è utile esaminare la struttura delle cartelle di un progetto.

Per farlo abbiamo diverse possibilità: possiamo ad esempio rinominare il file struts-blank- 1.x.x.war in ProvaStruts.war ed effettuare il deploy su un container come Tomcat o JBoss.

Una alternativa ancora più semplice è quella di utilizzare un tool come Eclipse per effettuare le nostre prove e, siccome siamo nell'ambito di applicazioni JEE, scarichiamo Eclipse per sviluppatori JEE (http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/galileor)

Possiamo importare il progetto in Eclipse da menu File -> Import e scegliendo il formato Web

Figura 3. Importare il file .war in Eclipse

file .war di esempio che troviamo nella cartella apps dell'archivio estratto. Questi esempi risultano parecchio interessanti

Ogni applicazione Web J2EE al di sotto della cartella in cui viene installata (ad esempio webapp di Tomcat) rispetta una struttura simile a quella che troviamo anche nel nostro progetto su Eclipse:

WebContent

|

|

|

|

|

|

|

|

(da considerarsi la 'root' dell'applicazione)

| +-- WEB-INF |

+-- src

(contiene il codice delle nostre servlet)

|

+-- classes

|

+-- lib

(qui ci sono le librerie del framework Struts)

|

+-- tags

|

+-- META-INF

|

+-- pages

(contiene le JSP per le viste)

Figura 4. Struttura delle cartelle

Alcuni di questi contenitori come WEB-INF sono fissi, ma possiamo personalizzare le altre directory modificando il

Alcuni di questi contenitori come WEB-INF sono fissi, ma possiamo personalizzare le altre directory modificando il file di configurazione della nostra applicazione. Ricapitolando:

WebContent è la root dell'applicazione. Qui possiamo inserire le nostre pagine dinamiche

(le viste JSP) organizzate in cartelle e tutta la parte statica del sito come le pagine HTML, i fogli di stile e le immagini. WEB-INF contiene i sorgenti delle azioni e i file di configurazione xml

lib contiene le librerie del framework e gli altri JAR utili all'applicazione. In generale,

quando non abbiamo uno strumento automatico a farlo per noi, dobbiamo copiare la cartella lib che troviamo nell'archivio di Struts all'interno della nostra applicazione classes: una cartella contenente le classi compilate dell'applicazione organizzate in cartelle corrispondenti alla struttura dei package

Il deployment descriptor per Struts

Il web.xml è il descrittore di deploy usato per configurare qualsiasi Web application sviluppata con tecnologia J2EE (http://java.html.it/guide/leggi/136/guida-j2ee/), quindi anche un'applicazione Struts avrà il suo descrittore. In più, per la configurazione di una applicazione Struts, abbiamo bisogno di un secondo file, parimenti importante: lo struts-config.xml.

In questa lezione però analizziamo i passi necessari a scrivere un web.xml per Struts, mentre approfondiremo lo struts-config.xml nella prossima lezione.

Il file web.xml contiene le informazioni di configurazione necessarie all'application server, per caricare i componenti necessari all'avvio dell'applicazione.

Questo file serve infatti a descrivere tutti i componenti dell'applicazione Web, contiene informazioni come:

Parametri ed inizializzazione ServletContext

Contenuto localizzato

Configurazione della sessione

Definizione Servlet/JSP

Mapping Servlet/JSP

Riferimenti a tag library

Mappature a tipi MIME

Lista di file di Welcome

Pagine di errore

Informazioni sulla sicurezza

Se lo apriamo con un tool come Eclipse, riusciamo ad esaminarne meglio le aree principali:

Figura 5. Web.xml su Eclipse

Se lo apriamo con un tool come Eclipse, riusciamo ad esaminarne meglio le aree principali: Figura

Una curiosità interessante: Eclipse mette in verdino, vicino ad ogni tag, i tag children previsti dal suo XML Schema.

Sebbene oggi gli ambienti di sviluppo provvedano alla compilazione automatica di questo file, è sempre bene conoscerne la struttura. Perciò possiamo provare a creare un file web.xml per la nostra applicazione, a partire da uno vuoto:

<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web app_2_3.dtd">

<web-app>

</web-app>

Configurare la ActionServlet

Il primo passo, uno dei più importanti, consiste nel configurare la ActionServlet che si occuperà di ricevere e smistare tutte le richieste dell'applicazione (il nostro controller). Quindi provvediamo a configurare l'istanza della servlet nel seguente modo:

<servlet>

<servlet-name>action</servlet-name>

<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

<init-param>

<param-name>config</param-name>

<param-value>/WEB-INF/struts-config.xml</param-value>

</init-param>

</servlet>

È importante notare che abbiamo associato alla servlet il file di configurazione (struts- config.xml), che, in questo modo, sarà caricato all'avvio dell'applicazione.

Il mapping delle servlet

Il passo successivo, necessario a configurare la servlet controller di Struts nel web.xml, lo compiamo scrivendo il "mapping delle servlet". Utilizziamo l'elemento <servlet-mapping> nel seguente modo:

<servlet-mapping>

<servlet-name>action</servlet-name>

<url-pattern>*.do</url-pattern>

</servlet-mapping>

In altre parole abbiamo detto all'application server di girare tutte le richieste che hanno il suffisso .do, alla servlet ActionServlet.

La taglib

Struts mette a disposizione dei tag JSP e per utilizzarli dobbiamo dichiarane l'uso all'avvio dell'applicazione. Per farlo elenchiamo le librerie di tag nel web.xml, grazie all'elemento <taglib>:

<taglib>

<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>

<taglib-location>/WEB-INF/struts-html.tld</taglib-location>

</taglib>

In questo caso abbiamo dichiarato la libreria struts-html ma come vedremo più avanti non è l'unica messa a disposizione da Struts.

Pagina di benvenuto ed errori

Infine nel deployment descriptor, anche se non vale per le applicazioni che usano Struts, può essere gestita la pagina di benvenuto dell'applicazione:

<welcome-file-list>

<welcome-file>index.jsp</welcome-file>

</welcome-file-list>

e gli errori HTTP, inserendo i relativi codici (404, 500, etc.):

<error-page>

<error-code>404.jsp</error-code>

<location>404.jsp</location>

</error-page>

Per effettuare prove o verifiche è ecco un esempio completo di web.xml (img/xeb.xml.html) per un'applicazione Struts.

Il file di configurazione 'struts-config.xml'

Per caricare e creare all'avvio tutti i componenti necessari all'applicazione, Struts fa riferimento ad un file di configurazione chiamato struts-config.xml. Questo file ci permette di specificare in maniera dichiarativa il comportamento dei componenti del framework, evitando che le informazioni e il comportamento siano inseriti rigidamente nel codice delle applicazioni.

Questo fornisce agli sviluppatori la flessibilità necessaria ad inserire le proprie estensioni, che il framework può utilizzare in maniera dinamica.

Lo stuts-config si basa sul formato XML e può essere validato con il DTD di Struts, analizziamone la struttura.

Il tag root dello struts-config è <struts-config>, all'interno del quale troviamo cinque sezioni:

global-forwards

form-beans

action-mappings

message-resources

plug-in

In questa lezione le presentiamo brevemente, ma ce ne occuperemo più approfonditamente nel corso della guida.

global-forwards

In questa sezione possiamo creare delle associazioni tra particolari nomi (che specificano azioni del controller) e i relativi percorsi (che specificano delle viste), stabilendo dei forward validi a livello "globale" nell'applicazione.

In altre parole non si fa altro che mappare le condizioni di ritorno di una richiesta con particolari Jsp. Lo facciamo utilizzando un elemento <forward> per ogni associazione, grazie alle proprietà name e path.

Un esempio può essere dato da una pagina globale per gli errori, scrivendo una entry nel global- fowards in questo modo:

<global-forwards> <forward name="error" path="/error.jsp"/> </global-forwards>

Grazie a questa configurazione, quando in caso di errore viene richiamata l'action error, l'applicazione inoltra la richiesta dell'utente alla Jsp con path /error.jsp.

Analizziamo gli attributi più importanti per configurare un global-forward:

Attributo

Descrizione

Serve a dichiarare la classe che estende il bean di configurazione e che manterrà className tutte le informazioni di forward. Se non specificata, la classe predefinita sarà org.apache.struts.action.ForwardConfig

Name

path

È il nome (unico) che servirà a riferirsi a questo forward nell'applicazione. Questo attributo è obbligatorio

È l'URI verso cui dovrebbe avvenire il forward. È un attributo obbligatorio e deve cominciare con il carattere "/"

form-beans

La seconda parte serve a definire i form bean, particolari classi che contengono i dati inseriti in un form all'interno di una Jsp. Si dichiara uno o più form bean nel seguente modo:

<form-beans> <form-bean name=" </form-beans>

"

...

type="

"

...

/>

Ecco gli attributi più importanti per configurare un form bean:

Attributo

Descrizione

className Quando non si vuole utilizzare il bean di configurazione standard di Struts, bisogna specificare in questo attributo la classe creata nell'applicazione che la sostituisce

Name

Type

È il nome (unico) che servirà a riferirsi a questo form bean in tutta l'applicazione. Questo attributo è obbligatorio

Il nome di una classe Java che estende la classe ActionForm di Struts

Analizzeremo meglio la struttura e le tipologie dei form bean nei capitoli successivi.

action-mappings

In questa sezione definiamo le action. Per ogni azione inseriamo un elemento <action> e ne specifichiamo sia le caratteristiche (grazie alle proprietà come path, name, parameters, etc.) sia i forward dell'azione stessa (grazie ad elementi <forward>). Ecco come pùo presentarsi la dichiarazione di una action:

<action-mappings> <action path="/ ... "

name="

...

"

scope="

...

"

type="

...

"

parameter="

...

"

validate="

...

">

<forward name=" </action> </action-mappings>

...

"

path="/

...

"

/>

Analizziamo gli attributi più importanti per definire un action-mapping:

Attributo

Descrizione

Necessità

path

È il percorso per la request inviata. Deve iniziare con il carattere "/" e senza l'estensione del nome del file. In altre parole è il nome dell'azione

obbligatorio

name

È il nome del form bean associato all'azione

facoltativo

input

Il path per il modulo di immissione dati verso il quale deve essere reindirizzato il controllo se si verifica un errore di validazione

obbligatorio se è specificato l'attributo name

validate

Valore booleano (false o true) che indica se il metodo validate() del form bean, deve essere invocato prima di eseguire l'action, per default è true

facoltativo

scope

Indica quale visibilità abbia il form bean e assumere i valori request (relativo solamente alla sola richiesta) o session (relativo per tutta la sessione dell'utente)

facoltativo

Forward

Questo elemento ci permette di indicare il nome (attributo

facoltativo, può non

name) e il path (attributo path) di una servlet o di una pagina JSP verso cui verrà effettuato il forward

type

È usato per elaborare la request se gli attributi forward o include non sono specificati. Si deve dichiarare il nome di una classe Java che estende la

org.apache.struts.action.Action

include

Indica il path di una servlet o di una pagina JSP che saranno incluse nella response

Serve a dichiarare il nome di un attributo necessario ad attribute accedere al form bean dell'action da dichiarare (vedremo meglio questo meccanismo in seguito)

parameter

È utilizzato per passare informazioni extra all'istanza dell'action selezionata. All'interno della action, possiamo recuperare un parametro definito in questo modo grazie al metodo getParameter()

Serve ad indicare una classe alternativa per il mapping e la className configurazione dell'action. Di default Struts usa

essere dichiarato se presenti gli attributi type o include.

facoltativo ed esclusivo rispetto a forward e include

facoltativo ed esclusivo rispetto a forward e type

facoltativo e ha precedenza rispetto all'attributo name

facoltativo

facoltativo

org.apache.struts.ActionMapping Ecco un esempio di action mapping, in cui associamo il path "/azione" alla classe it.html.struts.MyAction, indichiamo che utilizzeremo il form myForm e che per gli errori ci serviamo della vista dataerror.jsp:

<action path = "/azione" type = "it.html.struts.MyAction" name = "myForm" input = "/WEB-INF/jsp/dataError.jsp">

<forward name="OK" path="/WEB-INF/jsp/viewResult.jsp"/> <forward name="ERROR" path="/WEB-INF/jsp/busError.jsp"/> </action>

message-resources

I message-resources, sono classi utili per gestire i messaggi in modo unificato nell'applicazione. Sono particolarmente utili per applicazioni multilingua.

<message-resources parameter="MessageResources" />

Vedremo che nelle viste si farà riferimento a delle chiavi (key) che saranno poi associate ai messaggi corrispondenti.

plug-in

Infine abbiamo la parte dedicate alla dichiarazione dei plugin usati nell'applicazione. Osserviamo come aggiungere alla nostra applicazione uno dei plugin più utilizzati del framework, il validator che permette di validare i parametri inseriti in un form:

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">

<set-property property="pathnames" value="/org/apache/struts/validator/validator-rules.xml, /WEB-INF/validation.xml"/> </plug-in>

File di configurazione multipli

Nei progetti di grandi dimensioni è possibile specificare più di un file di configurazione. Ciò consente, ad esempio, l'importazione di componenti specifici per particolari rami dell'applicazione, o di avere più applicazioni Struts sullo stesso server.

Per dichiarare un nuovo ramo dell'applicazione, ad esempio la sezione blog, dobbiamo agire sul web.xml ed aggiungere un parametro all'elemento <servlet>

<init-param>

<param-name>config/blog</param-name>

<param-value>/WEB-INF/struts-blog-config.xml</param-value>

</init-param>

Hello World con Struts

In questa lezione vediamo come su possa realizzare una applicazione di benvenuto (la classica "Hello World"), che visualizza un messaggio di benvenuto. Iniziamo ad approfondire alcuni concetti e ne lasceremo altri da trattare in seguito.

Dopo aver creato il nostro progetto J2EE con Eclipse importiamo il file struts-blank- 1.x.x.war così come abbiamo visto nella lezione precedente (http://java.html.it/guide/lezione/4556/creare-un-progetto-struts-con-eclipse/). Ecco ciò che otteniamo lanciando l'applicazione (per esempio su TomCat):

Figura 6. Risultato dell'applicazione

<set-property property="pathnames" value="/org/apache/struts/validator/validator-rules.xml, /WEB-INF/validation.xml"/> </plug-in> File di configurazione multipli Nei progetti di grandi dimensioni è possibile

In precedenza abbiamo visto come questo progettino rappresenti l'ossatura di base di una applicazione Struts. In questa lezione continueremo ad analizzare i file di questa applicazione, per comprenderne il funzionamento.

I componenti principali dell'applicazione struts-blank sono:

Il file WEB-INF/web.xml

Il file WEB-INF/struts-config.xml

I file .jsp (index.jsp, pages/Welcome.jsp)

Il file WEB-INF/classes/message.properties

Le api di Struts contenute nella cartella WEB-INF/lib

Il file web.xml come abbiamo detto nelle lezioni precedenti, non è un file di Struts ma il file di configurazione per ogni applicazione J2EE.

Apriamo il file e osserviamo il contenuto degli elementi <servlet> e <servlet-mapping>:

è sovrapponibile alla configurazione standard già esaminata in precedenza:

<servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param>

<load-on-startup>2</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>action</servlet-name>

<url-pattern>*.do</url-pattern>

</servlet-mapping>

index.jsp

Infatti anche qui troviamo la configurazione dell'ActionServlet e la sua mappatura, con la delega alla classe ActionServlet di gestire tutti i file che abbiano estensione .do. Infine definiamo come file di partenza la vista index.jsp.

Esaminiamo quindi il file configurazione WEB-INF/struts-config.xml.

<global-forwards> <forward name="welcome" path="/Welcome.do"/> </global-forwards>

Nel global-forwards diciamo che quando viene inviata una richiesta alla pagina /Welcome.do, questa viene associata ad un forward di nome welcome

<action-mappings> <action path="/Welcome" forward="/pages/Welcome.jsp"/> </action-mappings>

Questa dicitura serve per configurare l'action Welcome.do definendone il forward alla pagina /pages/Welcome.jsp. Inoltre abbiamo la dichiarazione del message-resource:

<message-resources parameter="MessageResources" />

Lo struts-config della nostra piccola applicazione contiene l'esempio per la configurazione di qualsiasi componente di Struts.

Adesso passiamo alle due viste. La prima è la index.jsp:

<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>

<logic:redirect forward="welcome"/>

Si dichiara il tag <logic> e si effettua un forward all'action con il nome welcome configurata nello struts-config.

La pagina pages/welcome.jsp si compone invece nel seguente modo:

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %> <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %> <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>

<html:html> <head> <title><bean:message key="welcome.title"/></title> <html:base/> </head> <body bgcolor="white">

<logic:notPresent name="org.apache.struts.action.MESSAGE" scope="application"> <font color="red"> ERROR: Application resources not loaded -- check servlet container logs for error messages. </font> </logic:notPresent>

<h3><bean:message key="welcome.heading"/></h3> <p><bean:message key="welcome.message"/></p>

</body>

</html:html>

Nelle lezioni successive chiariremo tutte le sue parti, per adesso commentiamo solo queste righe:

<h3><bean:message key="welcome.heading"/></h3> <p><bean:message key="welcome.message"/></p>

Che servono a prelevare dei messaggi dal "message resource" per comporre la pagina Jsp al momento della compilazione. Per prelevare i messaggi basta specificare la chiave.

Infine abbiamo il file MessageResources.properties (nella cartella WEB- INF/src/java/) in cui troviamo le definizioni per tutti i messaggi con le relative chiavi.

welcome.title=Struts Blank Application welcome.heading=Welcome! welcome.message=To get started on your own application, copy the struts- blank.war to a new WAR file using the name for your application. Place it in your container's "webapp" folder (or equivalent), and let your container auto- deploy the application. Edit the skeleton configuration files as needed, restart your container, and you are on your way! (You can find the MessageResources.properties file with this message in the /WEB-INF/src folder.)

Questo sistema, che permette di associare i messaggi alle chiavi, risulta molto utile, specie quando vogliamo internazionalizzare l'applicazione.

Regole e consigli per scrivere applicazioni con Struts

Prima di entrare nel dettaglio dei vari componenti di Struts è utile fissare alcune regole che ci

aiutino a realizzare applicazioni stabili e revisionabili. Alcune di queste regole hanno carattere generale: sono valide per Struts ma applicabili anche allo sviluppo con altri framework.

Processo di sviluppo

Struts si basa sul paradigma MVC, ecco un possibile processo di sviluppo di base per tutte le applicazioni:

  • 1. Disegnare (e poi creare) tutte le viste che rappresentano l'interfaccia utente dell'applicazione

  • 2. Creare e distribuire tutti gli ActionForm (vedremo meglio in seguito di che si tratta) utilizzati dalle viste

  • 3. Scrivere la logica applicativa realizzando i componenti del Controller

  • 4. Definire le relazioni che esistono tra le Viste e il Controller (struts-config.xml)

  • 5. Apportare le modifiche appropriate al file web.xml

  • 6. Mandare in esecuzione l'applicazione

Abbiamo omesso cose molto importanti come la gestione dei requisiti e l'adozione di una suite per lo unit testing, ma solo per concentrarci meglio sul framework.

Scrivere il markup solo nelle viste

Un'altra regola impostante per ottenere codice efficiente e per soddisfare i principi del MVC è quello di scrivere il markup HTML solo nelle nelle viste, quindi nelle pagine Jsp.

Sarebbe infatti possibile rispondere ad una richiesta direttamente dall'Action, sfruttando la funzione write del componente out. L'oggetto out risulta molto utile soprattutto per accedere ai parametri e alle proprietà di una sessione, ecco un modo poco ortodosso di utilizzarlo:

out.write("<html><body>Ciao</body></html>");

Questa funzione ci potrebbe "risparmiare la fatica" di creare una pagina Jsp, ma rende le viste non modificabili e può creare problemi a tutta l'architettura Struts.

Tutte le Action finiscono con il .do

Quando definiamo il controller nel web.xml, dichiariamo una classe di tipo filter, questo significa che stabiliamo un url-pattern (una espressione) che determina quali richieste debbano essere gestite dalle nostre Action.

Lo standard di Struts prevede il suffisso .do per le Action, pertanto è buona norma aderire a questa convenzione, e terminare con il .do tutte le nuove Action che creiamo. Questo è utile soprattutto per la manutenzione e per non creare confusione nel lavoro di gruppo.

Sui jar

Non creare package con namespace già presenti in Struts o in altri framework come ad

esempio org.apache.struts. Quando si caricano i jar di Struts stare attenti a non avere jar di versioni differenti

Se si usano altri framework consultare sempre la compatibilità e soprattutto stare attenti a quando si caricano i jar. In ogni caso Struts è quello di alto livello quindi saranno gli altri framework a cambiare i jar. È consigliabile creare una nuova cartella e caricare dentro tutti i jar di struts e degli altri framework così da non avere problemi quando esportiamo

l'applicazione.

Test e configurazione

Per ogni Action o per ogni processo sviluppato è utile testare il funzionamento

dell'applicazione. Infatti con Struts il lavoro di un programmatore consiste soprattutto nella stesura dei file di configurazione, dove facilmente si può sbagiare qualche percorso, qualche lettera, etc. Lo Struts-config è caricato all'avvio dell'Application Server, quindi se si effettuano modifiche è necessario ricordare di riavviare l'application Server

ActionServlet

In questo capitolo approfondiamo il Controller, la parte più importante del framework Struts. Il Controller è composto di i 4 elementi fondamentali, che hanno responsabilità quali ricevere un input da un client, attivare le operazioni secondo la logica applicativa e gestire le viste e l'interfaccia con il client.

la classe ActionServlet

la classe Action

i Plugin

il RequestProcesser

La classe ActionServlet e il RequestProcessor

La classe org.apache.struts.ActionServlet è un elemento fondamentale per le applicazioni Struts. Si tratta del componente che realizza il Controller nella architettura MVC.

Il suo compito è, infatti, quello di gestire le richieste client e determinare quale org.apache.struts.action.Action processerà la richiesta arrivata. Funziona come un Action Factory, creando istanze di classi Action in base alle richieste ricevute.

La ActionServlet è una servlet che, come tutte le altre servlet, estende la classe javax.servlet.http.HttpServlet e quindi implementa tutti i metodi del ciclo di vita di una servlet (http://java.html.it/guide/lezione/784/le-servlet/), incluse le attività di init(), doGet(), doPost() e destroy.

I due punti di ingresso per l'ActionServlet sono essenzialmente gli stessi delle altre servlet:

doGet() e doPost().

// Codice di doGet() e doPost()

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { process (request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { process (request, response);

}

L'implementazione di questi metodi fa esattamente la stessa cosa, ossia chiamare il metodo process(). Per capire meglio questo comportamento esaminiamo, passo dopo passo, le attività compiute dall'ActionServlet quando riceve una richiesta:

1

I metodi doPost() o doGet() ricevono una richiesta e invocano il metodo process()

Il metodo process() ottiene il RequestProcessor corrente e ne invoca a sua volta il metodo process().

2

Se si intende estendere l'ActionServlet, il posto giusto per la personalizzazione è l'oggetto RequestProcessor: contiene la logica che il Controller Struts esegue su ogni richiesta

Il metodo RequestProcessor.process() è il luogo dove la richiesta viene

3

4

effettivamente servita. Questo metodo reperisce, dal file struts-config.xml, l'elemento <action> che corrisponde al path submitted della richiesta

Quando il metodo RequestProcessor.process() trova una <action> in match, va alla ricerca dell'entry <form-bean> referenziato dall'elemento <action>

Quando il metodo RequestProcessor.process() conosce il "fully qualified name" del

5

FormBean, crea o reperisce un'istanza dell'ActionForm nominato dall'elemento <form- bean> e popola i membri di istanza con i valori che arrivano dalla richiesta

Quando i dati dell'ActionForm sono stati caricati, il metodo

6

RequestProcessor.process() chiama il metodo ActionForm.validate(), che controlla la validità dei valori passati

Il metodo RequestProcessor.process() conosce tutto ciò che gli serve e può servire la

7

richiesta. Reperisce il "fully qualified name" della classe Action e chiama il metodo execute()

Quando la classe azione ritorna dal suo processing, il suo metodo execute() ritorna un oggetto ActionForward che viene utilizzato per determinare il target della transazione. Il metodo RequestProcessor.process() riacquisisce il controllo e la richiesta viene indirizzata al target A questo punto l'ActionServlet ha completato l'elaborazione della richiesta ed è pronto per servirne delle altre.

8

Al fine di delgare all'ActionServlet l'unica responsabilità di ricevere e rispondere ad una request chiamando la giusta Action, dalla versione 1.1 del framework è stata introdotta una nuova classe, il RequestProcessor (org.apache.struts.action.RequestProcessor), al fine di elaborare la request per il controller. Grazie a questo disaccoppiamento è possibile personalizzare e modificare il modo in cui viene elaborata la richiesta.

Configurare l'ActionServlet

Come ogni altra servlet Java, la ActionServlet di Struts deve essere configurata nel deployment descriptor. Quindi una volta aperto il file web.xml, possiamo inserire le nostre impostazioni utilizzando l'elemento <servlet>.

Una pratica comune consiste nell'utilizzare l'elemento <load-on-startup> per essere certi che l'ActionServlet venga avviata quando il container avvia l'applicazione Web.

Ecco un esempio di <servlet> entry che descrive ActionServlet:

<servlet>

<servlet-name>action</servlet-name>

<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

<init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <param-name>debug</param-name>

<param-value>4</param-value>

<init-param></init-param>

<load-on-startup>1</load-on-startup>

</servlet>

Le Action

Le Action sono gli strumenti grazie ai quali il Controller di Struts gestisce le attività. Ogni Action rappresenta una funzione dell'applicazione, quindi è qui che scriviamo la logica applicativa dei nostri progetti.

La classe Action disaccoppia le richieste del client dall'applicazione. In altre parole un oggetto di tipo Action è un'estensione del controller e fa da ponte tra le azioni client-side dell'utente e le operazioni della logica applicativa.

Ogni Action, come abbiamo già detto (http://java.html.it/guide/lezione/4558/il-file-di- configurazione-strutsconfigxml/), deve essere dichiarata e configurata nel file struts- config.xml e non nel web.xml. Il suo nome deve terminare con .do, è questo che permette alla richiesta di essere processata da Struts e non come una semplice servlet Java.

Le Action servono ad esempio a ricevere le richieste dai form, ad elaborare i dati e a lanciare le View per la visualizzazione delle informazioni. Per realizzare le Action, è necessario:

Creare una classe che estenda org.apache.struts.action.Action

Implementare il metodo execute() aggiungengo la logica di business della nostra

applicazione Compilare la nuova Action e spostarla nel classpath dell'applicazione Web

Aggiungere un elemento <action> al file struts-config.xml all'applicazione che descrive la nuova azione

Esaminiamo più in dettaglio alcuni di questi passi.

Creare una Action

Dichiarare una nuova Action è molto semplice, è sufficiente estendere la classe base e ricordare di importare tutti i namespace necessari (se utilizziamo un IDE ci saranno comunque suggeriti):

import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping;

public class EsempioAction extends Action {

// Qui scriviamo la Action

}

Il metodo execute()

La classe base Action ci da l'opportunità e il compito di effettuare l'override del metodo execute(), riscrivendo questo metodo, possiamo indicare le operazioni che vogliamo far compiere alla nostra azione. In altre parole è qui che inseriamo la "logica di business".

Il metodo execute() viene invocato dal controller quando viene ricevuta una richiesta. Da non sottovalutare, per il buon funzionamento dell'applicazione, che una classe Action viene istanziata una sola volta, all'avvio dell'applicazione, quindi occorre garantire che tutte le Action operino correttemente in un ambiente multithread, proprio come si fa quando si sviluppa una servlet.

Le funzioni principali di execute() sono:

compiere la logica dell'applicazione

instradare la richiesta indicando al Framework il passo successivo da eseguire

Azioni HTTP e Custom

Struts contempla due definizioni per execute().

La prima serve a dichiarare azioni custom che non sono specificatamente HTTP. Questa implementazione del metodo è analoga alla classe javax.http.servlet.GenericServlet; e la sua signature è la seguente:

public ActionForward execute(ActionMapping mapping, ActionForm form, ServletRequest request, ServletResponse response ) throws IOException, ServletException

La seconda implementazione viene utilizzata invece per dichiarare azioni HTTP. Ecco la sua signature:

public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException

Campo

ActionMapping

ActionForm

HttpServletRequest

Descrizione

Contiene le informazioni di deployment per un particolare Action bean

Rappresenta gli input del Form contenente i parametri della richiesta È un riferimento all'oggetto HTTP Request

HttpServletResponse È un riferimento all'oggetto HTTP Response Dopo aver esaminato i parametri passati al metodo execute(), bisogna dare un'occhiata al suo tipo di ritorno.

ActionForward

Questo oggetto viene utilizzato dal RequestProcessor per determinare la destinazione successiva della richiesta. Qui si può determinare ad esempio, se sarà lanciata una vista JSP o

un'altra azione.

// Esempio di execute()

public class EsempioAction extends Action {

public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException,

ServletException

{

 

if (form!=null) {

 

// 1. Creazione del form

//

(effetuiamo il cast dal form in ingresso)

SkeletonForm actionForm = (SkeletonForm) form;

// 2. Aggiungere qui la Business Logic

// 3. return con un appropriato ActionForward return mapping.findForward("success");

 

}

}

}

Nella costruzione delle Action, si segue una procedura comune:

  • 1. effettuare un cast dell'ActionForm referenziato

  • 2. aggiungere la specifica logica di business

  • 3. utilizzare il metodo ActionMapping.findForward() per trovare l'oggetto ActionForward che effettua un match con il sottoelemento <forward> nella definizione di <action> (nel file struts-config.xml)

  • 4. restituire l'oggetto ActionForward trovato

Configurazione della classe Action

Le classi Action si configurano nel file struts-config.xml, poiché si tratta di oggetti specifici di Struts.

L'elemento che viene utilizzato per descrivere un'azione Struts è <action>. e la classe che definisce gli attributi dell'elemento <action> è org.apache.struts.action.ActionMapping.

<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-

config_1_1.dtd">

<struts-config>

<form-beans> <!-- qui dichiariamo che il form 'lookupForm' sarà inviato--> <!-- all'action 'esempio' nel campo ActionForm --> <form-bean name="lookupForm" type="esempio.LookupForm" /> </form-beans>

<action-mappings> <!-- la location /Lookup lancerà il nostro form -->

<action path="/Lookup" type="esempio.LookupAction" name="lookupForm" > <!-- le viste da collegare all'esito dell'action --> <forward name="success" path="/quote.jsp" /> <forward name="failure" path="/index.jsp" /> </action> </action-mappings>

</struts-config>

Vedremo in seguito come estendere il mapping per definire attributi <action> addizionali.

DispatchAction

Spesso le azioni sembrano essere troppo numerose e troppo piccole, sarebbe utile raggruppare azioni correlate in una classe facilitando il riutilizzo.

A tale scopo Struts mette a disposizione le DispatchAction (org.apache.struts.action.DispatchAction). Il principio alla base è che ci possano essere funzionalità correlate per un servizio che, invece di essere suddivise in molteplici classi Action, si possono tenere insieme nella medesima classe.

DispatchAction è una classe astratta che estende la classe Action. Anziché avere un singolo metodo execute, si ha un metodo per ciascuna azione logica.

Nella request, infatti, bisogna inserire un parametro di nome method che sarà usato dalla DispatchAction per determinare quale metodo invocare.

Per implementare una DispatchAction bisognerà creare:

  • 1. una classe action handler che estenda DispatchAction;

  • 2. un metodo per ciascuna azione logica;

  • 3. un action-mapping per questo action handler

// Un esempio di DispatchAction

import javax.servlet.http.*; import javax.servlet.*; import org.apache.struts.actions.*; import org.apache.struts.action.*;

public class UserDispatchAction extends DispatchAction {

public ActionForward remove(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

System.out.println("REMOVE USER!!!!"); return mapping.findForward("success");

}

public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

System.out.println("SAVE USER!!!!"); return mapping.findForward("success");

}

}

È utile notare che tutti i metodi hanno la stessa firma del metodo Action.execute(). Produciamo il bean che conterrà il valore di method, unica proprietà del form inviante:

// Bean che contiene il valore di method import javax.servlet.http.*; import org.apache.struts.action.*;

public class UserForm1 extends ActionForm {

private String method = null;

public String getMethod() { return method; }

public void

setMethod(String method) { this.method = method; }

public void reset(ActionMapping mapping, HttpServletRequest request) { this.method = method; }

}

Il terzo step è quello per creare un action mapping per questo action handler e aggiungendo un elemento <form-bean> nel struts-config.xml:

<form-beans> <form-bean name="userForm1" type="fulvios.UserForm1" /> </form-beans>

<action path="/dispatchUserSubmit" type="fulvios.UserDispatchAction" parameter="method"

input="/userForm1.jsp"

name="userForm1"

scope="request"

validate="false">

<forward name="success" path="/success.jsp" /> </action>

Ecco quindi lo step finale: creare la userForm1.jsp.

<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html> <body> <html:form action="/dispatchUserSubmit"> action:

<html:select property="method" size="2"> <html:option value="save">Save</html:option> <html:option value="remove">Remove</html:option> </html:select> <br/> <html:submit/><html:cancel/> </html:form>

<%@ page language="java" %>

success!!

In questo esempio abbiamo la DispachtAction che contiene due metodi remove() e save(). Questa classe raggruppa tutte le funzionalità a disposizione dell'utente. Se non avessimo utilizzato una DispachtAction avremmo dovuto creare due Action e implementare i due metodi excute().

DispacthAction utilizza la reflection per individuare un metodo che corrisponda perfettamente al nome contenuto nel valore del parametro della richiesta, controllando anche la corrispondenza del numero e del tipo degli argomenti. Una volta trovato, il metodo sarà invocato e l'oggetto ActionForward restituito proprio come per una qualunque Action.

Sebbene si tratti di una soluzione valida, è importante utilizzarla con criterio. La DispatchAction risulta particolarmente utile quando le classi da raggruppare rappresentano azioni simili tra loro o hanno parti comuni da eseguire prima di effettuare operazioni specifiche. Ad esempio se dobbiamo prelevare dei dati da un database e modificarli in modo differente a seconda della scelta di un utente conviene utilizzare una DispatchAction per evitare di scrivere uno stesso metodo più volte. Inoltre combinando le operazioni, si renderà più semplice la manutenzione dell'applicazione, infatti se si vuole cambiare l'implementazione di una funzionalità basterà agire solo su una classe.

LookupDispatchAction

La classe LookupDispatchAction (org.apache.struts.actions.LookupDispatchAction), è una sottoclasse della DispatchAction e come quest'ultima ci permette di specificare metodi multipli. Ciascun metodo poi sarà invocato utilizzando il meccanismo del parametro speciale da inserire nelle richieste, parametro che viene indicato nel file di configurazione.

Mentre la DispatchAction usa il valore del parametro della request per determinare quale metodo deve essere invocato, la LookupDispatchAction usa il valore del parametro della request per effettuare un reverse lookup dal resource bundle usando il valore del parametro e per farlo corrispondere a un metodo della classe.

In altre parole ci permette di pescare valori dal file delle risorse in modo dinamico. Per utilizzare LookupDispatchAction è necessario eseguire i seguenti step:

  • 1. Creare un action handler che erediti LookupDispatchAction

  • 2. Creare un metodo che rappresenti ciascuna azione logica

  • 3. Implementare il metodo getKeyMethodMap per mappare le chiavi del file di risorsa ai nomi dei metodi

  • 4. Creare un action mapping per questo action handler utilizzando l'attributo parameter per specificare quale parametro conterrà il nome del metodo che si vuole invocare nelle richieste

  • 5. Impostare i messaggi nel resource boundle per le etichette e i valori per i pulsanti

  • 6. Utilizzare bean:message per mostrare le etichette sul pulsante

Il primo step è creare una classe action handler che erediti LookupDispatchAction (codice completo (http://html.it/guide/img/struts/lookupdispatch_example.html)):

// Handler che eredita LookupDispatchAction public class UserLookupDispatchAction extends LookupDispatchAction {

// È necessario implementare questo metodo che mappi // le chiavi del file di risorse ai nomi dei metodi Map getKeyMethodMap() {

Map map = new HashMap(); map.put("userForm.remove", "remove"); map.put("userForm.save", "save"); return map;

}

// ...

Questa classe implementa il metodo getKeyMethodMap() che restituisce un oggetto di tipo java.util.Map contenente una serie di coppie del tipo chiave/valore. Le chiavi di questo Map dovrebbero corrispondere a quelle del resource bundle, mentre il valore associato dovrebbe essere il nome del metodo della sottoclasse LookupDispatchAction. Questo valore sarà invocato quando è incluso un parametro della request corrispondente al messaggio del resource bundle per la chiave.

Produciamo il bean che conterrà il valore di method, unica proprietà del form inviante:

import javax.servlet.http.*; import org.apache.struts.action.*;

// Bean che contiene il valore di method

public class UserForm2 extends ActionForm {

private String method = null;

public String getMethod() { return method; }

public void

setMethod(String method) { this.method = method; }

public void reset(ActionMapping mapping, HttpServletRequest request) { this.method = method;

}

}

Creiamo un action mapping (struts-config.xml):

<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-

config_1_1.dtd">

<struts-config>

<form-beans> <form-bean name="userForm2" type="simone.UserForm2" /> </form-beans>

<action-mappings>

<action path="/lookupDispatchUserSubmit" type="simone.UserLookupDispatchAction"

input="/userForm2.jsp"

name="userForm2"

parameter="method"

scope="request"

validate="true">

<forward name="success" path="/success.jsp" /> </action>

</action-mappings>

</struts-config>

Scriviamo le nostre viste. Prima il form:

<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>

<!-- Form JSP -->

<html> <body> <html:form action="/lookupDispatchUserSubmit"> <html:submit property="method"> <bean:message key="userForm.remove" /> </html:submit>

<html:submit property="method"> <bean:message key="userForm.save" /> </html:submit>

<html:cancel></html:cancel>

</html:form>

</body>

</html>

poi la pagina con il risultato:

<%@ page language="java" %>

<!-- JSP con il risultato del form -->

<html>

<body>success!!</body>

</html>

infine il file di risorse, dove impostiamo le etichette e i valori per i pulsanti:

ApplicationResources_it_IT.properties

userForm.save=Salva

userForm.remove=Rimuovi

ApplicationResources_en_US.properties

userForm.save=Save

userForm.remove=Remove

È importante modificare anche il file web.xml a causa dei file di risorse:

<init-param>

<param-name>application</param-name>

<param-value>ApplicationResources</param-value>

</init-param>

Si tratta di un percorso piuttosto lungo semplicemente per determinare quale metodo invocare. L'intento di questa classe è di rendere tutto più facile quando si ha un modulo HTML con pulsanti di immissione multipli con lo stesso nome.

Forward Action

In genere non è una buona prassi quella di inserire, all'interno di una pagina JSP, dei link diretti ad altre pagine JSP, soprattutto per questioni di ordine e manutenzione: in effetti è all'interno del file di configurazione struts-config.xml, che fa parte del Controller, che dovremmo descrivere l'intero flusso dell'applicazione.

In alcune occasioni possiamo però avere la necessità di effettuare un forward da una pagina Jsp a un'altra, senza che in realtà ci sia bisogno di passare per una classe Action. Quello che si vuole è un plain link.

Nell'architettura MVC è compito del controller di elaborare tutte le richieste e selezionare la view per il client. Se si utilizza un link diretto, a un'altra pagina JSP, si stanno violando i confini dell'architettura "Model 2" (l'MVC per applicazioni Web).

Se permettessimo alla nostra applicazione di chiamare direttamente la pagina, il controller non sarebbe in grado di portare a termine i compiti per esso stabiliti nell'architettura MVC. Per risolvere questi problemi Struts mette a disposizione la ForwardAction che esegue semplicemente un forward verso un URI configurato nell'attributo parameter dell'action nello struts-config.

Quindi la ForwardAction ci evita la creazione di una classe Action che effettua solamente un semplice forward.

Prima di esaminare un esempio più consistente vediamo una configurazione tipica di ForwardAction:

<action input="/index.jsp" path="/provaForward" parameter="/pagina.jsp" type="org.apache.struts.actions.ForwardAction"> </action>

Quando viene selezionata l'action /provaForward, viene chiamato l'unico metodo della ForwardAction, che effettua un forward a pagina.jsp. La classe ForwardAction è molto utile quando è necessario integrare Struts con altri framework o più pagine Jsp.

Esempio

Abbiamo detto che ForwardAction agisce come bridge tra la vista corrente JSP e la pagina alla quale si collega. Utilizza il RequestDispatcher per effettuare un forward alla risorsa Web specificata. È ciò che permette di collegarsi a un'azione invece che direttamente a una pagina JSP.

Ecco alcuni passi necessari per implementare una ForwardAction:

utilizzare <html:link> con l'attributo action e aggiungere il link alla pagina JSP che

punta all'azione creare un action mapping nel file di configurazione di Struts che utilizza ForwardAction con

l'attributo parameter che specifica il percorso alla JSP

Supponiamo di avere una pagina JSP, coded.jsp, che ha un link diretto su un'altra pagina JSP:

<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html> <body>

<html:link page="/index.jsp">Home</html:link>

</body>

</html>

e di volerla convertire secondo la logica dell'architettura MVC/Model2. In questo caso modifichiamo il tag <html:link>su un'azione. È sufficiente produrre notcoded.jsp:

<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html> <body> <html:link action="home">Home</html:link> </body> </html>

Infine bisogna aggiungere un action mapping all'azione home referenziata dal tag html:link:

<action path="/home" type="org.apache.struts.actions.ForwardAction" parameter="/index.jsp"> </action>

Link a forward globali

Da una prospettiva di design, c'è un'ulteriore alternativa all'utilizzo dell'azione ForwardAction, anziché inserire un link a un azione o a una pagina, ci si potrebbe collegare a un global forward. Ecco un esempio di pagina JSP collegata a un global forward:

<%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html> <body> <html:link forward="home">Home</html:link> </body> </html>

Per permettere ora al codice di funzionare dobbiamo aggiungere un global forward al file di configurazione di Struts che mappi l'azione home:

<global-forwards> <forward name="home" path="/index.jsp" /> </global-forwards>

È possibile anche modificare il global forward in modo che punti a un action mapping:

<global-forwards> <forward name="home" path="/home.do" />

</global-forwards>

Questa, solitamente, è la pratica migliore, infatti, è più naturale collegarsi a forward che ad azioni.

Forward Attribute vs. ForwardAction

Struts permette le due dichiarazioni seguenti nel file struts-config.xml, ma la seconda è sicuramente più snella:

<!-- ForwardAction --> <action path="/home" type="org.apache.struts.actions.ForwardAction" parameter="/index.jsp" />

<!-- Forward Attribute --> <action path="/home" forward="/index.jsp" />

Forward per accesso Legacy

Supponiamo di avere una risorsa Web legacy che si vuole utilizzare con la validazione form di Struts, purtroppo, la risorsa legacy fa parte di un modello MVC elaborato che è stato creato prima dell'implementazione di Struts.

Per ragioni di semplicità la nostra risorsa legacy sarà una servlet. Essenzialmente si vuole fare in modo che il metodo doGet di una servlet venga chiamato solo se l'ActionForm valida i dati con successo. Ecco la nostra servlet d'esempio:

import javax.servlet.*; import javax.servlet.http.*; import org.apache.struts.action.*; import org.apache.struts.*;

import java.io.*;

public class LegacyServlet extends HttpServlet {

public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

ActionMapping mapping = (ActionMapping) request.getAttribute(Globals.MAPPING_KEY); UserForm form = (UserForm)request.getAttribute(mapping.getName()); response.getWriter().println("User name: " + form.getUsername() + " Password: " + form.getPassword()); }

}

e questo è lo UserForm.java, che passa UserName e password

import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; import javax.servlet.http.HttpServletRequest;

public class UserForm extends ActionForm {

private String username = null; private String password = null;

public String getUsername() { return username; }

public void

setUsername(String username) { this.username = username; }

public String getPassword() { return password; }

public void

setPassword(String password) { this.password = password; }

public void reset(ActionMapping mapping, HttpServletRequest request) { this.username = null; this.password = null;

}

}

Notiamo che la servlet può accedere al contesto che il Framework di Struts ha mappato su request (Codice completo del web.xml (http://html.it/guide/img/struts/legacyforward_webxml_example.html)).

<!--

-->

<servlet>

<servlet-name>legacy</servlet-name>

<servlet-class>simone.LegacyServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>legacy</servlet-name>

<url-pattern>/legacy/roar</url-pattern>

</servlet-mapping>

<!--

...

-->

Quindi, un post su /legacy/roar causerebbe l'esecuzione del metodo doGet della servlet.

Ora, per mappare questa servlet su un'azione che agisce come form handler, è necessario mettere mano a struts-config.xml:

<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-

config_1_1.dtd">

<struts-config> <form-beans> <form-bean name="userForm" type="simone.UserForm" /> </form-beans>

<action-mappings>

<action path="/legacy" forward="/legacy/roar" input="/userForm.jsp" name="userForm" parameter="/legacy/roar" validate="true" scope="request"> </action> </action-mappings> </struts-config>

E infine ecco la JSP:

<%@ page language="java" %>

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html> <body> <html: form action="/legacy"> username: <html:text property="username"/><br/> password: <html:password property="password"/><br/> <html:submit/><html:cancel /> </html:form> </body> </html>

Il RequestDispatcher effettua la chiamata al metodo doGet() della Servlet solo se il metodo execute() della ForwardAction viene chiamato.

Avendo impostato il metodo validate su true nell'action mapping per la servlet, il metodo execute() di ForwardAction viene chiamato solo se ActionForm (UserForm) validates restituisce nessun oggetto ActionError.

MappingDispatchAction e altre Action già pronte

In questa lezione analizzeremo quelle action pronte all'uso, contenute nel package org.apache.struts.actions, che non abbiamo ancora trattato, ma che vale la pena conoscere.

MappingDispatchAction

La MappingDispatchAction è identica alla DispatchAction, solo che in fase di mapping non si specifica più il parametro, ma direttamente il nome del metodo da invocare. La stessa azione sarà mappata con nomi differenti e sarà chiamata a seconda del metodo da invocare.

Riprendendo l'esempio fatto per la DispatchAction nelle lezioni precedenti, dovremo modificare innanzitutto l'estensione della classe, che sarà org.apache.struts.action.MappingDispatchAction. Nello struts-config scriveremo:

<action path="/saveMappingDispatchUserSubmit" type=" fulvios.UserMappingDispatchAction" parameter="save">

<forward name="success" path="/success.jsp" /> </action>

<action path="/removeMappingDispatchUserSubmit" type="fulvios.UserMappingDispatchAction" parameter="remove">

<forward name="success" path="/success.jsp" /> </action>

Quindi se vogliamo eseguire il metodo save invocheremo l'azione con il nome /saveMappingDispatchUserSubmit mentre per il metodo remove /removeMappingDispatchUserSubmit.

BaseAction

La BaseAction è molto simile ad una semplice Action di Struts solo che mette a disposizione il seguente metodo execute():

public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse res) throws Exception {

preProcess(mapping,form,request,response); if (isErrors(request)) { return findFailure(mapping,form,request,response);

}

try { executeLogic(mapping,form,request,response);

} catch (Exception e) { setException(request,e); catchException(mapping,form,request,response);

} finally { postProcess(mapping,form,request,response); }

if (isErrors(request)) { return findFailure(mapping,form,request,response);

}

if ((isStruts_1_0()) && (isMessages(request))) { saveErrors(request,getMessages(request,false));

}

}

Questo metodo mette a disposizione una parte dove si può implementare una logica di business da effettuare prima di eseguire il processo vero e proprio che sarà contenuto nel metodo executeLogic(). Nel metodo è già compresa la gestione delle eccezioni generale.

IncludeAction

La classe IncludeAction ha la stessa funzionalità della ForwardAction solo che permette l'integrazione di servlet con l'applicazione Struts. Si configura allo stesso modo della ForwardAction solo che l'attributo parameter deve specificare il path di una servlet, mentre type deve essere org.apache.struts.actions.IncludeAction.

Il RequestProcessor

Il RequestProcessor è la classe da riscrivere quando si vuole personalizzare il processing dell'ActionServlet.

Essa contiene un entry point predefinito che viene invocato dal controller di Struts con ciascuna richiesta. Questo entry point si chiama processPreprocess().

Se si desidera aggiungere il proprio processing specializzato al Controller è necessario implementare il metodo processPreprocess(), aggiungendo la specifica logica e restituendo true per continuare con il processing normale. Se si desidera terminare il processing normale, restituire false per dire al controller che la richiesta corrente è completa.

Ecco un esempio di implementazione di default processPreprocess():

protected boolean processPreprocess(HttpServletRequest request, HttpServletResponse response) { return true; }

Per creare il proprio RequestProcessor è necessario seguire gli step seguenti:

Creare una classe che estende org.apache.struts.action.RequestProcessor;

Aggiungere un costruttore di default vuoto;

Implementare il metodo processPreprocess()

Ecco di seguito il codice per creare il RequestProcessor:

import javax.servlet.http.*; import javax.servlet.*; import java.io.*; import java.util.*; import org.apache.struts.action.RequestProcessor;

public class EsempioRequestProcessor extends RequestProcessor {

public EsempioRequestProcessor() { }

public boolean processPreprocess(HttpServletRequest request, HttpServletResponse response) {

System.out.println("-------------processPreprocess Logging-------------"); System.out.println("RequestedURI = " + request.getRequestURI()); System.out.println("Protocol = " + request.getProtocol()); System.out.println("Remote Address = " + request.getRemoteAddr()); System.out.println("Remote Host = " + request.getRemoteHost()); System.out.println("Remote User = " + request.getRemoteUser()); System.out.println("Requested Session Id = " + request.getRequestedSessionId());

return true;

}

}

Nel metodo processPreprocess() reperiamo le informazioni memorizzate in request ed effettuiamo un log.

Una volta che il log è completato, il metodo processPreprocess ritorna il valore boolean true e il processing normale prosegue.

Se il metodo processPreprocess avesse restituito false, il Controller avrebbe terminato il normale processing e l'azione non sarebbe mai stata eseguita.

Per effettuare il deploy del nostro RequestProcessor dobbiamo:

Compilare il nostro RequestProcessor e metterlo nel classpath dell'applicazione.

Aggiungere l'elemento <controller> al file di configurazione dell'applicazione struts-

config.xml. Ecco il contenuto totale del file struts-config.xml:

<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-

config_1_1.dtd">

<struts-config> <form-beans> <form-bean name="lookupForm" type="esempio.LookupForm" /> </form-beans>

<action-mappings> <action path="/Lookup" type="fulvios.LookupAction" name="lookupForm" > <forward name="success" path="/quote.jsp" /> <forward name="failure" path="/index.jsp" /> </action> </action-mappings>

<controller processorClass="esempio.EsempioRequestProcessor" />

<plug-in className="esempio.EsempioPlugin" /> </struts-config>

I Plugin

I Plugin di Struts sono estensioni modulari del controller di Struts. Introdotti con Struts 1.1, sono definiti dall'interfaccia org.apache.struts.action.Plugin. Risultano utili quando si allocano risorse o si preparano connessioni a database o su risorse JNDI.

Questa interfaccia definisce due metodi init() e destroy(), ovvero i metodi del ciclo di vita dei Plugin.

init()

Il metodo init() rappresenta l'inizio della vita del plugin: viene invocato quando il container di JSP/Servlet avvia l'applicazione Web contenente il Plugin. Esaminiamone la firma:

public void init(ActionServlet servlet, ApplicationConfig applicationConfig ) throws javax.servlet.ServletException;

Quando viene lanciato, il metodo init() riceve un riferimento all'ActionServlet e all'ApplicationConfig e viene utilizzato per caricare e inizializzare risorse necessarie al Plugin.

Il riferimento ad ActionServlet permette di referenziare le informazioni del Controller mentre l'oggetto ApplicationConfig fornisce l'accesso alle informazioni di configurazione che descrivono l'applicazione Struts.

destroy()

Il metodo destroy() termina la vita del Plugin: viene invocato ogni volta che il container di

JSP/Servlet arresta l'applicazione Web contenente il Plugin. Questo metodo risulta molto utile perché ci sonsente di rilasciare le risorse allocate dal metodo init(). La sua firma è molto semplice:

public void destroy();

Creare un Plugin

Ecco i passi necessari alla creazione di un Plugin:

Creare una classe che implementi l'interfaccia

org.apache.struts.action.Plugin

Aggiungere un costruttore di default vuoto

Implementare i metodi init() e destroy()

Compilare il Plugin e spostarlo nel classpath dell'applicazione Web

Aggiungere l'elemento <plug-in> al file struts-config.xml

Ecco un esempio di plugin (Vedi codice completo (http://www.html.it/articoli/2236/cod01.html)):

public void init(ActionServlet servlet, ModuleConfig applicationConfig) throws javax.servlet.ServletException {

System.out.println("---->The Plugin is starting<----"); Properties properties = new Properties();

try {

File file = new File("c:/info/startup.info");

// Crea l'input stream FileInputStream fis = new FileInputStream(file);

// Carica le proprietà properties.load(fis);

ServletContext context = servlet.getServletContext();

// ...

L'obiettivo di questo Plugin è quello di rendere disponibili un set di proprietà all'avvio dell'applicazione. Per testarlo non ci resta che:

Compilare e includere la classe del Plugin nel classpath (spostando il file in una cartella dell'applicazione, nel nostro caso si chiama esempio)

Aggiungere l'elemento <plug-in> al file di configurazione struts-config.xml

Riavviare l'applicazione.

Ecco come appare il file struts-config.xml:

<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-

config_1_1.dtd">

<struts-config> <form-beans> <form-bean name="lookupForm" type="esempio.LookupForm" /> </form-beans>

<action-mappings> <action path="/Lookup" type="esempio.LookupAction" name="lookupForm" > <forward name="success" path="/quote.jsp" /> <forward name="failure" path="/index.jsp" /> </action> </action-mappings>

<plug-in className="esempio.EsempioPlugin" /> </struts-config>

Le taglib di struts

Abbiamo già detto che le viste in Struts sono caratterizzate da pagine Jsp. In questo capitolo esamineremo i vantaggi dell'impiego delle librerie di tag nelle View di Struts. Vedremo i tag più importanti e le loro funzionalità.

Chi conosce linguaggi di markup come XML (http://xml.html.it/guide/leggi/58/guida-xml-di-base/), ha già confidenza con il concetto di tag, qui ricordiamo solo la distinzione tra tag "contenitori" e non.

I tag "senza contenuto" sono quelli che non contengono altri tag, essi specificano l'informazione servendosi solo degli attributi. Sono spesso impiegati per semplici azioni. Un esempio potrebbe essere quello delle immagini in HTML:

<img src="percorso-immagine" />

Gli elementi contenitori invece racchiudono altri elementi o un contenuto tra i tag di apertura e chiusura. L'esempio è quello del paragrafo in HTML:

<p style="text-align:right">Testo allineato a destra</p>

Jsp Custom Tag

Nelle pagine Jsp, oltre al classico markup elaborato direttamente dal browser, è possibile utilizzare il meccanismo dei Custom Tag, ovvero elementi di markup speciali che vengono interpretati dalla nostra applicazione e che, ad esempio, servono a generare automaticamente interi pezzi di markup HTML.

Il rendering e i comportamenti di questi componenti sono affidati ad una specifica classe Java detta tag handler (http://java.html.it/articoli/leggi/2297/custom-tag-jsp-esempio-di-tag-handler/5/). L'handler ha accesso a tutte le risorse della Jsp che ospita i componenti (oggetti session, request, response e pageContext).

Struts mette a disposizione molti tag personalizzati, raggruppati in cinque librerie:

Html Bean Logic Nested Template Le prime versioni di Struts contenevano anche una sesta libreria di tag chiamata form inclusa poi

nella libreria Html.

Utilizzare una taglib

Per usare le taglib bisogna includere il Tag Library Descriptor (http://java.html.it/articoli/leggi/2297/custom-tag-jsp-definire-un-tag-library-descriptor-tld/3/) (TLD ) per ciascuna libreria, che contiene le definizioni di tutti i tag della libreria.

Possiamo farlo grazie alla direttiva <%@taglib%> che ha questa sintassi:

<%@ taglib uri="/WEB-INF/nome_libreria.tld" prefix="prefisso" %>

Dove con l'attributo uri indichiamo il path del file .tld e con prefix indichiamo all'application server che dovrà occuparsi di elaborare tutti i tag che iniziano per "prefisso".

Ad esempio, de vogliamo utilizzare le librerie Html e Bean in una pagina Jsp, inseriamo le seguenti direttive all'inizio della pagina:

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>

Possiamo trovare un altro semplice esempio qui (http://java.html.it/articoli/leggi/2297/hello-world-

con-i-custom-tag-di-jsp/2/).

Nelle lezioni successive vedremo nel dettaglio le librerie e i principali tag che li compongono. Per un riferimento esaustivo su tutti i tag delle librerie di Struts è possibile consultare i javadocs ( http://struts.apache.org/1.x/apidocs/index.html) nella sezione taglib.

La HTML taglib

Una delle librerie di tag più utili di Struts è la HTML taglib: permette di creare form di input e interfacce utente basate su HTML. Il vantaggio nell'utilizzare questi tag sta nel fatto che semplificano l'interazione con il framework, grazie ad essi possiamo ragionare direttamente in termini di action, e concentrarci non tanto sul colloquio tra View e Controller, quanto sulla realizzazione del front end.

Per importare questi tag dobbiamo inserire il relativo riferimento alle definizioni in testa alla nostra vista, con una direttiva simile a questa:

<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>

In questo caso utilizziamo le definizioni presenti online, ma possiamo anche decidere di utilizzare definizioni salvate in locale sul nostro server.

Tutti i tag di questa libreria saranno richiamati utilizzando il prefisso html: (ad esempio <html:link>)

Facciamo un veloce elenco di questi tag, senza scendere nel dettaglio degli attributi: nelle prossime lezioni esamineremo più dettagliatamente i più importanti.

Tag generici per la formattazione e la navigazione

Nome

Funzione

html

base

Visualizza un elemento html

Realizza l'elemento base di HTML: definisce in automatico l'indirizzo di base per i link relativi

link

Crea il codice HTML per il classico link, ma possiamo sfruttarlo per collegare anche le nostre action, che il framework interpreta come ActionForward

img

frame

Visualizza un tag HTML img Definisce un frameset HTML, le pagine vengono chiamate al suo interno con lo stesso

meccanismo del tag <html:link> errors Serve per mostrare messaggi d'errore, ad esempio in caso di validazione di un form

Il tag <html:html>

È usato per la visualizzazione di un elemento HTML. Permette di includere un attributo locale che scriverà le impostazioni locali dell'utente. Un esempio di uso di questo tag è per impostare la lingua dell'applicazione a seconda delle impostazione del browser. Si usa nel seguente modo:

<html:html locale="true"> </html:html>

Tag per i form

form

text

password

textarea

option

checkbox

radio

submit

cancel

reset

button

file

image

hidden

multibox

Nome

Funzione

Definisce un form HTML Casella di testo Visualizza un campo di input per le password Visualizza un campo di input textarea Crea un menu a tendina Visualizza un campo di input (checkbox) Visualizza un radio button Visualizza un pulsante submit Crea un campo di input che annulla il form< Visualizza un campo di input con pulsante reset Crea un campo di input (pulsante)

Visualizza un campo di input per la selezione di un file

Visualizza un tag input del tipo image Genera un campo nascosto Mostra un elenco di checkbox

options - optionsCollection Visualizza una raccolta di opzioni select

Il tag <html:form>

Il tag <html:form> di Struts è uno dei più importanti della HTML taglib. Permette di visualizzare un form, che invii i suoi dati riferendosi direttamente ad una action specifica, che potrà servirsi del relativo ActionForm per memorizzare i dati. Esaminiamone gli attributi più importanti:

Nome

Funzione

action Deve essere dichiarato l'URL (la action) che riceverà i dati da questo form method Il metodo HTTP per la richiesta

focus

Il nome del campo a cui sarà assegnata la priorità nell'esame della pagina

style

Lo stile CSS da applicare al form

enctype Esprime la codifica del contenuto da usare quando questo form viene passato all'elaborazione

Gli eventi JavaScript

La maggior parte dei tag HTML supportano i gestori degli eventi Javascript (event handler) tramite i loro attributi. Sotto l'elenco degli attributi supportati.

Evento

Si scatena quando

Onblur

l'elemento perde il focus di input

Onclick

l'elemento riceve un click del mouse

Onfocus

l'elemento riceve il focus

Onkeydown

l'elemento ha un focus di input e un tasto è premuto

Onkeypress l'elemento ha un focus di input e un tasto è premuto e rilasciato

onmousemove l'elemento è sotto il puntatore del mouse e il puntatore viene spostato onmousedown l'emenento viene cliccato

Bean taglib e gestione dei messaggi

Bean taglib e gestione dei messaggi

La Bean taglib è stata creata per permettere alle viste (JSP) di accedere ai JavaBeans e alle proprietà loro associate. Inoltre, grazie a questi tag possiamo definire nuovi bean accessibili all'interno di una pagina attraverso variabili di script e attributi con scope di pagina. Ecco un elenco di alcuni di questi tag:

Tag

Descrizione

Cookie

Permette l'accesso al valore di uno specifico request cookie

Define

Definisce una variabile sulla base del valore di uno specifico bean property

Header

Definisce una variabile sulla base del valore di uno specifico request header

Include

Permette di includere una pagina generata da un'action o ad un URL esterno

page

Espone come bean un oggetto dal contesto della pagina specificata

parameter Permette di accedere al valore di un parametro di richiesta resource Rende disponibile il valore di una risorsa di una web application

Il tag <bean:message>: la gestione dei messaggi

Il tag <bean:message>, anche se sembra estraneo alle funzionalità della libreria di tag Bean, è uno dei tag più diffusi di Struts. La sua funzione è quella di prendere un messaggio internazionalizzato per l'area locale del client tramite la Key del messaggio specificata e lo scrive

nell'output. Si usa nel seguente modo:

<bean:message key="

...

"/>

Alcune librerie di Java permettono il supporto della lettura di risorse di messaggi da una classe Java o da un file di proprietà. La classe di partenza è la java.util.ResourceBundle. Struts estende questa funzionalità tramite la org.apache.struts.util.MessagesResources.

Per fissare le idee riprendiamo l'esempio dello struts-blank. La Jsp finale non contiene nessun messaggio ma solo dei tag bean message con le rispettive key:

<bean:message key="welcome.heading"/> <bean:message key="welcome.message"/>

I messaggi sono specificati tramite una key nel file message.propeties nel seguente modo:

welcome.heading=Welcome! welcome.message=To get started on your own application, copy the struts- blank.war to a new WAR file using the name for your application. Place it in your container's "webapp" folder (or equivalent), and let your container auto- deploy the application. Edit the skeleton configuration files as needed, restart your container, and you are on your way! (You can find the MessageResources.properties file with this message in the /WEB-INF/src folder.)

Per creare un message resource con struts, basta creare un file .properties nella cartella WEB INF e dichiarare il nome nello struts-config nel seguente modo:

<message-resources parameter="MessageResources" />

Questa funzionalità oltre a suddividere le varie responsabilità ai singoli componenti, risulta molto utile quando vogliamo internazionalizzare la nostra applicazione ma di questo ci occuperemo nelle lezioni successive facendo un esempio.