Sei sulla pagina 1di 25

LEZIONE 15 - 14/04/2013

Il framework Spring
E' un framework molto articolato. www.spring.io.
- Spring boot: ci sono gi molte cose preconfigurate che permetto-
no di costruire applicazioni articolate senza nemmeno avere Tom-
cat (usa una versione embedded).
- SPRING FRAMEWORK: parte con due idee fondamentali. La pri-
Tutorial:
ma la dependency injection (= creo e configuro programmi in mo- www.duckranger.com/2011/07/spring-mvc-3-0-with-sts-tutorial-part-i/
do dichiarativo). La seconda la possibilit di aggiungere compor-
tamenti cross-cutting.
- Spring XD: supporto per le operazioni che richiedono la manipola-
C. Barberis, G. Malnati, 2011-14

zione di una grande quantit di dati avendo a disposizione mecca-


nismi precostituiti
- Spring Data: uniforma l'accesso alle basi dati, nascondendo i det-
tagli della tecnologia sottostante.
- Spring Batch: serve per fare operazioni programmate su grossi
moli di dati.
- Spring Security: fornisce meccanismi di autenticazione
- Spring Hateoas: supporto REST
- Spring mobile: implementazione di servizi web per dispositivi mo-
bili

Come fa un oggetto a procurarsi gli altri oggetti con cui relaziona-


Accoppiamento di dati to? Di solito quando noi programmiamo a oggetti, buona parte del
codice scritto per dettare al meglio le dipendenze.
Pressoch tutte le applicazioni sono basate su un Traslando l'esempio in un modello Enterprise, si supponga di avere
insieme di classi che interagiscono secondo una
qualche logica un Manager che gestisce altri Dipendenti. Dentro di s ha il set dei
Nelle applicazioni tradizionali, ciascun oggetto suoi sottoposti. La fregatura di scrivere il codice come nell'esempio
responsabile di ottenere i riferimenti degli oggetti con cui che le classi sono fortemente accoppiate: non posso compilare
deve interagire, detti dipendenze
DamselRescuingKinght senza avere RescueDamselQuest. Abbia-
C. Barberis, G. Malnati, 2011-14

Questo pattern porta alla realizzazione di applicazioni


strettamente accoppiate mo creato un'implementazione particolare di un cavaliere solo per
public class DamselRescuingKnight implements Knight { fargli salvare una damigella.
private RescueDamselQuest quest;
public DamselRescuingKnight() {
quest = new RescueDamselQuest();
}
public void embarkOnQuest() throws QuestException {
quest.embark();
}
}
Applicazioni
Applicaz
Applicazioni
icaz ioni Internet
Int 2

Diciamo allora che un oggetto non deve mai conoscere direttamen-


Accoppiamento di dati te le classi degli altri oggetti, ma solo la loro interfaccia. Quindi di-
pendenze ok, ma bisogna conoscere le interfacce.
Linterazione fra oggetti fondamentale in ogni
programma Dopodich io so di avere un oggetto quest all'interno. Io per voglio
Ma laccoppiamento stretto fra oggetti produce codice
un quest particolare. Come faccio a procurarmelo? Spring dice che
difficile da testare, riutilizzare e da capire quando io voglio che dentro un oggetto ne finisca un altro, la cosa
da dichiarare in un file esterno: sar uno strato SW a popolare gli
Il framework Spring permette di evitare
C. Barberis, G. Malnati, 2011-14

oggetti con le dipendenze di cui hanno bisogno. Questo principio si


laccoppiamento stretto
chiama dependency injection.
Le dipendenze fra oggetti vengono generate allatto della
creazione da una terza parte che coordina gli oggetti nel
sistema
Questa tecnica prende il nome di dependency injection
http://www.springsource.org/spring-framework

Applicazioni Internet 3

L'idea che il mio programma si appoggia su uno strato SW chia-


Dependency Injection mato contenitore (!= al contenitore Tomcat che ha milionate di clas-
si). Il contenitore consulta il file di configurazione e sulla base di ci
che trova scritto implementa l'oggetto e me lo restituisce. Si pu im-
Tutte le dipendenze vengono create da un plementare il concetto di singleton (una sola istanza), uno ogni vol-
contenitore ta che lo chiedo, uno ogni nuova sessione di lavoro, e cos via...
Successivamente sono iniettate nel programma
principale sotto forma di propriet degli oggetti
Il programma diventa cos in grado di eseguire la
C. Barberis, G. Malnati, 2011-14

propria elaborazione
Approccio contrario alla normale creazione di
applicazioni
Lapproccio tradizionale infatti prevede che il punto di
ingresso del programma crei tutte le dipendenze e
che successivamente avvenga lelaborazione

Applicazioni Internet 4
Perch l'accoppiamento delle classi sia "debole", una classe non
Dependency injection deve contenere dentro di s riferimenti ad altre classi applicative
(quelle che descrivono il dominio nel quale io lavoro). Se una clas-
se ha bisogno di usarne un'altra, lo fa in quanto implementazione di
Per garantire un accoppiamento debole, ciascun un'interfaccia.
oggetto dovrebbe conoscere le proprie dipendenze
soltanto in termini di interfaccia Qui ad esempio abbiamo un cavaliere coraggioso. Non sa di preci-
In modo da legare la classe allinterfaccia piuttosto che so quale impresa vuole compiere.
allimplementazione
C. Barberis, G. Malnati, 2011-14

Allatto della creazione, verr indicato loggetto da


utilizzare
public class BraveKnight implements Knight {
private Quest quest;
public BraveKnight(Quest quest) {
this.quest = quest;
}
public void embarkOnQuest() throws QuestException {
quest.embark();
}
}
Applicazioni Internet
Appl Int t 5

Come faccio a iniettare le cose? L'idea di descrivere gli oggetti


Dependency injection che voglio usare nel mio programma tramite un XML.

In questo caso un bean una qualunque classe Java, con dei meto-
Spring permette di creare le associazioni fra i
di setter e getter. Ogni bean ha un nome e fa riferimento a una clas-
diversi oggetti dellapplicazione tramite un file se. All'interno del tag bean posso mettere delle informazioni: nell'
xml esempio quando qualcuno chiede knight, l'XML si accorge che ser-
<?xml version="1.0" encoding="UTF-8"?> ve anche un quest da passare al costruttore.
<beans
C. Barberis, G. Malnati, 2011-14

xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/
beans http://www.springframework.org/schema/beans/spring-
beans-3.0.xsd">

<bean id="knight" class="example.BraveKnight">


<constructor-arg ref="quest" />
</bean>
<bean id="quest" class="="example.SlayDragonQuest" />
</beans>
Applicazioni
Applicaz
Appl icazioni
icazioni Internet
Int 6

E' un componente SW che si occupa di creare gli oggetti. Non solo


Contenitore li crea ma ne gestisce le dipendenze e il ciclo di vita. E' dunque un
oggetto che fa da schermo per la creazione di altri oggetti (bean).
Ci sono due tipi di contenitori, uno pi semplice e uno pi sofisticato.
Le applicazioni basate su Spring vivono allinterno di un Noi usiamo ApplicationContext.
contenitore
Componente software che crea gli oggetti, li collega tra loro, li
configura e ne gestisce il ciclo di vita Spring va benissimo in tutte quelle situazioni in cui dobbiamo gestire
Spring offre due tipi di contenitori oggetti, non necessariamente web.
C. Barberis, G. Malnati, 2011-14

BeanFactory (adatti a scenari molto semplici)


ApplicationContext (adatti a scenari di complessit arbitraria)

public class KnightMain {


public static void main(String[] args) {
ApplicationContext context = new
ClassPathXmlApplicationContext("knights.xml");
Knight knight = (Knight) context.getBean("knight");
knight.embarkOnQuest();
}
}
Applicazioni Internet 7

