Sei sulla pagina 1di 14

Sessione 15

Servlet

1
Servlet
Le servlet sono le classi Java fondamentali per gestire l’elaborazione di richieste/risposte Http in ambito web. Tutti i tool Java
specifici per il web, che si sono diffusi negli ultimi anni, come ad esempio Struts (che vedremo più avanti nel corso), sono
“estensioni” delle servlet. Vale a dire che le classi principali di questi tool non sono altro che classi che ereditano dalle servlet per
specializzare (e sperabilmente migliorare) il comportamento di base delle stesse servlet.

In Java una servlet è una classe che estende HttpServlet del package javax.http.servlet.

Tra i metodi esposti dalla classe HttpServlet (cfr. JavaDoc relativa) i due più importanti sono doGet e doPost per gestire
richieste, rispettivamente, di tipo GET e POST.

Una tecnica molto diffusa è quella di far richiamare dal metodo doGet il codice del metodo doPost in modo che qualsiasi tipo di
richiesta riceviamo dal client (GET o POST) venga eseguito sempre lo stesso codice lato server:

@Override
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,
IOException
{
doPost(request,response);
}

2
Entrambi i metodi, doGet e doPost, ricevono due parametri di ingresso: uno di classe HttpServletRequest e l’altro di classe
HttpServletResponse.

HttpServletRequest rappresenta una richiesta Http. Tra i metodi che espone notiamo:

• getParameter(String s): permette di recuperare il valore di un parametro inviato al server. s rappresenta il nome del
parametro. Ad esempio, nella sessione dedicata al linguaggio Html abbiamo visto che una form può inviare dati al web
server attraverso un campo <input type=”text” name=”nomeCampo”>. In questo caso, l’utente scrive del testo nel campo
“nomeCampo” e invia i dati effettuando il submit della form. Lato server, nel codice della servlet scrivendo
request.getParameter(“nomeCampo”) potremmo leggere il testo inserito dall’utente nel campo nomeCampo della form
Html

• request.getSession(): permette di recuperare l’oggetto Session che rappresenta la sessione web dell’utente

• request.getServerName(): resituisce il nome del server su cui è stata avviata la web application

• request.getServerPort(): restituisce la porta su cui è in ascolto il server su cui è stata avviata la web application

• request.getServletPath(): resituisce il servlet path, ovvero il nome associato alla servlet (cfr. più avanti web.xml)

HttpServletResponse rappresenta invece la risposta Http.

3
Da notare che i parametri associati ad un oggetto di classe HttpServletRequest ed ad un oggetto di classe HttpSession
seguono i cicli di vita delle richieste e delle sessioni Http. Pertanto un parametro di richiesta nasce con la richiesta Http
inviata dal client e termina con la risposta Http inviata dal server. Viceversa un parametro di sessione “vive” per tutta la
durata della sessione del client (quindi sarà presente in differenti singole richieste/risposte Http).

Due dei metodi più importanti di HttpServletResponse sono getWriter() e getOutputStream() che consentono di recuperare il
flusso dati associato alla risposta Http. Per esempio la servlet potrebbe scrivere nel flusso dati associato alla risposta Http il
codice Html della pagina di risposta Http.

Vediamo un classico giro di richiesta risposta Http. Immaginiamo di avere una pagina html, servlet.html fatta nel seguente modo:

<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Primo esempio servlet</title>
</head>
<body>
<div style="text-align: center">
<br>
<form action="/Corso/test" method="post">
Nome:&nbsp;<input type="text" name="nome">
<br>
<br>
<br>
<input type="submit" value="invia i dati al server">
</form>

4
</div>
</body>
</html>

Tralasciamo per un momento il modo in cui chiamiamo la servlet tramite il parametro action della form, in quanto questo lo
vedremo tra poco quando parleremo del file web.xml della web application. Concentriamoci, invece, sul fatto che la pagina Html
prevede, lato client, l’inserimento di testo da parte dell’utente nel campo <input type=”text” name=”nome”> e che questo testo
verrà inviato alla servlet quando l’utente clicca sul bottone <input type=submit>.

Lato server, il codice della nostra servlet recupererà il testo scritto dall’utente in questo modo:

String nome = request.getParameter("nome");

Inoltre, la servlet potrà scrivere la pagina Html di risposta tramite le seguenti istruzioni:

PrintWriter printWriter = response.getWriter();


printWriter.println("<h1>Nome: " + nome + "</h1><br>");

Una servlet per essere utilizzata deve essere configurata nel web.xml, il file principale che descrive la web application.

Tra le varie informazioni che è possibile definire all’interno del file web.xml, e che analizzeremo man mano che le utilizzeremo,
notiamo:

