Il framework Apache Struts

Transcript

Il framework Apache Struts
LEZIONE 9 - 18/02/2014
© G. Malnati, C. Barberis, 2012-13
L'approccio MVC è così rilevante che la comunità internazionale ha
sviluppato un botto di roba che supporta il paradigma. Apache Struts
è uno dei framework che supporta MVC.
Il framework Apache Struts
A.A. 2012-13
Il motivo per cui è interessante è proprio perchè supporta le diverse
fasi in cui passa un'applicazione. Il problema più grande dell'MVC è
il modello, che dipende solo da noi. Di conseguenza dobbiamo fare
leva su logiche scritte da noi e testarle opportunamente. Per questo
MVC si adatta molto bene in fase di test.
Introduzione
• L’architettura
MVC consente di separare
la logica dalla presentazione
• Facilità di
© G. Malnati, C. Barberis, 2012-13
◦
◦
◦
◦
Le turbe che ci facciamo sulla presentazione sono minime perchè
bene o male va tutto bene.
Sviluppo
Test
Manutenzione dell’applicazione
Estensione
Anche la manutenzione è più facile, perchè sostanzialmente si è fatto un bel divide et impera: quando separo le parti riesco a identificare
prima il problema. Buona anche la manutenzione perfettiva.
2
In Struts 2 ci si è concentrati su MVC. Di base si è partiti da un prodotto un po' commerciale, poi donato alla comunità. Lo citiamo perchè in alcuni namespace che ci verranno tra le mani ci saranno
questi nomi.
Introduzione
•
Il framework open source Struts 2 è stato introdotto
nel 2005
E' il successore di Struts 1, poco estensibile e che non supportava
AJAX e tutto un altro insieme di cose belle.
◦ Implementa il pattern MVC
◦ È basato sul framework OpenSymphony WebWork 2.2
© G. Malnati, C. Barberis, 2012-13
◦ http://struts.apache.org/
•
Aggiunge delle funzionalità mancanti nella versione 1
•
•
•
•
•
•
Estensibilità
Supporto ad AJAX
Internazionalizzazione e localizzazione
Gestione della navigazione nelle pagine
Validazione dei campi di input
Layout consistente
3
Struts 2: Caratteristiche generali
•
Il modello, le viste e il controllore sono implementati dalle
interfacce e classi
•
Il controllore determina l’azione da invocare in base all’URL
contenuta nella richiesta ed al file struts.xml
•
Alla ricezione di una richiesta, viene istanziato l’oggetto
Action corrispondente
◦ Action, Result e FilterDispatcher
© G. Malnati, C. Barberis, 2012-13
◦ Che definisce le corrispondenze richiesta/azione
◦ Ed eseguito il metodo execute()
◦ Questo restituisce un stringa che sarà utilizzata per determinare
quale vista selezionare
•
Le viste possono essere implementate utilizzando differenti
tecnologie
◦ JSP, Velocity Template, Freemaker, …
4
--------------------------------------------------------------------------------------------In generale i principi che ci interessano sono i seguenti:
- abbiamo modelli, viste e controllori. Il controllore, elementare, lo fa
Struts previa configurazione di un filtro nel WebContainer. Il filtro
va configurato sull'URL /* (qualunque cosa che viene chiesta la
prende lui)
- la prima cosa che fa il controllore è capire che azione viene richiesta: siccome Struts intercetta tutto, decide cosa fare in base alla URL
e ha delle sue regole che permettono di mappare un qualcosa sulla
URL a un qualche componente che gestisce il tutto. Il componente
che gestisce la richiesta prende il nome di Action: in Struts è definita un'interfaccia Action e una classe ActionSupport. Quando noi vogliamo implementare i comportamenti relativi alle azioni, creiamo
una classe che implementa l'interfaccia Action o estende
ActionSupport. L'interfaccia Action ha un metodo solo, execute: è
senza parametri e ritorna una stringa
- FilterDispatcher: riceve tutte le richieste, decide in base alla URL a
quale Action è da girare la richiesta e invoca l'oggetto Action, utilizzando execute. In base alla stringa di risposta, il FilterDispatcher
decide quale vista attivare. Ci sono già delle stringhe predefinite,
come SUCCESS, INPUT, ERROR... e possiamo definire qualunque
tipo di risposta. Il filtro mappa le risposte sulle viste corrispondenti,
tramite un insieme di regole (se l'azione A1 ritorna la stringa S2
faccio vedere la vista V5). Se non viene detto niente di meglio, la
vista V5 è raggiungibile a V5.jsp.
E' il motore iniziale che controlla tutto quello che succede.
Struts 2: Caratteristiche generali
Il FilterDispatcher, prima di prendere la richiesta che ha ricevuto e
passarla all'execute fa attraversare la richiesta a un insieme di moduli intermedi, detti intercettori.
framework opera grazie alla presenza di
un filter dispatcher, che ha il compito di
© G. Malnati, C. Barberis, 2012-13
• Il
Ognuno di questi moduli si occupa di un aspetto (intercettore dei parametri, intercettore dell'internazionalizzazione...). Hanno il potere di
stoppare la richiesta, non invocando nemmeno Action. Altrimenti arrivo a eseguire e mi viene restituita la mia bella stringa, torno indietro
ripercorrendo tutta la catena e gli intercettori hanno ancora il potere
di dire la loro.
◦ Esaminare le richieste
◦ Inoltrarle ai controllori
◦ Selezionare la vista da mostrare
• Un
insieme di componenti, chiamati
intercettatori, supportano tali operazioni
automatizzando vari compiti
5
Struts 2: Caratteristiche generali
•
Le URI contenute nelle richieste vengono
mappate sulle singole azioni usando le
informazioni contenute nel file struts.xml
◦ O ricavate in base ad una convenzione, se nel
framework viene incluso il file
Se l'XML viene modificato runtime cambiando il mapping (aggiungo
azioni senza aggiungere nuove classi) non c'è bisogno di ricompilare
l'applicazione: al ricevimento della richiesta si fa quello che si deve.
© G. Malnati, C. Barberis, 2012-13
• struts2-convention-plugin.jar
◦ Eventuali cambiamenti non comportano la
dell’applicazione
ricompilazione dell
applicazione
•
Se la richiesta contiene dei parametri, questi
sono memorizzati dal framework nell
’Action
nell’Action
relativa, prima dell
dell’invocazione del metodo
execute()
Attraverso l'uso di un apposito interceptor, se la richiesta contiene
dei parametri, questi vengono salvati nell'oggetto action.
◦ Utilizzando i metodi setter da essa esposti, che
devono avere il nome corrispondente al parametro
6
Struts 2: Caratteristiche generali
•
Si possono validare i valori in ingresso ad
un’azione e rimandare l’utente sul campo del
form sul quale è fallito il controllo
© G. Malnati, C. Barberis, 2012-13
◦ Attraverso annotazioni o un file xml per la validazione
•
---------------------------------------------------------------------------------------------Le URI delle richieste che ricevo vengono mappate su azioni differenti (ricordati il modello FSM: l'azione serve per sapere dove devo
andare, sotto ben precise condizioni). Si noti che il mapping viene
creato in modo normalmente esplicito andando a creare un file creato struts.xml: le richieste a stringa vuota le mappo ad esempio sulla
homeAction, le richieste che vanno su list le mappo su listAction e
così via...
Possiamo poi installare un plugin: struts2-convention-plugin.jar (installabile solo se ho il core), che usa la convenzione qualcosa ->
qualcosaAction() e evita di fare l'xml.
Il dispatcher, dopo aver esaminato il risultato
dell’azione, può intraprendere diverse azioni
◦ Mostrare una pagina jsp, generare un pdf, mandare un
messaggio di errore, generare pagine d'attesa
(validazione carte di credito), ...
*** ESEMPIO DI DINAMICA ***
1) Arriva una Request 2) Il filtro la prende 3) Qual è la URI? Cerco
la determinata Something 4) Creo un'istanza di SomethingAction,
vuota (= costruttore senza parametri) 5) Una volta creato viene passato agli intercettori: ce ne sono già di precablati, possiamo aggiungerli o toglierli al bisogno 6) L'intercettore di parametri vede se ci sono parametri HTTP, li estrae e vede se l'oggetto Action selezionato
ha il metodo setParametro: se c'è lo invoca, se c'è bisogno di fare
parsing si fa e gli si passa il parametro 7) Sull'oggetto Action ora popolato si invoca execute 8) Quando l'azione è terminata ritorno una
stringa per sapere com'è andata l'esecuzione: se execute ha prodotto dei dati, li ha salvati da qualche parte (tipicamente dentro una
mappa che viene passata) 9) Il filtro guarda il valore ritornato e sceglie la vista che potrà prendere i valori nella mappa per riempire il
template con dei dati significativi
--------------------------------------------------------------------------------------------Tra i vari interceptor c'è validate che verifica se "i dati sono buoni"
attraverso una serie di strumenti per imporre vincoli sui singoli parametri o sui parametri nel loro insieme.
7
© G. Malnati, C. Barberis, 2012-13
Quando arriva una richiesta attraversa una sequenza di filtri:
1) ActionContextCleanUp, non obbligatorio: se messo permette di
garantire che l'elaborazione sia "fresca"
2) Filtri personali
3) FilterDispatcher
Quando il FilterDispatcher prende in mano la cosa interroga l'ActionMapper, oggetto a cui dice: "Mi è arrivata una richiesta, chi è il deputato per questa URL?". Mi viene istanziato un oggetto con l'opportuna Action e glielo passo al FilterDispatcher.
Il FilterDispatcher passa all'ActionProxy che ne governa l'invocazione. Si fa tutta la catena degli intercettori: se uno stoppa gestisco il
tutto, altrimenti l'azione costruita pian piano è pronta. Si arriverà a un
risultato e al suo relativo template. Si ripassa tutto agli intercettori
che possono ancora aggiungere pezzi. Il risultato viene messo dentro la risposta.
8
Struts 2: Flusso di funzionamento
Framework
ActionInvocation - invoke()
Si
© G. Malnati, C. Barberis, 2012-13
L’elaborazione
della richiesta
può continuare?
Lo stack contiene
un nuovo
interceptor?
No
Si
No
Chiamata dell’intercettatore
Chiamata dell’azione
Generazione del risultato
Render del risultato
Post elaborazione
9
Struts 2: Flusso di funzionamento
•
© G. Malnati, C. Barberis, 2012-13
•
La catena degli intercettori viene eseguita attraverso il metodo invoke().
Il controllore riceve la richiesta dell’utente e
determina l’azione da invocare
Il framework crea un’istanza dell’azione richiesta
e seleziona gli intercettatori corrispondenti
◦ Essi validano i parametri ricevuti, effettuano le
conversioni di tipo eventualmente necessarie,
popolano l’oggetto Action
•
Ogni volta che viene chiamato il metodo invoke(),
l’istanza di ActionInvocation consulta il proprio
stato ed esegue il prossimo intercettatore,
attraverso il metodo intercept()
10
Struts 2: Flusso di funzionamento
•
© G. Malnati, C. Barberis, 2012-13
•
Se all'intercettore "piace" la richiesta richiama invoke... e così via fino ad arrivare all'azione.
L’intercettatore, a sua volta,
richiama il metodo invoke()
dell’istanza di ActionInvocation
Dopo aver chiamato tutti gli
intercettatori, viene invocata
l’azione e generato il risultato
◦ Gli intercettatori possono essere
chiamati anche dopo la generazione
del risultato, per rielaborarne il
contenuto
•
Infine, avviene la presentazione
dei risultati
11
LA PRIMA COSA CHE DOBBIAMO FARE è dire che vogliamo questo filtro.
Filter Dispatcher
•È
il cuore del controllore del framework
© G. Malnati, C. Barberis, 2012-13
◦ Verifica l’URI in ingresso e determina quale
azione invocare e quale classe azione Java
instanziare
• Quello
di default ha il seguente nome
◦ org.apache.struts2.dispatcher.ng.filter.
StrutsPrepareAndExecuteFilter
12
Filter Dispatcher
essere registrato nel descrittore di
sviluppo dell’applicazione (web.xml)
© G. Malnati, C. Barberis, 2012-13
• Deve
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.
StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
13
Nel file struts.xml si specifica come mappare le URL ricevute su determinate azioni. Scrivendo che si estende struts-default si va a prendere una catena di intercettori già fatti all'interno.
Gli intercettatori
• Alcuni
compiti del controllore vengono
affidatati a sotto-componenti, gli
intercettatori
© G. Malnati, C. Barberis, 2012-13
◦ Possono essere aggiunti o rimossi
semplicemente modificando il file di
configurazione di struts
◦ Non occorre ricompilare l’applicazione
14
Ne possiamo aggiungere / modificare degli altri.
Gli intercettatori
•
Alias ad esempio permette di trasformare il nome di un parametro
nel nome dell'attributo corrispondente di una nostra Action. Utile se
per qualche motivo dobbiamo interfacciarci con qualcosa di cui non
abbiamo il codice completo.
Di seguito vengono elencati e descritti gli
intercettatori più diffusi
© G. Malnati, C. Barberis, 2012-13
◦ I nomi tra parentesi sono utilizzati per registrare gli
stessi nel file di configurazione
•
Chaining: permettiamo di avere visibili, oltre alla lavagna corrente in
cui ci si scrive cose relative alla richiesta corrente, anche cose della
richiesta precedente. Utile per verificare bontà parametri.
Alias (alias)
◦ Converte parametri simili che possono avere nomi
differenti tra le richieste
•
Chaining (chain)
◦ Se il risultato è di tipo “Chain”, vengono resi disponili
le proprietà della precedente azione a quella corrente
15
Checkbox: gestione decente delle checkbox in HTML.
Gli intercettatori
•
Cookie: permette di aggiungere un cookie all'azione corrente
Checkbox (checkbox)
Conversion Error: se un parametro non viene accettato perchè il suo
tipo non era buono viene visualizzato un messaggio di errore coerente.
© G. Malnati, C. Barberis, 2012-13
◦ Gestisce le checkbox all’interno di un form, in modo tale che
quelle non spuntate possano essere rilevate
•
Cookie (cookie)
•
Conversion Error (conversionError)
◦ Aggiunge un cookie all’azione corrente
Create Session: crea una sessione, se già non esiste. Occhio che
per default il FilterDispatcher NON crea l'oggetto Session, questo per
evitare di caricare il container con contenuti che magari non vengono
utilizzati.
◦ Aggiunge gli errori legati alla conversione dei parametri
all’elenco degli errori presenti nei campi dell’azione
•
Create Session (createSession)
◦ Crea un oggetto HttpSession se questo non esiste già per
l’utente corrente
16
Execute and Wait: quando lato server devo fare un'operazione lunga
permette di generare una pagina d'attesa, elaborare nel frattempo e
quando il risultato è disponibile si sostituisce la pagina.
Gli intercettatori
•
Debugging (debugging)
Exception: permette di mappare eccezioni che possono venire da
una qualche azione in una pagina di risultato
◦ Supporto al debugging
© G. Malnati, C. Barberis, 2012-13
•
Execute and Wait (execAndWait)
File Upload: permette la gestione di POST in cui il Content-Type non
è x-form-www-url-encoded, ma mime-multipart (tipico dell'upload del
file).
◦ Esegue un’azione che richiede un’elaborazione di
tempo lunga in background e nel frattempo manda
all’utente una pagina intermedia di attesa
•
Exception (exception)
◦ Mappa le eccezioni a un risultato
•
File Upload (fileUpload)
◦ Supporto all’upload di file
17
i18n: per l'internazionalizzazione. Dà la possibilità di sostituire delle
parole chiave con la versione tradotta nelle diverse lingue, a patto di
fornire le corrispondenze.
Gli intercettatori
•
I18n (i18n)
Message store: permette di accedere, all'interno della sessione, ad
una serie di messaggi relativi alle azioni precedenti.
◦ Supporto all’internazionalizzazione e alla
localizzazione
© G. Malnati, C. Barberis, 2012-13
•
Logger (logger)
◦ Fornisce in uscita il nome dell’azione
•
Message store (store)
◦ Salva e recupera dalla sessione i messaggi o gli errori
delle azioni o gli errori dei campi, per gli oggetti
Action che implementano l’interfaccia
ValidationAware
18
Parameters: se la richiesta contiene parametri, va a cercare il metodo set opportuno e salva quello che deve salvare
Gli intercettatori
•
Scope: permette di salvare lo stato dell'azione nella sessione o nell'
applicazione.
Model Driven (modelDriven)
◦ Supporto per il pattern model driven per tutte le
classi azione che implementano ModelDriven
© G. Malnati, C. Barberis, 2012-13
•
Parameters (params)
◦ Popola le proprietà dell’azione con i parametri della
richiesta
•
Scope (scope)
◦ Fornisce un meccanismo per salvare lo stato
dell’azione nella sessione o nel contesto
dell’applicazione
19
Servlet Config: permette di accedere agli oggetti richiesta e risposta,
che altrimenti sarebbero nascosti.
Gli intercettatori
•
Servlet Config (servletConfig)
◦ Fornisce l’accesso alle mappe che rappresentano gli oggetti
di tipo HttpServletRequest e HttpServletResponse
© G. Malnati, C. Barberis, 2012-13
•
Static Parameters: permette di accedere alle proprietà contenute in
struts.xml
Static Parameters (staticParams)
Roles: permette di definire ruoli.
◦ Mappa le proprietà definite all’interno del file struts.xml
sulle proprietà dell’azione
Timer: logga quanto dura l'esecuzione di un'azione.
•
Roles (roles)
•
Timer (timer)
◦ Supporta azioni basate su ruoli
◦ Fornisce in uscita il tempo che è stato richiesto per
l’esecuzione dell’azione
20
Token e Token Session: permette di validare la sessione corrente,
guardando il SessionID come un token autorizzativo.
Gli intercettatori
•
Validation: estende Parameter. Permette di andare a vedere se c'è
un file action-validation.xml nella cartella dove c'è la nostra classe
per decidere il range dei nostri parametri in ingresso.
Token (token) - Token Session (tokenSession)
◦ Verifica che sia presente un token valido nella richiesta per evitare l’invio
ripetuto delle stesse informazioni
•
Validation (validation)
◦ Supporto alla validazione dei campi di input (specificati tramite il file actionvalidation.xml)
© G. Malnati, C. Barberis, 2012-13
•
Workflow: chiama validate() presente nell'azione e se fallisce restituisce INPUT.
Workflow (workflow)
◦ Chiama il metodo validate() all’interno della classe azione e restituisce
INPUT in caso di errore
•
Parameter Filter (n/a)
•
Profiling (profiling)
•
Prepare (prepare)
◦ Rimuove i parametri dalla lista di quelli disponibili per l’azione
◦ Supporta la profilatura dell’azione
◦ Se l’azione implementa l’interfaccia Preparable, invoca il metodo prepare()
prima di invocare il metodo di esecuzione vero e proprio
21
Per default questa è la sequenza base. Ci interessa che vengono
chiamati params (setta i parametri), validation (verifica i vincoli) e
workflow (se la verifica è fallita genera INPUT e ricarica la pagina
precedente).
Lo stack di default
•
Struts2 definisce il seguente stack di default
© G. Malnati, C. Barberis, 2012-13
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
exception
servletConfig
prepare
checkbox
multiselect
actionMappingParams
params
conversionError
validation
workflow
22
Le azioni sono classi che hanno il metodo execute. Possono avere
una serie di setter e getter, utilizzabili per ricevere parametri o informazioni ulteriori o mettere a disposizione informazioni alla vista.
Le azioni
•
•
Le azioni permettono di eseguire operazioni all’interno
dell’applicazione
Sono costituite da classi java dotate di metodi e proprietà, secondo
le seguenti regole
© G. Malnati, C. Barberis, 2012-13
◦ Una proprietà deve avere i metodi get e set
◦ Una proprietà può essere di qualunque tipo
◦ La conversione tra tipi String e i tipi elementari avviene
automaticamente
◦ Deve avere un costruttore senza argomenti
◦ Deve avere almeno un metodo
Tutti i getter sono accessibili alle viste. Tutti i setter agli intercettori.
Il costruttore dev'essere senza argomenti. Ci dev'essere almeno un
metodo. Occhio che siccome ogni volta che c'è una richiesta viene
costruito un oggetto, gli attributi sono volatili. Se dobbiamo salvare
delle informazioni dobbiamo appoggiarci su un model, salvandolo
nel contesto.
In base all'URL della richiesta si crea un oggetto istanza della Action.
Per default non si crea la sessione HTTP.
◦ Ad essa si possono associare azioni multiple
◦ Viene creata un’istanza di azione ad ogni richiesta HTTP
◦ Non viene creato un oggetto HttpSession
23
Ha un senso estendere ActionSupport, nonostante un qualche execute venga lanciato comunque, perchè così abbiamo tutta una serie
di benefici.
Le azioni
classe azione può implementare
l’interfaccia
© G. Malnati, C. Barberis, 2012-13
• La
◦ com.opensymphony.xwork2.Action
◦ Direttamente o estendendo la classe
ActionSupport
•È
lecito dichiarare azioni che dispongano
di un metodo execute() ma che non
implementino formalmente l’interfaccia
24
L'azione trovandosi i parametri salvati li può utilizzare e salva nei
propri attributi informazioni visibili alle viste successive. Oltre ai parametri della richiesta veri e propri, Action può analizzare il contesto
più generale del ServletContainer.
Le azioni
• Attraverso
il metodo statico
ActionContext.getContext(), si può
accedere a vari tipi di informazione
© G. Malnati, C. Barberis, 2012-13
◦
◦
◦
◦
◦
◦
La lavagnetta temporanea in cui scrivere dei dati che vanno a beneficio delle viste successive è l'OGNL value stack, in cui troviamo coppie (chiave, valore).
I parametri della richiesta
Gli attributi della richiesta
Gli attributi della sessione
Gli attributi della applicazione
Gli errori rilevati
Lo stack dei valori OGNL
25
Validare i parametri (1)
•
Un'azione può verificare se i parametri ricevuti
sono accettabili per i propri scopi o chiedere
all'utente di inserire valori compatibili attraverso
il metodo validate()
Non ci sono parametri. Se va tutto bene non fa niente, se viceversa
scopre qualcosa che non funziona ha la possibilità di invocare il metodo addFieldError per dire "guarda che user mi è piaciuto, password
un po' meno". Il dato viene sbattuto dentro lo stack: un'eventuale vista attivata potrà accedere all'informazione e visualizzarla vicino al
tag opportuno.
© G. Malnati, C. Barberis, 2012-13
◦ L'intercettore "parameter" è responsabile della sua
invocazione automatica
◦ Se, durante la sua esecuzione, vengono chiamati i
metodi
addFieldError(<fieldName>,<ErrorMsg>)
addActionError(<ErrorMsg>)
i parametri forniti sono considerati errati e l'azione si
interrompe restituendo il valore "input"
◦ Altrimenti si prosegue normalmente, invocando il
metodo execute() e restituendo il valore relativo
26
L'esecuzione degli intercettori, in tal caso, si interrompe. Non arrivo
alla execute e mi viene ritornato INPUT, che di solito viene mappato
in struts.xml in un qualcosa del tipo "torna a dove hai immesso questi parametri". Se validate passa liscio si passa agli intercettori successivi.
Tipica configurazione per validare i parametri. Questa roba va ovviamente in struts.xml
Validare i parametri (2)
© G. Malnati, C. Barberis, 2012-13
LEZIONE 10 - 24/03/2014
C'è un intercettore particolare che si chiama parameter. Invoca sulla
action corrente, se presente, il metodo validate. Di base si è detto
che la nostra richiesta può avere dei parametri.
Dopo che l'interceptor parameter ha chiamato tutti i setter, guarda se
c'è un metodo validate. Se c'è si invoca.
<struts>
<package name="n" extends="struts-default">
<action name="Login" class="ns.Login">
<result name="input">/login.jsp</result>
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
27
E questo è il metodo validate. In alto abbiamo i getter e i setter.
...
Validare i parametri (3)
© G. Malnati, C. Barberis, 2012-13
class Login extends ActionSupport {
private String user,pass;
public String getUser() {return user;}
public String getPass() {return pass;}
public void setUser(String u) {user=u;}
public void setPass(String p) {pass=p;}
public void validate() {
if (user==null|| user.length()==0)
addFieldError("user", "User required");
if (pass==null|| pass.length()==0)
addFieldError("pass", "Pass required");
if (!checkPw(user,pass)) addActionError("reject");
}
public String execute() {return SUCCESS;}
}
28
Nel file struts.xml, all'interno di ogni blocco action ci sono una serie
di sottoblocchi result che hanno un type e un name. Il name è la
stringa ritornata dalla action, il type è cosa farsene.
I risultati
© G. Malnati, C. Barberis, 2012-13
• Un
metodo dell’azione ritorna una stringa Per default mi ritrovo success come nome e dispatcher come tipo.
Dispatcher: quanto contenuto tra <result> e </result> è il nome di
che determina quale risultato eseguire
una pagina a cui andare.
• Un risultato deve avere un nome e un
tipo
◦ Il nome di default è “success”
◦ Il tipo di default è “dispatcher”, che ridirige il
browser a una pagina jsp
◦ Se si usa il convention-plugin, i risultati sono
cercati nella cartella WEB-INF/content
29
...
I risultati
•
Di seguito, vengono elencati e descritti i tipi di risultati
•
•
Chain (chain)
© G. Malnati, C. Barberis, 2012-13
•
•
Consente di effettuare il forward verso una pagina JSP
FreeMarker (freemarker)
•
•
Permette di concatenare i risultati precedenti con quelli attuali
Dispatcher (dispatcher)
•
•
I nomi tra parentesi sono utilizzati per registrare gli stessi nel file di
configurazione
Utilizzato per l’integrazione con FreeMarker
HttpHeader (httpheader)
•
Utilizzato per rispondere al browser con header http
30
I risultati
•
Redirect Action(redirect-action)
◦ Utilizzato per redirigere il risultato ad un’altra azione
•
Stream (stream)
•
Velocity (velocity)
•
XSLT (xslt)
•
PlainText(plaintext)
© G. Malnati, C. Barberis, 2012-13
◦ Utilizzato per mandare un InputStream al browser
◦ Utilizzato per l’integrazione con Velocity
◦ Utilizzato per l’integrazione per XML/XSLT
◦ Utilizzato per mandare del testo in chiaro, generalmente per
mostrare il sorgente di una pagina JSP
31
Per poter creare un'applicazione struts dobbiamo partire da un progetto (meglio se Maven), scaricare le dipendenze e creare nella cartella src/main/resources il file struts.xml che ci permette di impostare l'elenco delle azioni che ci interessano.
File di configurazione
•
Il file struts.xml definisce tutti gli aspetti
dell’applicazione
Tipicamente questo file include una serie di definizioni come ad esempio lo stack di default che conviene usare. Un file importante che
si può mettere è default.properties, in cui posso aggiungere comportamenti particolari di struts.
◦ Include le azioni, gli intercettatori e i possibili risultati
◦ Può ereditare le configurazioni di default del framework
© G. Malnati, C. Barberis, 2012-13
• Sono incluse nel file del framework struts2-core-VERSION.jar
•
Il file default.properties contiene le impostazioni che
vengono utilizzate in tutte le applicazioni struts
◦ Anch’esso incluso nel package struts2-core-VERSION.jar
◦ File opzionale, nel caso in cui vanno bene le proprietà di default
32
Lorem ipsum dolor sit amet.
Il file struts.xml
•
•
L’elemento root è il tag <struts>
Le azioni possono essere raggruppate in package
◦ Quest’ultimo deve avere un attributo name e un namespace
© G. Malnati, C. Barberis, 2012-13
• Il namespace, se non presente, è quello di default “/”
• Per invocare un’azione di un package non presente in un namespace non di
default, si deve specificare il namespace nell’URI
• /context/namespace/actionName.action
<?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="package-1" namespace="namespace-1"
extends="struts-default">
<action name="..."/>
<action name="..."/>
</package>
</struts>
33
Il file struts.xml
•
I package possono essere suddivisi in file distinti
◦ Si utilizza il tag <include>
◦ Ogni tag deve avere lo stesso elemento DOCTYPE e un elemento root
struts
•
Un’azione è posizionata all’interno di un elemento package
© G. Malnati, C. Barberis, 2012-13
◦ Deve avere un attributo "name"
◦ Se non si specifica la classe di azione verrà istanziata la classe di azione
di default
◦ Si può specificare anche il metodo da eseguire quando l’azione viene
invocata
◦ Se non specificato, il metodo di default è execute
◦ <action name="Address_save" class="app.Address" method="save">
34
Il file struts.xml
•
L’elemento <result> è un sotto elemento di <action>
◦ Corrisponde al valore di ritorno di un metodo di un’azione
© G. Malnati, C. Barberis, 2012-13
◦ Un’azione può ritornare differenti risultati, quindi avere differenti
elementi <result>
◦ Se il risultato restituito da un’azione non è presente nel file di
configurazione
• Viene controllato se il esso è presente nell’elemento global-results,
quest’ultimo contenuto all’interno del package
• In caso contrario, viene lanciata un eccezione
◦ L’attributo name, se omesso, assume il valore “success”
◦ L’attributo type specifica il tipo di risultato di ritorno, se omesso assume
il valore “Dispacher”
<action name="Product_save" class="app.Product" method="save">
<result name="success" type="dispatcher”>/jsp/Confirm.jsp </result>
<result name="input" type="dispatcher"> /jsp/Product.jsp </result>
</action>
35
Il file struts.xml
•
Ci sono 5 elementi relativi agli intercettatori che possono comparire nel
file struts.xml
◦ Interceptors, interceptor, interceptor-ref, interceptor-stack, default-interceptorref
© G. Malnati, C. Barberis, 2012-13
•
Gli intercettatori definiti in un package possono essere usati da tutte le
azioni dello stesso
◦ Per applicare un intercettatore a un’azione si utilizza il tag interceptor-ref
<package name="main" extends="struts-default">
<interceptors>
<interceptor name="alias" class="..."/>
</interceptors>
<action name="Product_delete" class="...">
<interceptor-ref name="alias"/>
<result>/jsp/main.jsp</result>
</action>
</package>
36
Lorem ipsum dolor sit amet.
Il file struts.xml
•
L’elemento param è utilizzato per passare un valore a un oggetto
◦ Può essere utilizzato all’interno di: action, result-type, interceptor
© G. Malnati, C. Barberis, 2012-13
◦ Ha l’attributo obbligatorio name
<action name="customer" class="...">
<param name="siteId">california01</param>
</action>
•
L’elemento constant permette di sovrascrivere un’impostazione del
file default.properties
◦ Ha gli attributi name e value
37
Associare URL e azioni (1)
•
Se il progetto include tra le proprie librerie il
file struts2-convention-plugin.jar,
il framework crea un insieme implicito di
corrispondenze URL/azioni
© G. Malnati, C. Barberis, 2012-13
◦ Vengono cercati, tra le classi del progetto, quelle
appartenenti a package il cui nome contenga le
stringhe "struts", "struts2", "action", "actions"
◦ Tutte le classi in tali package (o nei loro sottopackage) che implementano l'interfaccia Action o
il cui nome termina per "Action" sono
considerate azioni
38
Associare URL e azioni (2)
© G. Malnati, C. Barberis, 2012-13
•
Una classe identificata come azione viene mappata su
una URL in base al proprio nome ed al sotto-package
di appartenenza
◦ Il nome viene dapprima privato del suffisso "Action", se
presente
◦ Se ciò che resta del nome usa la convenzione
"CamelCase", viene trasformato in una sequenza di parole
separate da "-"
• "ResetForm" ð "reset-form"
•
L'eventuale sotto-package determina la presenza di
sottocartelle nel path
◦ myproject.actions.resetAction ð /reset
◦ myproject.actions.cart.InsertItem ð /cart/insert-item
39
Legare le azioni ai risultati
convention plugin, per default, cerca i
risultati nella cartella WEB-INF/content
© G. Malnati, C. Barberis, 2012-13
• Il
◦ Secondo il pattern
<actionURL>-<resultCode>.<extension>
◦ Ad esempio, se l'azione "alfa" restituisce il
valore "success", la pagina caricata sarà
WEB-INF/content/alfa-success.jsp
• Le
estensioni supportate sono
◦ jsp, ftl, vm, htm, html
40
Lorem ipsum dolor sit amet.
Usare le annotazioni
© G. Malnati, C. Barberis, 2012-13
•
I singoli metodi presenti all'interno di una
classe possono essere annotati con
@Action("/UrlToBeMapped")
◦ Questo fa aggiungere una corrispondenza tra la
URL indicata ed il metodo annotato
•
Nell'annotazione è anche possibile indicare
quali intercettori debbano essere attivati
◦ Se l'informazione è omessa, viene attivato lo stack
di default
41
Il file struts.properties
•
Può essere creato per sovrascrivere le impostazioni di
default presenti in default.proprerties
© G. Malnati, C. Barberis, 2012-13
◦ Deve essere situato nel classpath o in WEB-INF/classes
◦ In alternativa, si può utilizzare l’elemento constant
◦ Oppure l’elemento init-param all’interno della dichiarazione del
filter dispatcher
<filter>
<init-param>
<param-name>struts.devMode</param-name>
<param-value>true</param-value>
</init-param>
</filter>
42
OGNL
© G. Malnati, C. Barberis, 2012-13
•
Nel pattern MVC la vista ha il compito di rendere
accessibile il modello ed altri oggetti (richiesta,
parametri, sessione, ...) agli utenti
◦ Per accedere ad essi da una pagina JSP si può utilizzare OGNL
(Object-Graph Navigation Language)
◦ Linguaggio ereditato da WebWork
•
OGNL permette di
◦ Associare elementi della GUI agli oggetti del modello e
convertire valore da un tipo all’altro
◦ Associare tag generici con gli oggetti del modello
◦ Creare liste e mappe al volo, che possono essere usate dagli
elementi della GUI
◦ Invocare qualsiasi metodo
43
OGNL - Value Stack
© G. Malnati, C. Barberis, 2012-13
•
Per ogni invocazione di azione, viene creato
l’oggetto Value Stack
◦ Prima dell’esecuzione del metodo execute()
◦ È utilizzato per salvare l’azione e altri oggetti
◦ Viene consultato durante l’elaborazione dagli
intercettatori e anche dalla vista per mostrare i
risultati e altre informazioni
◦ Per potervi accedere, Struts conserva questo oggetto
come un attributo della richiesta chiamato
struts.valueStack
44
Lorem ipsum dolor sit amet.
OGNL – Value Stack
•
Il Value Stack al suo interno contiene due tipologie di
elementi
◦ Object Stack
• Vengono salvate le azioni e le relative proprietà
© G. Malnati, C. Barberis, 2012-13
◦ Context Map
• Vengono salvate tutte le mappe del contesto dell’applicazione
Object 0
Object 1
request
attr
parameters
session
application
45
OGNL – Value Stack
•
Le seguenti mappe vengono salvate nell’oggetto
Context Map
◦ parameters
• Contiene i parametri di richiesta per la richiesta corrente
© G. Malnati, C. Barberis, 2012-13
◦ request
• Contiene tutti gli attributi della richiesta per la richiesta corrente
◦ session
• Contiene gli attributi di sessione per l’utente corrente
◦ application
• Contiene gli attributi di ServletContext per l’applicazione corrente
◦ attr
• Ricerca gli attributi nel seguente ordine: request, session e application
46
OGNL – Accesso ai dati
•
È possibile accedere ai dati di Context Map e Object Stack
•
La ricerca è basata sugli indici
◦ Nel primo caso l’espressione deve iniziare con il carattere ‘#’
© G. Malnati, C. Barberis, 2012-13
◦ Se una determinata proprietà non viene trovata su un preciso oggetto,
la ricerca continuerà sul prossimo oggetto e così via
•
Si possono utilizzare le seguenti forme
◦ object.propertyName
◦ object.[‘propertyName’]
◦ object[“propertyName”]
◦ [0].propertyName
◦ #session.code
◦ #request[“customer”][“contactName”]
47
OGNL – Accesso a dati statici e
metodi
•
Nella vista si possono invocare campi e metodi statici
◦ Non necessariamente presenti nello Stack Value
◦ Per accedervi si usa rispettivamente la seguente sintassi
© G. Malnati, C. Barberis, 2012-13
• @fullyQualifiedClassName@fieldName
• @fullyQualifiedClassName@fieldName
◦ Ad esempio:
• @java.util.Calendar@DECEMBER
• @app04a.Util@now()
•
Se invece si vuole accedere a un metodo dello Stack Value, si
utilizza la seguente sintassi
◦ object.methodName(argumentList)
48
Lorem ipsum dolor sit amet.
I tag di Struts
•
Tag dell’interfaccia utente messi a disposizione
da Struts per interagire con i form HTML e i
suoi elementi
© G. Malnati, C. Barberis, 2012-13
◦ All’inizio della propria pagina jsp bisogna includere la
seguente direttiva
• <%@ taglib prefix="s" uri="/struts-tags" %>
◦ I tag struts sono definiti nel package
org.apache.struts2.components e derivano dalla classe
UIBean
49
Struts tag - attributi
•
Ad un attributo è possibile assegnare un valore statico
o un’espressione OGNL
•
Attributi più comuni
◦ Rispettivamente racchiudendo l’attributo tra “value” e %{value}
© G. Malnati, C. Barberis, 2012-13
◦ cssClass, cssStyle, title, disabled, label*, labelPosition*, key,
requiredposition*, name, required*, tabIndex, value
◦ L’attributo name, in un tag di input, mappa l’elemento alla
rispettiva proprietà dell’azione
◦ L’attributo value mantiene il valore dato dall’utente
◦ L’attributo label definisce l’etichetta dell’elemento
◦ L’attributo key è una scorciatoia per indicare il name e il value
50
Struts tag - attributi
Gli attributi secondari si possono suddividere
nelle seguenti categorie
• Template
•
© G. Malnati, C. Barberis, 2012-13
◦ templateDir, theme, template
•
Javascript
◦ onclick, ondbclick, onmousedown, onmouseup,
onmouseover, onmouseout, onfocus, onblur,
onkeypress, onkeyup, on keydown, onselect, onchange
•
Tooltip
◦ Tooltip, tooltiplconPath, tooltipDelay
51
Configurare un’applicazione
Struts2 in Eclipse 1/2
© G. Malnati, C. Barberis, 2012-13
•
Inserire nella cartella WebContent/WEB-INF/lib almeno i
seguenti file
◦
◦
◦
◦
◦
◦
◦
◦
◦
◦
◦
asm-3.3.jar
asm-commons-3.3.jar
asm-tree-3.3.jar
commons-fileupload-1.2.2.jar
commons-io-2.0.1.jar
commons-lang3-3.1.jar
freemaker-2.3.19.jar
javassist-3.11.0.GA,jar
ognl-3.0.6.jar
struts2-core-2.3.12.jar
xwork-core-2.3.12.jar
59
Lorem ipsum dolor sit amet.
Configurare un’applicazione
Struts2 in Eclipse 2/2
Aggiungere al classpath le cartelle così
inserite
• Selezionare la cartella “Java Resources” con
il tasto destro e creare una nuova cartella
sorgente chiamata “resources”
© G. Malnati, C. Barberis, 2012-13
•
◦ Al suo interno creare il file struts.xml
◦ All’atto dell’esecuzione verrà posto all’interno
della cartella WebContent/ WEB-INF/classes
60
© G. Malnati, C. Barberis, 2012-13
Il file WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app …>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
61