E' il contenitore pi semplice. L'unica funzione che sa mettere in at-


XmlBeanFactory to creare dei bean. Quando crea un bean crea anche tutte le rela-
tive dipendenze.
Semplice contenitore fornito da Spring
Implementa linterfaccia Qui abbiamo un BeanFactory che crea dei trade-beans, oggetti atti
org.springframework.beans.factory.BeanFactory a gestire una qualche transazione commerciali.
Crea e istanzia i bean insieme a tutte le configurazioni di
dipendenza
Quando viene richiesto un bean, il client ne ottiene
C. Barberis, G. Malnati, 2011-14

unistanza completamente funzionale


Tutte le associazioni e le relazioni vengono create prima di creare
il bean
Utilizzato solitamente per applicazioni mobili o nei
contesti in cui le risorse sono limitate
// Instantiate the factory with your beans config file
BeanFactory factory =
XmlBeanFactory(new FileInputStream("trade-beans.xml"));
// Use the factory to obtain your TradeService bean
TradeService service = (TradeService)
factory.getBean("tradeService");
Applicazioni Internet
Int t 8
ApplicationContext estende XMLBeanFactory e introduce cose che
ApplicationContext mi servono nelle applicazioni web.

- Caricamento dinamico di risorse: posso avere pezzi determinati a


Estensione dellinterfaccia BeanFactory che, alla runtime che "riempiono" l'XML. E' interessante perch magari og-
gestione del ciclo di vita dei bean, aggiunge il ni volta che creo un cavaliere voglio mettergli lo stampino, median-
supporto per te opportune callback.
Il caricamento dinamico di risorse - Internazionalizzazione dei messaggi: in un oggetto posso mettere
delle stringhe che possono essere costanti oppure chiavi in una
C. Barberis, G. Malnati, 2011-14

Una versione estesa del pattern observer con il


supporto della tecnica publish/subscribe mappa che pu avere tante versioni diverse in funzione del locale
corrente
Il supporto allinternazionalizzazione dei messaggi
- Gestione annidata dei contesti: io ho dei contesti relativi alla ri-
La gestione annidata di contesti chiesta in quanto tale.

Applicazioni Internet 9

Ci sono molte implementazioni concrete.


Implementazioni di - FileSystemXmlApplicationContext: vuole un path assoluto
ApplicationContext - ClassPathXmlApplicationContext: cerco nel classpath del conteni-
FileSystemXmlApplicationContext
tore
Carica le definizioni dei bean a partire da un file XML, di cui viene - WebXmlApplicationContext: quello che ci interessa.
specificato il percorso
ClassPathXmlApplicationContext
Il file di configurazione viene cercato nel classpath del contenitore
WebXmlApplicationContext
C. Barberis, G. Malnati, 2011-14

Il file XML viene caricato a partire da unapplicazione web


ApplicationContext ctx =
new FileSystemXmlApplicationContext("/opt/temp/trade-beans.xml");

ApplicationContext ctx = new


ClassPathXmlApplicationContext("trade-beans.xml");

XmlWebApplicationContext ctx = new XmlWebApplicationContext();


ctx.setConfigLocation ("/WEB-INF/applicationContext.xml");
ctx.setServletContext (pageContext.getServletContext());
ctx.refresh ();
Applicazioni Internet 10

Si diceva che un contenitore gestisce e produce dei bean. Un bean


Bean in Spring un oggetto qualunque costruito a partire dal nome della sua clas-
se e da eventuali parametri inseriti nell'XML (dipendenze, ciclo di vi-
ta delle istanze, visibilit...)
In Spring, qualunque oggetto pu essere un Queste informazioni possono essere date tutte per esplicito in un fi-
bean le XML o espresse mediante annotazioni.
Un bean unistanza che viene creata dal framework
sulla base della sua definizione di classe
C. Barberis, G. Malnati, 2011-14

I metadati di configurazione indicano gli oggetti


da istanziare, quali dipendenze devono essere
iniettate, la visibilit ed il ciclo di vita delle
istanze,
I metadati possono essere forniti in un file XML
Oppure come annotazioni o Java Configuration

Applicazioni Internet 11

Ciclo di vita di un bean Una volta che l'oggetto creato, il contenitore si chiede: "Ma questo
oggetto implementa una delle interfacce che io conosco?". Se ad
esempio un oggetto implementa BeanNameAware gli dico che sar
Il contenitore carica le definizioni dei bean noto al codice applicativo con un nome ben specifico.
Quando gli viene chiesto un bean specifico lo istanzia
Il bean viene popolato con le propriet dichiarate nelle definizioni
Se una propriet ha un riferimento ad un altro bean, questo viene creato e
inizializzato prima di creare il bean che lo referenzia
Se il bean implementa determinate interfacce, vengono chiamati i
metodi appropriati
C. Barberis, G. Malnati, 2011-14

Come BeanNameAware o BeanFactoryAware


Il framework invoca i metodi di pre-inizializzazione di
BeanPreProcessor
Se specificato, viene invocato uno specifico metodo di
inizializzazione
Se viene indicato un BeanPostProcessor, il framework ne invoca il
metodo di post-inizializzazione

Applicazioni Internet 12
Ciclo di vita di un bean Questo tutto il giro completo.
1) Recupero dall'XML il nome della classe e creo un'istanza
2) Popolo le propriet (nell'esempio del cavaliere, quest)
3) "Caro oggetto, sappi che tu ti chiami..."
4) "Guarda che tu sei appena stato creato da me..."
5) "Chi l'ApplicationContext che l'ha fatto"
...
C. Barberis, G. Malnati, 2011-14

Ho un mucchio di punti di appoggio in cui inserire il codice che mi


serve. Se non dobbiamo fare niente, boh, sticazzi, non scrivo nulla.
Molto meglio rispetto a doverlo pensare.

Il bean resta vivo fintantoch il contenitore vivo.

Applicazioni Internet 13

Configurazione di Spring Dovendo lavorare con Spring dobbiamo preparare un file XML in
cui indichiamo una serie di bean. Per ciascuno di essi abbiamo un
identificatore e la relativa classe. All'interno di un bean posso mette-
La configurazione di Spring viene inserita in uno re tutte le dipendenze.
o pi file XML
Contiene le dichiarazioni dei bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
C. Barberis, G. Malnati, 2011-14

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<bean id="..." class="...">
<! qui si inseriscono i collaboratori
e la configurazione di questo bean -->
</bean>
<! altri bean -->
</beans>
Applicazioni Internet 14

Configurazione di Spring

Il file XML deve contenere la definizione di


almeno un bean
Ciascuna definizione contiene una serie di
informazioni
C. Barberis, G. Malnati, 2011-14

Come il nome e la classe


Lo scope del bean, le sue dipendenze,
Durante lesecuzione, il framework utilizza le
definizioni per creare unistanza del bean

Applicazioni Internet 15

Configurazione tramite XML Siccome brutto creare un file con 5000 righe, fai tanti XML separa-
ti, suddivisi in base alle funzionalit (es.: Business.xml, Login.xml,
ClasseDAO.xml).
possibile suddividere le definizioni dei bean
allinterno di pi file Si possono creare bean anonimi solo quando vogliamo che ci siano
Suddividendoli, ad esempio, per funzionalit (business propriet collegate 1:1 con qualcun altro. Non sono accessibili se
bean, dao, utility beans, ) non nel contesto in cui sono inseriti.
C. Barberis, G. Malnati, 2011-14

Solitamente, ciascun bean ha un nome o un


identificativo
possibile creare bean anonimi, che non possono
essere interrogati dal codice client

Applicazioni Internet 16
Le dipendenze sono specificate nel momento in cui il codice viene
Injection tramite costruttore costruito.
I pezzi che servono al costruttore sono dichiarati in ordine!