5
• la sezione <welcome-file-list>: presenta una serie di file di “benvenuto” all’interno di altrettanti sotto-tag <welcome-file>.
Quando vogliamo aprire da browser un file Html della web application dobbiamo indicare il percorso completo (path) del
file html rispetto alla radice della web application. Ad esempio, se abbiamo creato un file index.html all’interno della
directory html sotto la directory radice della nostra web application, per richiedere al web server il file index.html dovremo
inserire nella barra degli indirizzi del browser l’url http://localhost:8080/Corso/html/index.html (supponendo di avere
installato Tomcat sulla nostra macchina, localhost, sulla porta 8080 e che la nostra web application si chiami “Corso”). I
file di benvenuto, invece, sono file Html che vengono aperti senza bisogno di specificare il path completo; è necessario
specificare solo il nome della web application. Ad esempio, tipicamente, si crea un file di benvenuto (la “home” del sito) di
nome index.html direttamente sotto la radice della web application. A questo punto, inserendo il file index.html nella
sezione <welcome-file-list> del file web.xml, tramite l’url http://localhost:8080/Corso si aprirà direttamente la pagina
index.html

• la sezione <servlet>: consente, tramite i sotto-tag <servlet-name> e <servlet-class>, di definire il mapping tra nome
logico di una servlet e nome fully-qualified della classe Java

• la sezione <servlet-mapping>: consente, tramite i sotto-tag <servlet-name> e <url-pattern>, di definire il mapping tra il
nome logico di una servlet ed il path da inserire nell’url (dopo il nome della web application) per richiamare la servlet

6
Nell’esempio precedente la sezione del file web.xml relativa alla nostra servlet sarà:

<servlet>
<servlet-name>Test</servlet-name>
<servlet-class>com.azienda.esempiCorso.sessione15.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Test</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>

A questo punto per richiamare la nostra servlet si dovrà invocare l’url http://localhost:8080/Corso/test.

Tuttavia, nel parametro action della form non è necessario indicare la prima parte dell’url http://localhost:8080, ecco perché il
parametro è valorizzato come action=”/Corso/test”.

Vediamo adesso un altro esempio in cui illustriamo un classico esempio di form di login, andando a sfruttare il codice che
abbiamo visto nella sezione Hibernate per le operazioni di ricerca sulla classe Utente.

Gli elementi che ci occorrono sono:

7
• creare una pagina Html con una form con un <input type=”text”> in cui inserire il nome utente, un <input
type=”password”> in cui inserire la password dell’utente, oltre al classico <input type=”submit”> per inviare i dati

• creare una servlet che recuperi nome utente e password inviati dalla form ed interroghi il database per verificare se esiste
l’utente che sta provando a loggarsi. Per fare il controllo su database utilizzeremo il metodo retrieve(Utente utente, boolean
openTransaction) della classe HibernateDao

• modificare il file web.xml per aggiungere la sezione relativa al mapping della servlet creata al punto precedente

I campi della form per inserire nome utente e password nella pagina Html saranno:

<input type="text" name="userName">


<input type="password" name="password">

Nella servlet recuperemo i dati inviati dal client tramite le istruzioni:

String userName = request.getParameter("userName");


String password = request.getParameter("password");

Poi ricercheremo l’utente su database tramite le istruzioni:

Utente utente = new Utente();


utente.setUserName(userName);
utente.setPassword(password);

8
DaoInterface dao = new DaoHibernate();
Utente utenteFromDb = dao.retrieveById(utente.getId(),true);

E infine rimanderemo ad una pagina di benvenuto o di errore a seconda della risposta che riceviamo dal database attraverso le
istruzioni:

request.getRequestDispatcher("/html/loginOk.html").forward(request,response);
request.getRequestDispatcher("/html/loginError.html").forward(request,response);

Il metodo getRequestDispatcher(String s) della classe HttpServletRequest permette di recuperare una risorsa della web
application, come ad esempio un file Html e restituisce un oggetto di classe RequestDispatcher che rappresenta la risorsa.

Il metodo forward della classe RequestDispatcher (che nel codice abbiamo richiamato “inline”, ovvero in un’unica istruzione
abbiamo recuperato l’oggetto di classe RequestDispatcher ed abbiamo invocato sull’oggetto il metodo forward), consente di
“forwardare” la richiesta alla risorsa, ovvero consente di richiamare la risorsa come se fosse stata effettuata una nuova richiesta
Http verso la risorsa. In pratica simula la richiesta Http verso la pagina Html che viene passata come parametro al metodo
forward.

In definitiva, apriremo la pagina Html loginOk.html oppure loginError.html in funzione dell’esito della ricerca su database.

Nel file web.xml la sezione relativa alla nuova servlet sarà:

9
<servlet>
<servlet-name>Login</servlet-name>
<servlet-class>com.azienda.esempiCorso.sessione15.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>

E quindi nel parametro action della form scriveremo “/Corso/login”.

Filtri

Nelle Java web application, è possibile scrivere del codice che resti “in ascolto” su alcune (o tutte) le pagine della web
application. Questi componenti “in ascolto” sono detti filtri.