I parametri che devono essere passati al Il vantaggio che se il bean viene costruito allora ha tutte le parti di
costruttore vengono specificati nel file di cui ha bisogno. Altrimenti c' una qualche eccezione (perch maga-
configurazione ri Sonnet29 non un poem).
Tramite il tag <constructor-arg>
public class PoeticJuggler extends Juggler {
C. Barberis, G. Malnati, 2011-14

private Poem poem;


public PoeticJuggler(int beanBags, Poem poem) {
super(beanBags);
this.poem = poem;
}
...
} <bean id="sonnet29" class=Sonnet29" />
<bean id="poeticDuke" class="PoeticJuggler">
<constructor-arg value="15" />
<constructor-arg ref="sonnet29" />
</bean>
Applicazioni Internet 17

C' anche la possibilit di preparare un metodo static che fa da fac-


Istanziare una classe tramite un tory e di dire al contenitore chi chiamare. Questo utile per imple-
metodo factory mentare una classe singleton.
Lattributo factory-method permette di
specificare un metodo statico da invocare per la
costruzione di un oggetto
Utile per istanziare una classe singleton
C. Barberis, G. Malnati, 2011-14

public class Stage {


private Stage() {
}
private static class StageSingletonHolder {
static Stage instance = new Stage();
}
public static Stage getInstance() {
return StageSingletonHolder.instance;
}
} <bean id="theStage"
class="Stage"
factory-method="getInstance" />
Applicazioni Internet
ernet
erne 18

Quando creo un bean posso aggiungergli anche un livello di visibili-


Scope dei bean t. Per default il container lo tratta come se fosse un singleton (a li-
vello applicativo: se ho due container separati ho due istanze!).
Singleton
Viene creata una singola istanza per contenitore (comportamento di Se vogliamo pi istanze possiamo aggiungere l'annotazione Proto-
default) type.
Prototype
Crea una nuova istanza tutte le volte che viene effettuata una chiamata per
Se siamo nel contesto di un'applicazione web possiamo anche fis-
ottenere il bean sare come scope Request: in questo caso ogni volta che verr in-
Request vocato getBean otteniamo oggetti distinti quando le richieste sono
C. Barberis, G. Malnati, 2011-14

Ogni richiesta HTTP disporr di una propria istanza


Session distinte.
Il bean legato al ciclo di vita di una sessione HTTP
Global-session
Lo scope del bean quello di una sessione HTTP globale (insieme delle
sessioni utilizzate dai "portlet" contenuti in una stessa web application
Gli ultimi tre scope sono disponibili solo per le implementazioni
web di ApplicationContext
Come XmlWebApplicationContext
<bean id="ticket"
class="Ticket" scope="prototype" />
Applicazioni Internet
ernet
erne 19

Se non vogliamo creare dipendenze nel costruttore possiamo farlo


Pre e post elaborazione successivamente. Le differenze possono essere create dal singolo
oggetto indicando un init-method o un destroy-method.
Spring fornisce due metodi per linizializzazione
delle propriet e per il rilascio di risorse Potrebbe venir comodo che la lista venga inizializzata in un metodo
init-metod: viene invocato dopo la creazione di un bean
secondario. Questo ha un senso in quelle situazioni in cui pensia-
mo che una certa risorsa sia accessibile "un po' pi avanti", ovvero
destroy-metod: viene invocato prima della distruzione di
un bean quando altri oggetti sono stati creati. Prima faccio le cose essenzia-
C. Barberis, G. Malnati, 2011-14

li.
<bean name="fileReader" class="FileReader"
init-method="init" destroy-method=cleanUp>

public class FileReader implements Reader {


private List<Location> locations = null;
public void init(){
locations = new ArrayList<Locations>();
}
public void cleanUp(){
locations = null;
}
}
Applicazioni Internet
Int 20
Una cosa analoga alla slide precedente.
Pre e post elaborazione Nell'esempio creo un oggetto di classe Connection. Vorrei che la
connessione sia gestita da Java.

In alternativa, si possono implementare le Dopo che tutte le restanti dipendenze mi sono state iniettate, vai a
interfacce fornite da Spring registrarti con JMX. Quando sei stato distrutto, cancellati.
InitializingBean con il metodo afterPropertiesSet()
permette linizializzazione
DisposableBean con il metodo destroy() per il rilascio
C. Barberis, G. Malnati, 2011-14

di risorse
public class Connection implements InitializingBean, DisposableBean
{
private ObjectName objectName;
//InitializingBean's method implementation
public void afterPropertiesSet(){
connection.registerToJmx(objectName);
}
//DisposableBean's method implementation
public void destroy(){
connection.unregisterFromJmx(objectName);
}
} Appl
Applicazioni Internet 21

Le dipendenze sono iniettabili nel costruttore o separatamente, an-


Iniettare propriet dando a dire che il costruttore privo di argomenti e tutti gli altri pez-
zi di cui posso aver bisogno sono accessibili mediante getter o set-
ter e li posso applicare in qualunque momento.
possibile iniettare delle propriet tramite il
kenny un bean che implementa l'interfaccia performer, che presup-
metodo setter relativo utilizzando il tag <property>
pone che ci sia qualche strumento che lui suona: questo gli viene
public class Instrumentalist implements Performer {
private String song; passato nelle propriet.
private Instrument instrument;
public Instrumentalist() { }
C. Barberis, G. Malnati, 2011-14

public void setSong(String song){


this.song=song;
}
public void setInstrument(Instrument instrument){
this.instrument=instrument;
}
}
<bean id="kenny" class="Instrumentalist">
<property name="song" value="Jingle Bells" />
<property name="instrument" ref="saxophone" />
</bean>
Applicazioni Internet
<bean id="saxophone" class="Saxophone" /> 22

Questo si presta sia a iniettare oggetti con nome (fai riferimento all'
Iniettare inner bean unico sassofono del mio progetto) o posso far s che kenny suoni
il proprio sassofono, che non ha nulla a che fare con quello degli
altri. L'inner bean costruito quando costruisco kenny: quando
Gli inner bean sono bean definiti nello scope di qualcuno fa la get di un sassofono ottiene come istanza quella dell'
altri bean ultima riga, su kenny invece c' un'istanza differente
Non necessitano di un attributo id perch non verr Gli inner bean non hanno un campo ID perch altrimenti sarebbero
mai fatto riferimento ad essi tramite il loro accessibili per nome. Cos invece sono accessibili solo nel contesto
identificativo dell'enclosing bean.
C. Barberis, G. Malnati, 2011-14

Non possono essere referenziati da altri bean

<bean id="kenny" class="Instrumentalist">


<property name="song" value="Jingle Bells" />
<property name="instrument" >
<bean class="Saxophone" />
</property>
</bean>
<bean id="saxophone" class="Saxophone" />
Applicazioni Internet 23

Posso iniettare collezioni di dati...


Iniettare collezioni di dati

Iniettare liste o insiemi di dati non duplicati


public class OneManBand implements Performer {
private Collection<Instrument> instruments;
public OneManBand() { }
public void setInstruments(Collection<Instrument> inst){
this.instruments = inst;
C. Barberis, G. Malnati, 2011-14

}
}

<bean id="hank" <bean id="hank"


class="OneManBand"> class="OneManBand">
<property name="instruments"> <property name="instruments">
<list> <set>
<ref bean="guitar" /> <ref bean="guitar" />
<ref bean="cymbal" /> <ref bean="cymbal" />
<ref bean="harmonica" /> <ref bean="harmonica" />
</list> </set>
</property> </property>
</bean> </bean>
Applicazioni Internet 24
...oppure mappe.
Iniettare collezioni di dati

Iniettare mappe
public
public
class
class
OneManBand
JMSSource{
implements Performer {
private
private
Map<String,
Map sourceProps
Instrument>
= null;
instruments;
public
public
OneManBand()
void setProperties(Map
{ } props){
public void
sourceProps
setInstruments(Map<String,
= props; Instrument> inst){
} this.instruments = inst;
C. Barberis, G. Malnati, 2011-14

}}
}

<bean id="hank" class="OneManBand">


<property name="instruments">
<map>
<entry key="GUITAR" value-ref="guitar" />
<entry key="CYMBAL" value-ref="cymbal" />
<entry key="HARMONICA" value-ref="harmonica" />
</map>
</property>
</bean>
Applicazioni Internet 25

Posso anche specificare determinate propriet.


Iniettare collezioni di dati

Iniettare propriet
private Properties instruments;
public void setInstruments(Properties instruments) {
this.instruments = instruments;
}
C. Barberis, G. Malnati, 2011-14

<bean id="hank" class="OneManBand">


<property name="instruments">
<props>
<prop key="GUITAR">STRUM STRUM STRUM</prop>
<prop key="CYMBAL">CRASH CRASH CRASH</prop>
<prop key="HARMONICA">HUM HUM HUM</prop>
</props>
</property>
</bean>

Applicazioni Internet 26

Se io mi adeguo alle convenzioni, per, la maggior parte delle cose


Auto wiring non ho bisogno di dirle. Il framework, guardando come sono fatte
le cose, provvede per i fatti suoi riempiendo i pezzi. La cosa fatta
a condizione che la cosa non sia fonte di ambiguit.
Spring permette di non inizializzare esplicitamente
le propriet e i valori, ma di delegare al framework Tre tecniche possibili:
tale compito - per nome
Quando non c ambiguit sugli oggetti da iniettare - per tipo
possibile utilizzare diverse tipologie di autowire - per costruttore
C. Barberis, G. Malnati, 2011-14

Per nome - autodetect (prima provo per costruttore, poi per tipo)
Per tipo
Per costruttore
Autodetect
Il framework tenta di utilizzare prima lautowire per costruttore,
poi quello per tipo

Applicazioni Internet 27

Se ha bisogno della propriet Instrument, si chiede: tra tutti i bean


Autowire per nome che io conosco, ce n' uno con la I minuscola? Se s, metto quello.
Se non lo trovo genero un'eccezione.

Il contenitore cerca, per ogni propriet, il bean il kenny ha bisogno di una canzone e di uno strumento. La canzone
cui nome nel file di configurazione coincide con data in modo esplicito, dello strumento non diciamo nulla sapendo
il nome della propriet che lui al suo interno ha una propriet instrument. Spring capisce
Se vengono trovate le corrispondenze, i bean relativi e dice: "ok, lo strumento l'unico che c' qui dentro".
vengono iniettati, altrimenti viene generata
C. Barberis, G. Malnati, 2011-14

uneccezione Se pi oggetti hanno una propriet con lo stesso nome tutti ricevono
Se pi bean hanno una propriet con lo stesso nome, lo stesso elemento
verr iniettato sempre lo stesso oggetto
<bean id="kenny"
class="Instrumentalist"
autowire="byName">
<property name="song" value="Jingle Bells" />
</bean>
<bean id="instrument" class="Saxophone" />

Applicazioni Internet 28
Ci che succede che io vado a cercare un bean il cui nome coinci-
Autowire per tipo de col nome del tipo della propriet. Eventualmente posso aggiun-
gere indicazioni.
Il contenitore cerca, per ogni propriet, un bean kenny sceglie l'autowire by type. Ho dichiarato tre strumenti: il sas-
il cui tipo coincide con il tipo della propriet sofono, il tamburo e un altro sassofono (con un nome diverso). Sic-
Se viene trovata una sola corrispondenza, i bean come Instrumentalist ha bisogno di uno strumento vedo chi imple-
relativi vengono iniettati menta l'interfaccia Instrument.
Altrimenti viene generata uneccezione
C. Barberis, G. Malnati, 2011-14

Per evitare le ambiguit, si pu segnalare che Il primo pu starci. Il secondo ha scritto primary=false. Se non ci fos-
Un dato bean non un candidato primario per se nessun altro prenderei lui. Il terzo ha scritto autowire-candidate=
liniezione, con il lattributo primary=false false e quindi non viene nemmeno considerato.
Un bean non pu essere utilizzato per lautowiring
<bean id="kenny" class="Instrumentalist" autowire="byType">
<property name="song" value="Jingle Bells" />
</bean>
<bean id="instrument" class="Saxophone" />
<bean id="drum" class="Drum" primary=false" />
<beanApplicazioni
id="saxophone"
Internet class="Saxophone" autowire-candidate="false" /> 29

Quando le dipendenze vengono iniettate tramite costruttore, lui va a


Autowire per costruttore cercare tra tutti i bean che conosce se ce n' qualcuno che ha tipo
compatibile con quelli del costruttore. Non dev'esserci ambiguit.
Se il costruttore di un bean necessita di
parametri possibile utilizzare lautowire per Supponiamo di avere TradePersistor che si occupa di rendermi per-
costruttore sistente una qualche transazione commerciale. TP ha bisogno nel
Il contenitore cerca un bean del tipo richiesto e lo suo costruttore di un DataSource: posso limitarmi a dire Autowire=
inietta nel costruttore "constructor" confidando che da qualche parte ci sia UN SOLO bean
C. Barberis, G. Malnati, 2011-14

Se pi bean soddisfano gli argomenti del costruttore, di tipo DataSource, che verr automaticamente selezionato e passa-
viene generata uneccezione to al costruttore.
public class TradePersistor {
public TradePersistor (DataSource datasource){ ..}
}

<bean name="tradePersistor" class="TradeReceiver"


Autowire="constructor"/>

Applicazioni Internet 30

Le funzionalit offerte da injection sono alla base di tutti i moduli of-


I moduli offerti da Spring ferti da Spring. Le cose di cui abbiamo parlato finora vivono nel co-
re.
Noi non vedremo gli aspetti della linea intermedia (AOP, Aspects...).
Diciamo solo che per capire cosa succede nel nostro codice aggiun-
giamo dei meccanismi per fare del log. Qui invece possiamo dichia-
rare queste cose con delle annotazioni e un pezzo di codice si oc-
cupa, all'atto del mapping in memoria, di aggiungere delle funziona-
lit derivate.
C. Barberis, G. Malnati, 2011-14

Applicazioni Internet 31

Lo strato CoreContainer
I moduli "core" e "bean" costituiscono
l'infrastruttura base del framework
Offrono i meccanismi di inserimento delle diepndenze e
dell'inversione del controllo e l'accesso ai bean tramite
BeanFactory
Il modulo "expression language" offre l'accesso ad
C. Barberis, G. Malnati, 2011-14

un linguaggio sofisticato per la manipolazione del


grafo degli oggetti durante l'esecuzione
Il modulo "context" generalizza l'accesso agli
oggetti
Supporta l'internazionalizzazione, la propagazione degli
eventi, il caricamento delle risorse e la creazione di
contesti specializzati

Applicazioni Internet 32
All'interno dello strato web ci sono alcune cose fondamentali:
Lo strato web - gestione di cose di uso frequente (ServletListener, upload multi-
part...)
- servlet (contiene l'implementazione del paradigma MVC)
Il modulo "web" offre funzionalit generali nel contesto
di applicazioni web
Supporta l'invio di file tramite il meccanismo "multipart file-
upload", l'inizializzazione di un un contesto web utilizzando un
servlet listener, il supporto alla remotizzazione di oggetti tramite
http
Il modulo "servlet" contiene l'implementazione di spring
C. Barberis, G. Malnati, 2011-14

del paradigma MVC


Permette di creare applicazioni web flessibili e debolmente
accoppiate con il framework stesso
Offre un sistema potenzialmente pi flessibile di quello offerto
da Struts
Il mdoulo Web-Portlet offre un'implementazione del
pattern MVC in ambienti basati su portlet

Applicazioni Internet 33

La cosa base che occorre notare che per poter utilizzare spring
Configurazione di un progetto sufficiente includere le tre dipendenze qui riportate.

Utilizzando Maven, si pu creare un progetto


web legato a tre sole dipendenze
spring-webmvc
servlet-api
C. Barberis, G. Malnati, 2011-14

jstl

Applicazioni Internet 34

Cos come in Struts anche qui abbiamo un punto di ingresso princi-


Costruire applicazioni web con pale che intercetta le richieste che giungono al container e in base
a tutti i parametri in suo possesso decide come comportarsi.
Spring
1. La richiesta proveniente dal browser arriva al La prima azione farne il mapping della richiesta, andando a vede-
DispatcherServlet di Spring re la URL e confrontandola con quella dei vari controllori. Tipica-
Punto di accesso unico mente andiamo a indicare i controllori in un file .XML o con annota-
org.springframework.web.servlet.DispatcherServlet zioni (e nel file XML inseriamo il package che contiene i nostri con-
Contiene informazioni su cosa lutente sta richiedendo trollori). Viene istanziato il controllore e invocato: viene restituito un
C. Barberis, G. Malnati, 2011-14

LURL di destinazione
Eventuali parametri aggiuntivi, come quelli inseriti in una form
oggetto di tipo ViewModel che contiene una stringa che ci dice
quale sar la view da far vedere, nonch un insieme di coppie chia-
vi, valori utilizzabili nella vista. Tornare solo la stringa d una sod-
Req
Request
1
Dispatcher disfazione limitata: per questo motivo i metodi dei controllori pos-
servlet
sono ad esempio avere come parametro un oggetto che implemen-
ta l'interfaccia Model (vedi al fondo) in modo da attingere a informa-
zioni precedenti o predisporre informazioni successive, utilizzate
Applicazioni Internet
pi avanti dalle viste.
35
La vista viene poi scelta dal ViewResolver, che nel modo pi sempli-
ce pu appendere .jsp e prependere WEB-INF.
Costruire applicazioni web con
Spring
2. Il DispatcherServlet deve consegnare la
richiesta ad un controllore
Vengono consultati uno o pi gestori dei mapping per
capire qual il controllore adeguato
C. Barberis, G. Malnati, 2011-14

Handler
2 mapping
Request
Req Dispatcher
1
servlet

Applicazioni Internet 36
Costruire applicazioni web con
Spring
3. Il DispatcherServlet consegna la richiesta al
controllore
Il controllore analizza, elabora e rimuove i parametri
della richiesta
C. Barberis, G. Malnati, 2011-14

Handler
2 mapping
3
Request
Req Dispatcher
1 Controller
servlet

Applicazioni Internet 37

Costruire applicazioni web con


Spring
4. Spesso la logica del controller richiede che
delle informazioni vengano restituite allutente
e visualizzate nel browser
Queste informazioni compongono il modello
C. Barberis, G. Malnati, 2011-14

Handler
2 mapping
3
Request
Req Dispatcher
1 Controller
servlet Model and logical
view name 4

Applicazioni Internet 38

Costruire applicazioni web con


Spring
5. Il DispatcherServlet si occupa di identificare
la vista opportuna per mostrare i dati
allutente
Consulta il ViewResolver fornendogli il nome logico
C. Barberis, G. Malnati, 2011-14

della vista ricevuto nel passo precedente

Handler
2 mapping
3
Request
Req Dispatcher
1 Controller
servlet Model and logical
view name 4

ViewResolver
Applicazioni Internet 39

Costruire applicazioni web con


Spring
6. Il DispatcherServlet consegna alla vista i dati
presenti nel modello
La vista li utilizza per costruire unappropriata
rappresentazione grafica
C. Barberis, G. Malnati, 2011-14

Handler
2 mapping
3
Request
Req Dispatcher
1 Controller
servlet Model and logical
view name 4

6 5

View ViewResolver
Applicazioni Internet
erne 40
Possono avvenire un mucchio di cose: la richiesta arriva in alto al
Il quadro complessivo container che stiamo usando (Tomcat) nel quale configurata una
web application con determinati filtri. Dopo aver attraversato i filtri
si arriva al DispatcherServlet utilizzato per intercettare le richieste.
Il DispatcherServlet:
- capisce se nella richiesta indicato un locale
- capisce stato configurato un tema per la nostra applicazione
- capisce se c' bisogno di salvare il contenuto di una POST
Fatte queste operazioni preliminari, si chiede a chi passare le cose:
C. Barberis, G. Malnati, 2011-14

c' l'HandlerMapping che si occupa di andare a vedere a chi des-


tinata la richiesta. In base a chi destinata, provvede a costruire un'
istanza del controllore e il dettaglio viene ritornato al DispatcherServ-
let. Occhio che il controllore ha un po' di responsabilit prima che la
richiesta arrivi all'handler: la richiesta passa prima da un po' di con-
trollori.
L'handler provvede ad aggiornare il modello salvando eventuali ope-
Applicazioni Internet
razioni e inoltra la risposta, che torna al dispatcher che separa mo-
41
dello e vista per andare a reperire la vista che poi verr corredata
col modello per generare la risposta definitiva.
DispatcherServlet LEZIONE 18
La difficolt principale che si perde un sacco di tempo a configura-
Quando il dispatcher viene caricato, crea il re bene un progetto. Conviene dunque usare un tool (Eclipse leg-
germente modificato, Spring Tool Suite) che ha un'integrazione ben
contesto dellapplicazione a partire da un file
fatta con Spring e una serie di wizard che configurano decentemen-
xml il cui nome basato sul nome del servlet te il tutto. Lo troviamo su spring.io/tools/sts/all. La prima volta maci-
Nellesempio, shop-servlet.xml na un botto.
C. Barberis, G. Malnati, 2011-14

Deve essere configurato nel file web.xml

web.xml
<servlet>
<servlet-name>shop</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Applicazioni Internet 42

DispatcherServlet
Il tag <url-pattern> indica quali URL sono gestite
dal DispatcherServlet
/ indica che la servlet gestisce tutte le richieste, comprese
quelle per i contenuti statici
<servlet-mapping>
C. Barberis, G. Malnati, 2011-14

<servlet-name>shop</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

Il tag <mvc:resources> pu essere utilizzato per


specificare il gestore delle richieste statiche
shop-servlet.xml
<beans ... >
<mvc:resources mapping="/resources/**"
location="/resources/" />
</beans>
Applicazioni
Applicaz
Applicazioni
icaz ioni Internet
Interne
Internett
erne 43

Controllore

possibile costruire un controllore per ogni


attivit gestita dallapplicazione
Registrazione e autenticazione degli utenti
Visualizzazione della home page
C. Barberis, G. Malnati, 2011-14

Gestione del carrello della spesa


Applicazioni Internet 44
Handler Mapping
Spring fornisce diverse implementazione dellhandler
mapping
BeanNameUrlHandlerMapping
mappa le URL su bean il cui nome inizia con "/"
ControllerBeanNameHandlerMapping
Mappa controllori su URL basate sul nome del bean del controller
C. Barberis, G. Malnati, 2011-14

ControllerClassNameHandlerMapping
Mappa controllori su URL utilizzando i nomi delle classi del bean
DefaultAnnotationHandlerMapping
Mappa le richieste su controllori o metodi annotati con
@RequestMapping
SimpleUrlHandlerMapping
Mappa controllori a URL utilizzando una collezione di tipo property
definita nellapplication context

Applicazioni Internet 45

Vedi aggiunte.
Quando noi creiamo il controllore lo chiamiamo @Controller e
Controllore della home page davanti ai suoi metodi mettiamo @RequestMapping. Se il nostro
package example; controllore avesse bisogno di cose particolari possiamo mettere
@Controller @Inject se vogliamo che il costruttore abbia dei parametri particola-
public class HomeController { ri: "Quando dovrai fare un homeController, vai a cercare tra i tuoi
public static final int ANNOUNCEMENTS_PER_PAGE = 25;
private MyService myService;
bean se ce n' qualcuno la cui classe implementa MyService". E'
tipo l'autowired su un attributo privato.
@Inject
C. Barberis, G. Malnati, 2011-14

public HomeController(MyService myService) {


this.myService = myService; @RequestMapping pu essere messa di fronte davanti al singolo
} metodo oppure davanti all'intera classe. Questo serve a far s che
@RequestMapping({"/","/home"})
tutti i metodi rispondano: i singoli metodi dunque rispondono vero-
public String showHomePage(Map<String, Object> model) { similmente a diverse azioni HTTP (GET, POST, ...)
model.put("announcements",
myService.getAnnouncements(ANNOUNCEMENTS_PER_PAGE));
return "home";
}
}
Applicazioni Internet 46

Controllore della home page

Lannotazione @Controller indica che questa classe


fornisce unimplementazione di un controller
una specializzazione dellannotazione @Component, che
indica che <context: component-scan> registrer come
bean la classe annotata
C. Barberis, G. Malnati, 2011-14

Nel file shop-servlet.xml si deve inserire


<context:component-scan base-package="example" />
Lannotazione @Inject permette di iniettare
automaticamente un oggetto di classe MyService
nel momento in cui viene istanziato il controller

Applicazioni Internet 47

Controllore della home page

Il metodo showHomePage()
annotato con @RequestMapping
Marca il metodo come un gestore di richieste, indicando che
deve gestire le richieste il cui path o / o /home
Prende come parametro una Map<String, Object>
C. Barberis, G. Malnati, 2011-14

che rappresenta il modello


Ottiene dal sevizio MyService i messaggi degli utenti pi
recenti e li inserisce nel modello
Restituisce una stringa contenente il nome logico
della vista che dovr rappresentare il risultato

Applicazioni Internet 48
A seconda del ViewResolver che abbiamo configurato, le regole
Identificare le viste sono diverse. Il caso pi semplice usare l'InternalResourceView
Resolver.
Quando noi ritorniamo home, quell'home diventa
Spring fornisce diverse implementazioni di identificatori
delle viste, come /WEB-INF/views/home.jsp. Nelle pagine jsp posso specificare dei
BeanNameViewResolver tag e utilizzare attributi del modello
Cerca unimplementazione di View il cui identificativo sia il nome logico
della vista
ContentNegotiatingViewResolver
Delega uno o pi altri identificatori, in base al tipo di contenuto richiesto
C. Barberis, G. Malnati, 2011-14

FreeMarkerViewResolver
Cerca un template basato su FreeMarker, il cui path viene determinato
utilizzando un prefisso o postfisso al nome logico
InternalResourceViewResolver
>>> Cerca un template allinterno del file WAR dellapplicazione. Il path viene
derivato dal nome logico
JasperReportsViewResolver
Cerca una vista definita come un file Jasper Reports report file, il cui path
viene derivato dal nome logico

Applicazioni Internet 49

Identificare le viste
ResourceBundleViewResolver
Cerca la vista a partire da un file di propriet
TilesViewResolver
Cerca una vista definita come un template Tiles, il cui nome il nome logico
UrlBasedViewResolver
la classe da cui derivano altri resolver
VelocityLayoutViewResolver
C. Barberis, G. Malnati, 2011-14

Sottoclasse di VelocityViewResolver che permette la composizione di pagine


VelocityViewResolver
Cerca una vista basata su Velocity , il cui path viene derivato dal nome logico
XmlViewResolver
Cerca unimplementazione che sia dichiarata come bean nel file /WEB-
INF/views.xml
XsltViewResolver
Cerca una vista basata su XSLT in cui il path del foglio si stile derivato dal
nome logico

Applicazioni Internet 50

InternalResolverViewResolver

Risolve il nome logico di una vista in un oggetto


di tipo View
Che delega il rendering a un template presente nel
contesto dellapplicazione
C. Barberis, G. Malnati, 2011-14

Il path viene costruito anteponendo al nome logico


un prefisso e post-ponendogli un suffisso

<bean class=
"org.springframework.web.servlet.view.InternalResourceVie
wResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
Applicazioni Internet 51

InternalResolverViewResolver

La vista creata unistanza di


InternalResourceView
possibile specificare la classe tramite la propriet
viewClass
C. Barberis, G. Malnati, 2011-14

<bean class=
"org.springframework.web.servlet.view.InternalResou
rceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.
view.JstlView" />
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>

Applicazioni Internet 52
Se vogliamo fare un sito, tipicamente abbiamo bisogno di interagire
Gestione dellinput con delle form. Ad esempio noi possiamo dare la possibilit all'uten-
te di aggiungere un Item: l'operazione base da gestire quella di
progettare le URL che l'utente utilizzer (www.boh.it/addItem: GET
Spesso il controllore deve eseguire delle specifico il prodotto, POST lo aggiungo).
operazioni a fronte di informazioni ricevute
Come parametri della URL o come dati di un form Se stiamo passando i parametri con URL, il controllore accede ai
parametri con la sintassi di annotazione qui indicata. Segue esem-
Questi possono essere iniettati nel metodo di
pio, dove username etichettato con @RequestParam("user").
C. Barberis, G. Malnati, 2011-14

esecuzione del controller sotto forma di


parametri
Facendone precedere la definizione dallannotazione
@RequestParam(<nomeParametro>)
La forma completa dell'annotazione
value=<nome>, required=<bool>, defaultValue=<default>

Applicazioni Internet 53

UserController
@Controller
@RequestMapping("/user")
public class UserController {
private final MyService myService;

@Inject
public UserController(MyService myService) {
this.myService = myService;
C. Barberis, G. Malnati, 2011-14

}
@RequestMapping(value="/users", method=GET)
public String listUserDetails(
@RequestParam("user") String username, Model model) {
UserDetails details = myService.getDetails(username);
model.addAttribute(details);
return "user/details";
}
}

Applicazioni Internet 54

Con form non cambia molto, devo solo fare attenzione a gestire i
Gestire l'invio di dati tramite form metodi GET e POST.

Le annotazioni sui metodi di un controllore


permettono di gestire semplicemente l'invio di
dati tramite form
Il controllore dispone di un primo metodo, annotato
C. Barberis, G. Malnati, 2011-14

con @RequestMapping(value ="<url>",


method=RequestMethod.GET) che restituisce la vista
con il form
Dispone anche di un secondo metodo, legato all'invio
tramite POST, che si occupa di validare ed elaborare i
parametri ricevuti e restituire la vista finale con il
risultato

Applicazioni Internet 55

Gestire la vista
Per facilitare l'integrazione con le viste, spring
mette a disposizione alcune librerie di tag
<%@ taglib prefix="s"
uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form"
uri="http://www.springframework.org/tags/form" %>
C. Barberis, G. Malnati, 2011-14

Nel caso di form, la libreria assume che al form sia


associato un bean, i cui attributi si riflettono nei
campi di ingresso del form stesso
Per default, il bean viene chiamato "command"
Il controllore responsabile dell'elaborazione del form, lo
ricever come parametro in ingresso se preceduto
dall'annotazione @ModelAttribute

Applicazioni Internet 56
Interessante perch posso passare i @RequestParam uno a fianco
Gestire l'invio tramite form all'altro OPPURE possiamo fare una classe qualunque che dentro
di s ha i vari attributi. In questo secondo caso mettiamo
@ModelAttribute. Affinch la cosa funzioni, necessario che chi
@Controller
public class GreetingController { spedisce i dettagli inserisca i parametri nel "pezzo" giusto.
@RequestMapping(value="/greeting",
method=RequestMethod.GET)
public String greetingForm(Model model) {
model.addAttribute("greeting", new Greeting());
return "greeting";
C. Barberis, G. Malnati, 2011-14

@RequestMapping(value="/greeting",
method=RequestMethod.POST)
public String greetingSubmit(
@ModelAttribute Greeting greeting, Model model) {
model.addAttribute("greeting", greeting);
return "result";
}
}

Applicazioni Internet 57

Il pezzo giusto lo indico con commandName. Quando ricevo i dati


Gestire l'invio tramite form del form devo istanziare un oggetto di tipo greeting e andare a met-
<%@ page language="jsp" %>
tere i dati che ho ricevuto.
<%@ taglib prefix="form" path="name" equivale a dire "invoca setName sull'oggetto greeting".
uri="http://www.springframework.org/tags/form"%> In questo modo ci risparmiamo anche la rogna del parsing.
<html>
<head><title>Simple form</title></head>
<body>
<form:form commandName="greeting" method="post">
<table><tr>
C. Barberis, G. Malnati, 2011-14

<td>Name:</td>
<td><form:input path="name" /></td>
</tr><tr>
<td colspan="2">
<input type="submit" value="Set" />
</td>
</tr>
</form:form>
</body>
</html>

Applicazioni Internet 58

E' possibile fare validazione dei parametri con Hibernate validator.


Validare i parametri Di seguito un esempio, che ci mostra come possiamo aggiungere
dei vincoli sui singoli attributi.
possibile annotare gli attributi degli oggetti pojo
utilizzati nei controllori con vincoli si relativi valori
Utilizzando le annotazione definite nel package
javax.validation.constraints
Occorre includere la dipendenza Maven
C. Barberis, G. Malnati, 2011-14

<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
Si possono esprimere vincoli su valore minimo,
massimo, lunghezza di una stringa, espressioni
regolari, nullit e non nullit dei valori

Applicazioni Internet 59

Validare i parametri (1) Nome dev'essere minimo 2 caratteri e massimo 30, ad esempio.
Quando person verr riempito, l'intercettore che mi crea questo og-
getto verifica che questi vincoli siano buoni. Se non sono buoni vie-
import javax.validation.constraints.*; ne lanciata un'eccezione che mi pu rimandare a una qualche pagi-
public class Person { na.
@Size(min=2, max=30)
private String name;

@NotNull
C. Barberis, G. Malnati, 2011-14

@Min(18)
private Integer age;

public String getName() { return this.name; }


public void setName(String name) { this.name = name; }

public Integer getAge() { return age; }


public void setAge(Integer age) { this.age = age; }

Applicazioni Internet 60
@Valid permette di fare l'enforcement sulla validazione. L'eccezio-
Validare i parametri (2) ne non viene scatenata subito, ma viene scritto in bindingResult se
ci sono problemi o meno e analizzandola posso sapere dove man-
dare l'utente.
@Controller
public class WebController {
@RequestMapping(value="/", method=RequestMethod.GET)
public String showForm(Person person) {
return "form";
}
C. Barberis, G. Malnati, 2011-14

@RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(@Valid Person person,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "form";
}
return "results";
}
}

Applicazioni Internet 61
HomeController.java Pagina:1/1
C:\Users\Riccardo\Desktop\ Ultima modifica: 21/06/2014 01.11.06

package com.duckranger.goodproject;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! the client locale is "+ locale.toString());
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG,
DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
}

Un possibile modo di costruire un controllore. C' un'annotazione che consente a Spring di capire di cosa si sta parlando
e dentro al controllore c' un metodo home preceduto da un @RequestMapping (quando io faccio una domanda a questi
URL con un certo metodo...).
Il parametro riceve un model in cui posso leggere le cose che c'era-no gi nella richiesta e posso scrivere aggiungendo
un attributo.Dato che c' un locale viene aggiunto un header che mi dice ancheche lingua stata scelta dall'utente.