I filtri sono classi che implementano l’interfaccia Filter del package javax.servlet.

Nel file web.xml della web application si configurano i filtri, in maniera molto simile alle servlet, specificando il mapping tra
nome logico e nome fully qualified della classe che implementano Filter e specificando il mapping tra nome logico del filtro e
insieme degli indirizzi che devono essere monitorati dal filtro.

10
Un esempio tipico nelle web application è la creazione di un filtro che controlli alcune url “riservate” della web application per
verificare che l’utente sia loggato in sessione; se l’utente è effettivamente loggato, il filtro lascia proseguire la navigazione verso
le url “riservate”, viceversa il filtro rimanda alla pagina di login.

Per implementare un filtro del tipo appena descritto nel nostro progetto “Corso”, potremmo creare una classe LoginFilter in
questo modo:

public class LoginFilter implements Filter

L’interfaccia Filter richiede l’implementazione dei metodi init, destroy e doFilter.

I primi due sono metodi legati al ciclo di vita del filtro, che al momento non ci interessano. Il metodo che svolge il lavoro che a
noi interessa in questa sede doFilter. Quest’ultimo metodo riceve in ingresso tre parametri: un oggetto di classe ServletRequest,
un oggetto di classe ServletResponse ed un altro oggetto FilterChain.

In una Java web application è possibile definire anche più filtri in ascolto sulle stesse pagine web, ovvero è possibile creare una
“catena di filtri”, che è rappresentata dalla classe FilterChain. Data una determinata pagina web su cui abbiamo messo “in
ascolto” n filtri, in configurazione dovremo definire l’ordine di invocazione di ciascun filtro. Ogni filtro della catena, nel proprio
metodo doFilter eseguirà i controlli di sua competenza e “passerà la palla” al prossimo filtro attraverso l’invocazione del metodo
doFilter dell’oggetto di classe FilterChain.

11
Ecco una possibile implementazione del metodo doFilter per la nostra classe LoginFilter:

public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,


ServletException
{
HttpServletRequest httpRequest = (HttpServletRequest) request;
String userLogged = (String) httpRequest.getSession().getAttribute("userLogged");
if ( ! (userLogged != null && userLogged.toUpperCase().equals("YES")) )
{
request.getRequestDispatcher("/login.html").forward(request,response);;
}
chain.doFilter(request,response);
}

Il metodo, tramite il metodo getAttribute dell’oggetto di classe Session associato alla richiesta Http (request) controlla che sia
presente nella sessione web dell’utente l’attributo userLogged, se così non è rimanda la navigazione alla pagina di login tramite
invocazione del metodo forward sull’oggetto di classe RequestDispatcher. In conclusione, “passa la palla” all’eventuale
successivo filtro della catena se c’è, altrimenti al componente web che è stato richiesto dal client, attraverso il metodo
chain.doFilter.

A questo punto modificheremo anche il codice della servlet LoginServlet in modo da mettere nella sessione web l’informazione
relativa all’utente loggato (parametro userLogged) in caso di utente riconosciuto sul database:

12
Utente utenteFromDb = dao.retrieveById(utente.getId(),true);
if ( utenteFromDb != null )
{
request.getSession().setAttribute("userLogged","YES");
request.getRequestDispatcher("/html/loginOk.html").forward(request,response);
}

Per concludere, vediamo la configurazione del filtro nel file web.xml:

<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.azienda.esempiCorso.sessione15.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/html/*</url-pattern>
</filter-mapping>

Nel sotto-tag <url-pattern> abbiamo definito che il nostro filtro deve monitorare tutti gli indirizzi che iniziano con /html ovvero
tutte le richieste Http del tipo http://localhost:8080/Corso/html.....

A questo punto ci conviene spostare il file login.html fuori dalla directory html in modo che non scatti nuovamente il filtro
quando l’utente viene rimandato alla pagina di login.

Possiamo riepilogare il giro delle richieste/risposte Http alla nostra web application “Corso”, dopo l’introduzione del filtro
LoginFilter, nel seguente modo:

13
• l’utente richiede una pagina “riservata” come ad esempio: http://localhost:8080/Corso/html/servlet.html

• Tomcat, accorgendosi dal web.xml che la richiesta Http è “controllata” da un filtro, invoca il codice del nostro filtro
LoginFilter

• il nostro filtro controlla che l’utente sia già loggato alla nostra web application, verificando la presenza in sessione
dell’attributo userLogged. Essendo la prima richiesta, l’utente non è ancora loggato e di conseguenza l’utente viene
rimandato alla pagina login.html

• le credenziali inserite dall’utente nella pagina login.html vengono controllate su database dalla nostra servlet LoginServlet.
Se l’utente esiste sul database la servlet mette in sessione l’attributo userLogged

• da questo momento in poi le successive richieste Http da parte del cliente, nella stessa sessione web, anche alle pagine
“riservate” della nostra web application sono consentite per l’utente

14