Volendo possiamo aggiungereun HttpServletRequest req in modo da passare al metodo la richiesta cos come stata
modellata dal servlet base, perch magari vogliamo vedere altri header della richiesta.Un po' meno arzigogolato
rispetto a struts in cui torno stringhe enumerative.

PSPad editor 4.5.7 (2450) www.pspad.com 21/06/2014 01.11.09 Riccardo


Model (Spring Framework API 2.5) http://docs.spring.io/spring/docs/2.5.x/api/org/springframework/ui/Mod...

Overview Package Class Use Tree Deprecated Index Help


PREV CLASS NEXT CLASS FRAMES NO FRAMES All Classes
SUMMARY: NESTED | FIELD | CONSTR | METHOD DETAIL: FIELD | CONSTR | METHOD

org.springframework.ui
Interface Model
All Known Implementing Classes:
BindingAwareModelMap, ExtendedModelMap

public interface Model

Java-5-specific interface that defines a holder for model attributes. Primarily designed for adding attributes to the model.
Allows for accessing the overall model as a java.util.Map.

Since:
2.5.1
Author:
Juergen Hoeller

Model addAllAttributes(Collection<?> attributeValues)


Copy all attributes in the supplied Collection into this Map, using attribute name
generation for each element.
Model addAllAttributes(Map<String,?> attributes)
Copy all attributes in the supplied Map into this Map.
Model addAttribute(Object attributeValue)
Add the supplied attribute to this Map using a generated name.
Model addAttribute(String attributeName, Object attributeValue)
Add the supplied attribute under the supplied name.
Map<String,Object> asMap()
Return the current set of model attributes as a Map.
boolean containsAttribute(String attributeName)
Does this model contain an attribute of the given name?
Model mergeAttributes(Map<String,?> attributes)
Copy all attributes in the supplied Map into this Map, with existing objects of the same name
taking precedence (i.e. not getting replaced).

addAttribute
Model addAttribute(String attributeName,
Object attributeValue)

Add the supplied attribute under the supplied name.

Parameters:
attributeName - the name of the model attribute (never null)
attributeValue - the model attribute value (can be null)

addAttribute
Model addAttribute(Object attributeValue)

1 di 2 19/06/2014 23.47
Model (Spring Framework API 2.5) http://docs.spring.io/spring/docs/2.5.x/api/org/springframework/ui/Mod...
Add the supplied attribute to this Map using a generated name.

Note: Empty Collections are not added to the model when using this method because we cannot correctly
determine the true convention name. View code should check for null rather than for empty collections as is already
done by JSTL tags.

Parameters:
attributeValue - the model attribute value (never null)

addAllAttributes
Model addAllAttributes(Collection<?> attributeValues)

Copy all attributes in the supplied Collection into this Map, using attribute name generation for each element.

See Also:
addAttribute(Object)

addAllAttributes
Model addAllAttributes(Map<String,?> attributes)

Copy all attributes in the supplied Map into this Map.

See Also:
addAttribute(String, Object)

mergeAttributes
Model mergeAttributes(Map<String,?> attributes)

Copy all attributes in the supplied Map into this Map, with existing objects of the same name taking precedence (i.e. not
getting replaced).

containsAttribute
boolean containsAttribute(String attributeName)

Does this model contain an attribute of the given name?

Parameters:
attributeName - the name of the model attribute (never null)
Returns:
whether this model contains a corresponding attribute

asMap
Map<String,Object> asMap()

Return the current set of model attributes as a Map.

Overview Package Class Use Tree Deprecated Index Help


PREV CLASS NEXT CLASS FRAMES NO FRAMES All Classes
SUMMARY: NESTED | FIELD | CONSTR | METHOD DETAIL: FIELD | CONSTR | METHOD

Copyright 2002-2008 The Spring Framework.

2 di 2 19/06/2014 23.47
web.xml Pagina:1/1
C:\Users\Riccardo\Desktop\ Ultima modifica: 20/06/2014 11.53.32

<?xml version="1.0" encoding="UTF-8"?>


<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<!-- The definition of the Root Spring Container shared by all Servlets and
Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-
class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Processes application requests -->


<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-
class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

web.xml contiene la configurazione base della descrizione del nostro progetto. Notare che per funzionare bene fa
due operazioni:
- crea un ContextLoaderListener cos da sapere quando il progetto viene deployed e quando undeployed (cos se o
file XML cambiano ricarica le configurazioni)
- contiene un Servlet (il dispatcher) che intercetta tutte le richieste. appServlet mappato sulla cartella radice in modo
da intercettare tutte le richieste e ha un suo parametro di configurazione (contextConfigLocation) che gli dice: quando
parti, vai a cercare nella cartella il file servlet-context.xml. All'interno del file possibile specificare i mapping tra URL e
controllori che andranno costruiti.

L'organizzazione del progetto si basa sul fatto che questo esiste a livello web (= l'utente finale accede al sito mediante
URL). Dall'altro lato, il servizio basato su una certa logica: il dominio del sito ha a che fare con alcuni concetti fonda-
mentali (in un sito di shopping ad esempio ho degli oggetti, dei cataloghi, dei carrelli della spesa, eventuali ordini...). Il
dominio di funzionamento interno e il dominio del web hanno dei parallelismi: certo che la parte web mostrer il carrel-
lo della spesa e le funzionalit, ma queste due cose bene tenerle separate. Questo perch la struttura interna dei dati
risponde alle esigenze di chi gestisce il negozio, mentre la parte web risponde ai bisogni dell'utente. In questo modo
posso fare evolvere la parte web dalla parte interna.

E' dunque bene che nel mio insieme di classi io vada a creare due sottocartelle: uno il package web (tutto quello che
mi serve per farlo girare sul web, e dentro ci vanno a finire i controllers) e uno il package service (in cui mappo "i con-
cetti", ovvero le cose che mi interessano). Ad esempio nel package service posso avere una public interface Item:
questo mi d la possibilit di crearmi delle classi concrete che implementano Item, e sono libero di farle evolvere nel
tempo.

PSPad editor 4.5.7 (2450) www.pspad.com 20/06/2014 11.53.36 Riccardo


servlet-context.xml Pagina:1/1
C:\Users\Riccardo\Desktop\ Ultima modifica: 20/06/2014 11.59.40

<?xml version="1.0" encoding="UTF-8"?>


<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- DispatcherServlet Context: defines this servlet's request-processing


infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->


<annotation-driven />

<!-- Handles HTTP GET requests for /resources/** by efficiently serving up


static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in


the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>

<context:component-scan base-package="it.polito.ai" />


</beans:beans>

Questo un file beans (come tutti i container di Spring) che contiene al suo interno alcuni pezzi base:
- Il bean che implementa InternalViewResolver, che si aspetta roba in .jsp. Viene specificato il prefisso da mettere
alle stringhe ritornate dai controller e anche il suffisso.
- <annotation-driven>: se noi non lo indichiamo, lui si limita a cercare nei file .XML. Quindi le annotazioni presenti
nelle classe vengono ignorate (e non ci piace)
- <context:component-scan>: lui di default non pu andare a cercare annotazioni in tutto il classpath esistente.
Tocca a noi dire il nome dei package in cui mettiamo annotazioni utili per il mapping.
- <resources>: guarda che all'interno del mio progetto ci sono due tipi di URL. Ho le URL dinamiche, che verranno
processate da un controller, ma ogni tanto far riferimento a delle cose statiche: vero che potrei fare un controller,
ma uno spreco. Questa regola ci dice che ogni volta che riceviamo un qualcosa il cui URL resources/... vai nella
cartella e daglielo.

PSPad editor 4.5.7 (2450) www.pspad.com 20/06/2014 11.59.46 Riccardo


root-content.xml Pagina:1/1
C:\Users\Riccardo\Desktop\ Ultima modifica: 21/06/2014 14.42.44

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<!-- Root Context: defines shared resources visible to all other web components -->

<bean name="itemManager" class="it.polito.ai.service.SimpleItemManager" />

</beans>

Qui possiamo definirci dei bean che vogliamo rendere accessibili a tutta la nostra struttura. In questo modo viene
creato a tutti un bean chiamato itemManager con questa classe. Pi avanti un esempio di HomeController modificato.

PSPad editor 4.5.7 (2450) www.pspad.com 21/06/2014 14.42.53 Riccardo


Item.java Pagina:1/1
C:\Users\Riccardo\Desktop\ Ultima modifica: 21/06/2014 02.14.14

package it.polito.ai.service;

/* Descrive un Item */
public interface Item {
String getName();
double getPrice();
String getDescription();
}
/*****************************************************************************/
package it.polito.ai.service;

public class SimpleItem implements Item {


private String name;
private String description;
private double price;

public SimpleItem (String name, String description, double price) {


this.name = name;
this.description = description;
this.price = price;
}

public String getName() {


return name;
}
public double getPrice() {
return price;
}
public String getDescription() {
return description;
}

public void setPrice(double price) {


this.price = price;
}
}

PSPad editor 4.5.7 (2450) www.pspad.com 21/06/2014 02.14.17 Riccardo


SimpleItemManager.java Pagina:1/1
C:\Users\Riccardo\Desktop\ Ultima modifica: 21/06/2014 02.36.04

package it.polito.ai.service;

import java.util.List;

/* Descrive un componente che gestisce degli Item */


public interface ItemManager {
public List<Item> getItems();
public void addItem(Item i);
public void removeItem(Item i);
}

/******************************************************************************/
package it.polito.ai.service;
import java.util.List;
import java.util.ArrayList;

public class SimpleItemManager implements ItemManager {


private List<Item> items = new ArrayList<Item>();

public SimpleItemManager() {
for (int i = 1; i < 5; i++) {
Item i = new SimpleItem("Item " + i, "Description " + i, i*10);
items.add(item);
}
}

public List<Item> getItems() {


return new ArrayList<Item>(items);
/* Oppure, con un wrapper readonly: return Collections.unmodifiableList(items); */
}

public void addItem(Item i) {


items.add(i);
}

public void removeItem(Item i) {


items.remove(i);
}
}

/* Affinch tutto funzioni, Item deve avere equals() e lo posso generare in modo
automatico */

PSPad editor 4.5.7 (2450) www.pspad.com 21/06/2014 02.36.07 Riccardo


HomeController.java Pagina:1/1
C:\Users\Riccardo\Desktop\ Ultima modifica: 21/06/2014 14.49.56

package it.polito.ai.web;

import it.polito.ai.service.ItemManager;
/* ... */

/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);


@Autowired
/* Vai a cercare tra tutti i bean se ne trovi uno di tipo ItemManager e ficcalo
dentro */
private ItemManager itemManager;

@RequestMapping(value = "/", method = RequestMethod.GET)


public String home(Locale locale, Model model) {
logger.info("Welcome home! the client locale is "+ locale.toString());
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG,
DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate);
model.addAttribute("items", itemManager.getItems());
return "home";
}
}

/* A questo punto nella vista home posso aggiungere una table che elenca gli item.
Gli item li peschiamo, ad esempio, con <c:forEach var="item"
items="${items}"></c:forEach>.
Questo vuol dire: prendi nel modello una variabile items che dev'essere iterable e
per ciascuno di questi elementi scorri l'iteratore assegnando l'elemento che hai
preso a una nuova variabile item. Il nome lo prendo con ${item.name}: si guarda
nell'oggetto item se c' un metodo getName e se s lo invoca. E cos via per gli
altri. */

PSPad editor 4.5.7 (2450) www.pspad.com 21/06/2014 14.57.39 Riccardo