Sinistra <- Monitoraggio di sistemi in rete - parte 4 - Indice Generale - Copertina - Preseeding Debian Parte I -> Destra

Sistemi Liberi


Server Side Java - parte 1

Server Side Java - parte 1

di Stefano Sasso

L'articolo...

In questo articolo, primo di una serie, vedremo i fondamenti della programmazione web lato server in Java. Capiremo cosa sono JSP e Servlet, e proveremo ad usare in maniera pratica quanto visto teoricamente. Questo articolo serve per dare uno spunto al lettore, che poi potrà realizzare applicazioni web in Java utilizzando le nozioni apprese.



Introduzione

Nello scenario dello sviluppo software professionale (ma non solo) Java rende possibili soluzioni pensate per applicazioni multitier (multi-livello) che utilizzano tutte le capacità e le caratteristiche di internet e delle reti in genere; in questa serie di articoli ci focalizzeremo sulle tecnologie nate dal desiderio di applicare Java allo sviluppo di applicazioni web.

Nel campo delle applicazioni web, o delle applicazioni distribuite in genere, le due figure principali sono il Client ed il Server. I due sono dei processi, o applicazioni, in esecuzione su macchine differenti che comunicano scambiandosi informazioni in diversi modi. Abitualmente il Client effettua una richiesta ed il Server cerca di esaudirla. Per soddisfare le richieste dei Client il server può appoggiarsi a basi di dati, che contengono le informazioni da elaborare, e che rappresentano il terzo importante elemento di questo tipo di architettura. Di norma esistono quindi dei Client che formulano delle richieste al Server, che a sua volta richiede i dati al database che li contiene, in modo del tutto trasparente al client li elabora in base alla richiesta avuta ed invia il risultato del suo lavoro.

Sun ha messo a disposizione di Java diverse tecnologie che rendono l'utilizzo di questo linguaggio la scelta più adatta per applicazioni distribuite o enterprise. Nel campo della programmazione web lato server, che è quello che ci interessa, i nomi che si devono imparare sono Servlet e JSP. Queste tecnologie costituiscono un importantissimo metodo di sviluppo di applicazioni web-based, e analizzandole meglio scopriremo che il loro utilizzo è molto simile (per non dire uguale) al modo in cui siamo abituati a lavorare normalmente con Java.

Le Servlet altro non sono che delle classi che lavorano sul server, e che per poter operare hanno bisogno di un contesto, un motore che si occupi del loro utilizzo. In questa serie prenderemo in considerazione il servlet container Apache Tomcat, che integra al suo interno anche il supporto per le JSP, le Java Server Pages. (Vedremo in seguito la differenza tra Servlet e JSP)

Si presume che il lettore abbia una minima conoscenza del linguaggio Java e dei suoi formalismi sintattici, in quanto non verranno trattate le nozioni di base.

Apache Tomcat

Apache Tomcat [1] è un servlet container Open Source rilasciato dall'Apache Software Foundation. Al momento è arrivato alla versione 5, ed è proprio questa che utilizzeremo nelle nostre applicazioni.

Requisiti per l'installazione

Per installare ed utilizzare Tomcat è necessario un JRE (Java Runtime Environment) oppure un JDK (Java Developer Kit), noi utilizzaremo il SUN JDK, liberamente scaricabile dal sito della Sun. [2]

Ipotizzando che il JDK sia installato in /opt/java dovremo inserire la seguente riga nel file /etc/profile

export JAVA_HOME=/opt/java
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=$JAVA_HOME/lib

dopodichè ricaricheremo in memoria il contentuto del file con

. /etc/profile

Installazione

Cominciamo scaricando il tarball di Tomcat precompilato dal sito http://Tomcat.apache.org/, dopodichè l'unica operazione da compiere è quella di decomprimerlo in una directory a piacere.

Avvio di Tomcat

Posizioniamoci nella directory "bin" all'interno della cartella di Tomcat, e lanciamo il comando

./startup.sh

per avviare il server. Possiamo ora puntare il nostro browser a http://localhost:8080/ ; Se ci appare la pagina di default di Tomcat significa che il server è perfettamente funzionante.

Struttura delle directory di Tomcat

Ecco il significato della struttura standard delle directory di Tomcat:

bin/: contiene gli script per avviare ed arrestare Tomcat

common/: librerie e classi disponibili per tutte le applicazioni web installate (si veda webapps/) e rese disponibili anche all'applicazione Tomcat

conf/: vi risiedono i file di configurazione, principalmente i descrittori in formato xml e i file properties

logs/: qui vengono salvati i file di log

server/: classi e librerie necessarie per il funzionamento di Tomcat, e visibili solo da esso

shared/: similmente alla directory common/ ogni classe e libreria qui contenuta viene resa disponibile a tutte le applicazioni web installate; però, a differenza di common/, tali librerie e classi non sono rese disponibili anche all'applicazione Tomcat

temp/: directory di lavoro temporanea

webapps/: in essa risiedono le applicazioni web; basterà copiare qui un archivio .war (web application resource) perchè esso venga automaticamente deployato da apache; viceversa, basterà rimuoverlo perchè esso venga un-deployato.

work/: è la directory dove Tomcat mette i file compilati a partire dalle JSP

Struttura delle directory di un'applicazione web

Normalmente le applicazioni web sono distribuite come archivi .war, generati con l'utility jar, con una determinata struttura di directory al suo interno.

La directory di più alto livello viene chiamata "document root"; tipicamente al suo interno risiedono i file statici, ma è possibile posizionarci anche delle JSP. (ovviamente nulla vieta che i files possano anche risiedere in sottocartelle della docroot)

All'interno della docroot deve essere presente la cartella WEB-INF, dentro la quale risiedono le risorse della web application. In particolare è obbligatoria la presenza del file web.xml (trattato meglio in seguito), il descrittore dell'applicazione (descrive le servlet e gli altri componenti che compongono l'applicazione, come ad esempio parametri di inizializzazione, vincoli per la sicurezza e così via.)

All'interno di WEB-INF possono essere presenti le seguenti cartelle (ma non sono obbligatorie)

classes/: directory che contiene le classi (compilate) necessarie alla web application; tali classi sono file con estensione .class, e non archivi .jar; la struttura delle sottodirectory deve essere compatibile con la suddivisione in package Java

lib/: vi si possono trovare sempre classi ed eventuali risorse, ma a differenza di classes/ qui ci sono solo archivi .jar.

jsp/: è buona norma tenere all'interno di questa cartella le pagine JSP che verranno poi richiamate dalle servlet, e che non devono essere direttamente richiamabili dall'utente finale.

tag/: all'interno di questa directory potremo trovare dei custom tag. vedremo la loro utilità in seguito.

Il descrittore dell'applicazione web: web.xml

Come abbiamo visto prima, ogni applicazione deve essere dotate del file descrittore, il file web.xml all'interno della directory WEB-INF.

Qui è mostrato un file web.xml tipo, con le descrizioni dei tag come commenti xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

	<!-- nome e breve descrizione della nostra applicazione -->
	<display-name>applicazione 1</display-name>
	<description>descrizione breve dell'applicazione 1</description>

	<!-- i file indice, simile al DirectoryIndex di apache -->
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>

	<!-- dichiariamo ora la presenza di una servlet, e gli assegnamo un nome, in questo caso servletIndice -->
	<servlet>
		<servlet-name>servletIndice</servlet-name>
		<servlet-class>it.pluto.journal.java.SimpleIndexServlet</servlet-class>
	</servlet>

	<!-- ora diciamo a Tomcat di ridirigere tutte le richieste per index.html verso la servlet con nome servletIndice -->
	<servlet-mapping>
		<servlet-name>servletIndice</servlet-name>
		<url-pattern>/index.html</url-pattern>
	</servlet-mapping>

</web-app>

Man mano che creeremo nuovi oggetti che dovranno essere dichiarati nel descrittore vedremo come (e dove) dichiararli.

Servlet e jsp, queste sconosciute

Abbiamo parlato prima di Servlet e JSP, ma cosa sono effettivamente?

Una servlet è un componente web sviluppato in Java che genera contenuto dinamico, il cui scopo è quello di estendere le funzionalità di un servlet containter, mentre le JSP, Java Server Pages, sono la tecnologia, complementare a quella delle servlet (come avremo modo di vedere meglio in seguito), per la creazione di pagine web dinamiche. Questi standard sono molto diffusi in quanto dispongono di caratteristiche migliorative che li differenziano dalle altre tecnologie disponibili, come CGI, PHP e ASP, e che possiamo riassumere in diversi punti:

Ma che differenza c'è tra una Servlet e una JSP?

Sono sostanzialmente la stessa cosa. Una pagina JSP, che consente di inserire al suo interno componenti dinamiche (che vengono eseguite ad ogni accesso alla pagina e possono essere utilizzate per generare output personalizzato), è, in effetti, una servlet, nel senso che essa, per poter essere eseguita, viene trasformata in una servlet equivalente. In particolare i componenti dinamici vengono trasformati in opportuni frammenti di codice java, mentre il contenuto statico viene convertito in istruzioni di output. Ma allora che bisogno abbiamo di avere sia le servlet che le jsp? Dal punto di vista delle funzionalità nessuno, ma la giustificazione sta nelle diverse professionalità a cui si rivolgono.

Nello sviluppo di applicazioni web-based di una certa complessità sono/possono essere coinvolte figure con specializzazioni molto diverse: da un lato i programmatori, preposti allo sviluppo della logica dell'applicazione, dall'altro i grafici/web designer, che si occuperanno dell'interfaccia utente dell'applicazione (livello di presentazione).

Tipicamente i primi hanno competenze che vanno dalla conoscenza del linguaggio di programmazione alla progettazione della base di dati, i secondi si focalizzano sulle tecnologie di web-publishing (html, xhtml, css, etc...).

Con servlet e JSP ci si rivolge a entrambe le categorie: mentre i programmatori si troveranno a loro agio nello sviluppo di servlet, i web designer potranno concentrarsi sullo sviluppo delle pagine JSP, senza che venga a loro chiesta alcuna conoscenza del linguaggio Java. Nella pratica quindi, gli unici elementi estranei al loro dominio con cui dovranno confrontarsi saranno i tag JSP forniti dai programmatori (custom tag).

Anche se le due figure coincidono la separazione dei livelli di logica e presentazione è utile; ad esempio si possono facilmente effettuare delle modifiche sull'interfaccia grafica senza correre il rischio di modificare la logica applicativa.

L'architettura di un'applicazione

L'architettura di un'applicazione è sostanzialmente la struttura, definita dal progettista, che dovrà avere l'applicazione stessa: è quindi un elemento che vincola e definisce la forma e la sostanza del futuro lavoro di sviluppo. Il modo più efficiente per progettare un'architettura applicativa consiste nella scomposizione in componenti separati che possano essere sviluppati, modificati o aggiornati indipendentemente dall'intera applicazione; questo consente alle applicazioni di essere sviluppate in ambienti di collaborazione in team e porta, inoltre, alla scrittura di un codice più facile da gestire rispetto alle applicazioni basate su un progetto centralizzato. A proposito di quest'ultima affermazione, infatti, occorre precisare che, integrare del codice Java in una pagina JSP, per quanto potente ed utile possa essere, è intrinsecamente pericoloso: più se ne inserisce più sarà difficile avere accesso alla pagina, e, inoltre, il codice Java amalgamato con il linguaggio HTML diventerà più difficile da leggere. Un sistema che evita questo inconveniente poichè consente di mantenere il codice Java distinto dalla pagina JSP è rappresentato dall'uso di servlet per l'elaborazione dei dati, e l'uso delle jsp (richiamate dalle servlet stesse) per la presentazione dei dati elaborati.

La maggior parte delle applicazioni web organizza i vari componenti in più livelli logici:

l'unione di questi livelli è meglio conosciuta con il nome di "paradigma MVC (model, view, controller)", molto famoso per la sua flessibilità e potenza.

La nostra prima applicazione web

Proviamo a creare ora una semplicissima applicazione:

Struttura directory

nella nostra cartella di lavoro creiamo la cartella "Applicazione1", con al suo interno la struttura standard per un'applicazione web:

mkdir Applicazione1
cd Applicazione1
mkdir -p WEB-INF/classes

(per il momento sono sufficienti queste cartelle)

web.xml di base

all'interno della cartella WEB-INF creiamo il file web.xml di base:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

	<!-- nome e breve descrizione della nostra applicazione -->
	<display-name>applicazione 1</display-name>
	<description>la mia prima applicazione web in java</description>

	<!-- i file indice, simile al DirectoryIndex di apache -->
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>

</web-app>

La prima servlet!

Principalmente una servlet non è altro che una classe Java che estende javax.servlet.http.HttpServlet, di cui, per riuscire a gestire le richieste, deve sovrascrivere i metodi doGet e doPost. Come si deduce dal nome, il primo esaudisce le richieste di tipo GET, mentre il secondo quelle di tipo POST. Per praticità creeremo il metodo doRequest, che verrà invocato sia da doGet che da doPost.

All'interno della cartella WEB-INF/classes creiamo quindi la classe java PrimaServlet, il cui codice è:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class PrimaServlet extends HttpServlet
{
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
	{
		// richiamiamo doRequest
		doRequest(request, response);
	}
	
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
	{
		// richiamiamo doRequest
		doRequest(request, response);	
	}
	
	public void doRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
	{
		/* inviamo un output al client.
		   cosa potrebbe esserci di meglio di un classico
		   ciao mondo? */
		//settiamo il content-type della risposta
		response.setContentType("text/html");
		//recuperiamo un oggetto PrintWriter per mandare output al client
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head>");
		out.println("<title>Ciao!</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>Ciao mondo!</h1>");
		out.println("</body>");
		out.println("</html>");
		out.close();
	}
}

NOTA: notiamo subito i due oggetti passati come argomenti delle funzioni: l'oggetto HttpServletRequest rappresenta la richiesta ricevuta dal client (ma anche l'ambito di vita delle variabili che devono esistere durante tutto l'arco della richiesta), mentre HttpServletResponse viene utilizzato per costruire la risposta da inviare al client stesso.

Esiste anche l'oggetto ServletContext, richiamabile con getServletContext(), che rappresenta qualsiasi cosa abbia a che fare con il contesto di esecuzione della servlet.

possiamo ora compilare la nostra prima servlet:

(ipotizzando di aver installato Tomcat in /opt/tomcat)

javac -classpath /opt/tomcat/common/lib/servlet-api.jar PrimaServlet.java

se l'operazione è andata a buon fine troveremo il file PrimaServlet.class nella directory WEB-INF/classes.

Dichiarazione della servlet in web.xml

Dichiariamo ora la nostra prima servlet nel file web.xml:

aggiungiamo il seguente spezzone xml all'interno del tag <web-app>:

	<!-- dichiariamo ora la presenza della nostra servlet, e gli diamo il nome univoco "prima" -->
	<servlet>
		<servlet-name>prima</servlet-name>
		<servlet-class>PrimaServlet</servlet-class>
	</servlet>

	<!-- ora diciamo a Tomcat di ridirigere tutte le richieste per index.html verso la nostra servlet. 
	possono esistere più servlet mapping per ogni servlet. -->
	<servlet-mapping>
		<servlet-name>prima</servlet-name>
		<url-pattern>/index.html</url-pattern>
	</servlet-mapping>

Creazione dell'archivio war

procediamo ora con la creazione l'archivio war, che successivamente deployeremo in Tomcat:

portiamoci nella webroot (directory Applicazione1) e lanciamo il comando

jar cvf Applicazione1.war *

Deploy

NOTA: Tomcat deve essere in esecuzione

Per deployare la nostra applicazione è sufficiente copiare il file war appena creato nella directory webapps/ di Tomcat. Dopo qualche secondo, sempre all'interno di webapps/ vedremo che Tomcat avrà creato automaticamente una directory con il nome dell'applicazione: questo significa che il deploy è stato eseguito.

Apriamo ora il nostro browser e puntiamolo a http://localhost:8080/Applicazione1 : come per magia vedremo comparire l'output della nostra servlet!

Se dovesse esserci qualche problema è buona cosa consultare i file di log di Tomcat, che si trovano nella directory logs/

Undeploy

NOTA: Tomcat deve essere in esecuzione

Per undeployare la nostra applicazione basta rimuovere il file war dalla directory webapps/ di Tomcat. Dopo poco vedremo scomparire la directory relativa all'applicazione; a questo punto l'undeploy è stato eseguito.

La prima jsp

NOTA: per scopi didattici, ora e in seguito (finchè non avremo appreso l'uso dei custom tag jsp) inseriremo del codice java direttamente all'interno delle JSP. Una volta che avremo imparato ad usare al meglio i custom tag potremo tranquillamente dimenticare questa pratica. Ricordo comunque che tutto quello che viene visto come JSP può essere "tradotto" in Servlet dal lettore.

Torniamo nella document root della nostra prima applicazione ("Applicazione1"), e creiamo un file chiamato prima.jsp, con al suo interno:

<html>
	<head>
		<title>ciao jsp</title>
	</head>
	<body>
		<h1>Ciao!</h1>
		<h2>io sono una JSP</h2>
		<%
		// qui dentro ci posso mettere codice java
		out.println("prova 123");
		String prova2 = "prova 456";
		%>
		<br/>
		<%=prova2%>
	</body>
</html>

Da notare l'uso diretto dell'oggetto PrintWriter chiamato out: in una jsp infatti sono disponibili, oltre ad "out" anche le variabili "request" e "response" (instanze relativamente di HttpServletRequest e HttpServletResponse), proprio come in una Servlet.

Possiamo ora, come visto prima, pacchettizzare la nostra applicazione, e deployarla in Tomcat (dopo aver undeployato l'archivio precedente!).

puntiamo ora il browser a http://localhost:8080/Applicazione1/prima.jsp ... et voilà, la pagina è servita.

NOTA: è possibile includere il contentuto di una JSP in un'altra JSP, utilizzando la direttiva "include". Può essere utile per includere parti comuni di codice html.

<%@ include file="common/header.jsp" %>
<div id="contentuto">...</div>
<%@ include file="common/footer.jsp" %>

Cattura di errori o eccezioni da parte del container

E' possibile fare in modo che Tomcat catturi errori http (404, 403, ...) o eccezioni lanciate da Servlet, mandando in output una pagina JSP.

Per fare questo è sufficiente inserire in web.xml, all'interno del tag "web-app"

<error-page>
	<error-code>404</error-code>
	<location>/WEB-INF/jsp/errori/404.jsp</location>
</error-page>
oppure
<error-page>
	<exception-type>java.lang.NumberFormatException</exception-type>
	<location>/WEB-INF/jsp/errori/nfe.jsp</location>
</error-page>

HttpServletRequest e HttpServletResponse

Ora, attraverso una serie di JSP, andremo ad analizzare i principali metodi di HttpServletRequest e di HttpServletResponse. Tutti i metodi che utilizzeremo saranno ovviamente utilizzabili anche da eventuali servlet.

Intestazioni della richiesta

Esaminiamo un breve esempio dimostrativo, che recupera le intestazioni della richiesta, mostrandole in output. All'interno della nostra Applicazione1 creiamo la jsp intestazioni.jsp:

<%@ page import="java.util.Enumeration" %>
<html>
	<head>
		<title>intestazioni della richiesta</title>
	</head>
	<body>
		<h2>intestazioni HTTP:</h2>
		<ul>
		<%
		Enumeration e = request.getHeaderNames();
		while (e.hasMoreElements())
		{
			String nome = (String) e.nextElement();
			String valore = request.getHeader(nome);	
		%>
			<li><b><%=nome%></b>: <%=valore%></li>
		<%
		}
		%>
		</ul>
	</body>
</html>

Parametri della richiesta

Vediamo ora il recupero dei parametri della richiesta. Il passaggio di parametri, sostanzialmente, avviene in modalità GET oppure in modalità POST.

Quando una richiesta è svolta in modo GET i parametri sono forniti come come parte dell'url richiesto, distaccati dal nome della pagina con un punto interrogativo. Qualcosa come

http://www.host.com/search.do?q=ciao

La parte che segue il ? prende il nome di querystring e può contenere anche più di una coppia chiave-valore, in questo modo:

chiave1=valore1&chiave2=valore2&...&chiaveN=valoreN

Quando la richiesta avviene invece in modo POST i parametri sono trasferiti in maniera trasparente come corpo della richiesta, di seguito alle intestazioni. Pertanto non sono più visibili in coda all'url della pagina domandata.

Ad ogni modo, non è importante conoscere quale metodo sia stato utilizzato per inviare i dati, in quanto l'oggetto HttpServletRequest fornisce una serie di metodi recuperare in modo trasparente sia i parametri GET che i POST.

Il primo metodo che affronteremo è request.getParameter(String name) che recupera uno specifico parametro e lo restituisce sotto forma di stringa. Nel caso il parametro ricercato non esista verrà ritornato null.

Vediamo un esempio banale: nella nostra Applicazione1 creiamo la pagina nome.jsp con questo contenuto

<html>
	<head>
		<title>nome</title>
	</head>
	<body>
		<%
		String nome = request.getParameter("nome");
		%>
		<b>nome</b>:<br/>
		<%= (nome != null) ? nome : "non pervenuto" %>
	</body>
</html>

Proviamo ora a puntare il nostro browser (come sempre dopo aver ri-deployato l'applicazione! -d'ora in poi sarà sottointeso che a ogni modifica bisogna ri-deployare il tutto) a http://localhost:8080/Applicazione1/nome.jsp

e a http://localhost:8080/Applicazione1/nome.jsp?nome=Stefano

Lo stesso sarebbe avvenuto passando tale parametro in modalità POST. Proviamo subito: creiamo (sempre nella nostra Applicazione1) il file nomeForm.html con all'interno

<html>
	<head>
		<title>nome</title>
	</head>
	<body>
		<form method="POST" action="nome.jsp">
			nome: <input type="text" name="nome"/><input type="submit"/>
		</form>
	</body>
</html>

andiamo ora a http://localhost:8080/Applicazione1/nomeForm.html, completiamo, inviamo ... e come volevasi dimostrare vedremo il nome che abbiamo inserito nel form.

Ma un parametro può anche ricorrere più di una volta; in pratica è lecito inviare ad una servlet più argomenti con lo stesso nome. vediamo subito un esempio: creiamo un form e una jsp per raccogliere i dati inviati:

coloriForm.html:

<html>
	<head>
		<title>colori</title>
	</head>
	<body>
		<form method="POST" action="colori.jsp">
			quali sono i tuoi colori preferiti?<br/>
			<input type="checkbox" name="colori" value="Rosso"/>Rosso<br/>
			<input type="checkbox" name="colori" value="Nero"/>Nero<br/>
			<input type="checkbox" name="colori" value="Blu"/>Blu<br/>
			<input type="checkbox" name="colori" value="Verde"/>Verde<br/>
			<input type="submit"/>
		</form>
	</body>
</html>

e colori.jsp:

<html>
	<head>
		<title>colori</title>
	</head>
	<body>
		<b>i tuoi colori preferiti sono</b>:
		<ul>
			<%
			String[] colori = request.getParameterValues("colori");
			if (colori == null)
			{
				out.println("non ti piace nessun colore");
			}
			else
			{
				for (int i = 0; i < colori.length; i++)
				{
				%>
				<li><%=colori[i]%></li>
				<%
				}
			}
			%>
		</ul>
	</body>
</html>

vediamo ora il risultato a http://localhost:8080/Applicazione1/coloriForm.html (vi siete ricordati di ri-deployare, vero? :-)

Invio di errori o redirezioni

Utilizzando opportuni metodi di HttpServletResponse è possibile mandare al client errori http o redirezioni.

Questi metodi sono response.sendError(int httpError) (o, in alternativa, response.sendError(int httpError, String errorMessage)) per mandare un'errore, e response.sendRedirect(String url) per redirigere la richiesta ad un'altra pagina. E' buona norma utilizzare la funzione sendRedirect() in accoppiata con response.encodeRedirectURL(), per garantire il mantenimento della sessione. Proviamo subito queste funzioni con due jsp: errore.jsp e redirect.jsp

errore.jsp:

<%
response.sendError(403, "Non sei autorizzato");
%>

redirect.jsp:

<%
response.sendRedirect(response.encodeRedirectURL("prima.jsp"));
%>

Accesso al contesto di esecuzione

Vediamo ora come accedere all'oggetto ServletContext: creiamo una jsp chiamata server.jsp:

<html>
	<head>
		<title>informazioni sul server</title>
	</head>
	<body>
		<b>Server: </b><%=getServletContext().getServerInfo()%>
	</body>
</html>

Le sessioni utente

Il protocollo HTTP è privo di stati, in quanto non dispone di alcun meccanismo utile per conservare la "cronologia" delle richieste provenienti da uno stesso utente. Nel caso sia necessario seguire un client attraverso tutta l'applicazione web, pagina dopo pagina, si deve per forza ricorrere ad un meccanismo esterno. Le sessioni utente costituiscono un meccanismo che sopperisce alla mancanza di stati del protocollo http. Quando un utente si collega per la prima volta all'applicazione web, Tomcat gli associa un identificativo univoco, che lo contraddistingue da ogni altro client. Tale codice viene conservato sia all'interno del server sia nel client, sotto forma di cookie temporaneo oppure come querystring appesa ai collegamenti presenti nella pagina richiesta. Quando l'utente si sposta verso una nuova pagina, tale codice può così essere rispedito al server, in un modo o nell'altro. Il server a questo punto può recuperare il valore inviato dal client, e, confrontandolo con tutti quelli che ha in memoria, riconoscere la provenienza della richiesta. Le applicazioni web possono così sfruttare questo meccanismo memorizzando dei dati all'interno delle cosiddette variabili di sessione. I dati mantenuti all'interno delle variabili di sessione, anzichè venir mandati esplicitamente all'utente (con il rischio di intercettazione o di modifica), vengono conservati all'interno del server, associati all'identificativo univoco del client.

Le sessioni utente hanno però uno svantaggio: i dati, all'interno del server, non possono essere mantenuti in eterno. Per questo ogni sessione ha una durata limitata nel tempo. Ad ogni utente, dopo la creazione della sua sessione, è concesso un tempo di inattività massimo, superato il quale il suo identificativo ed i dati relativi saranno rimossi dalla memoria del server.

Le sessioni utente sono disponibili alle servlet grazie alla classe HttpSession, richiamabile con request.getSession(). Cominciamo con un esempio semplice semplice: vediamo quale è il nostro id univoco di sessione, e recuperiamo un po' di informazioni: creiamo la jsp idsessione.jsp:

<%@ page import="java.util.Date" %>
<html>
	<head><title>id</title></head>
	<body>
		id di sessione: <%=request.getSession().getId()%><br/>
		Data di creazione: <%= new Date(request.getSession().getCreationTime()) %><br/>
		Ultimo accesso: <%= new Date(request.getSession().getLastAccessedTime()) %><br/>
		Massima inattività concessa: <%= request.getSession().getMaxInactiveInterval() %> secondi<br/>
	</body>
</html>

E' possibile comunque variare il tempo di massima inattività utilizzando il metodo setMaxInactiveInterval(int secondi).

Qualsiasi sessione, inoltre, può essere invalidata e chiusa prima del termine della sua durata, servendosi del metodo invalidate()

E' possibile inserire e recuperare dati dalla sessione con i metodi getAttribute e setAttribute, che hanno le seguenti firme:

vediamo un esempio: creiamo le due jsp sessioneForm.jsp e sessioneValori.jsp

sessioneForm.jsp:

<html>
	<head><title>sessioni</title></head>
	<body>
		<form method="POST" action="sessioneValori.jsp">
			nome: <input type="text" name="nome"/><br/>
			valore: <input type="text" name="valore"/><br/>
			<input type="submit"/>
		</form>
		<br/>
		<a href="<%=response.encodeURL("sessioneValori.jsp")%>">visualizza variabili di sessione</a>
	</body>
</html>

notiamo subito l'uso di response.encodeURL() nel collegamento: questo serve per aggiungere in automatico l'id di sessione come quesrystring nel caso il browser client non supporti i cookie.

sessioneValori.jsp:

<%@ page import="java.util.Enumeration" %>
<%
String nome = request.getParameter("nome");
String valore = request.getParameter("valore");
if (nome != null && !nome.equals(""))
	request.getSession().setAttribute(nome, valore);
%>
<html>
	<head><title>sessioni</title></head>
	<body>
		<h3>variabili di sessione:</h3>
		<ul>
			<% 
			Enumeration e = request.getSession().getAttributeNames();
			while (e.hasMoreElements())
			{
				String chiave = (String)e.nextElement();
			%>
				<li><b><%=chiave%></b>: <%=request.getSession().getAttribute(chiave)%></li>
			<%
			}
			%>
		</ul>
		<br/>
		<a href="<%=response.encodeURL("sessioneForm.jsp")%>">inserisci variabile di sessione</a>
	</body>
</html>

faccio notare che all'interno di una JSP, sebbene io abbia usato request.getSession(), è disponibile la variabile "session" che, in fin dei conti, è la stessa cosa. Ho usato la forma request.getSession() per abitudine, in quanto nelle servlet (di default) non esiste la variabile "session", a meno che non venga inizializzata dal programmatore.

Termina qui il primo articolo della serie. Con le nozioni apprese finora potreste già provare a creare qualche semplice applicazione web, mentre nei prossimi articoli capiremo come passare informazioni in maniera trasparente tra servlet e JSP (in modo da avere una servlet che funge da controller ed una serie di viste jsp), ed andremo ad affrontare altri elementi fondamentali per la programmazione web in java, come i custom tag ed i filtri. Seguirà poi un'introduzione ad ant, che ci permetterà di automatizzare la compilazione dei nostri progetti.

Riferimenti bibliografici

[1] Apache Tomcat: http://tomcat.apache.org/

[2] http://java.sun.com/



L'autore

Stefano Sasso si diverte a configurare server e sistemi di rete e si diletta nella programmazione Java, PHP, Perl e Python. Frequenta il corso di laurea in Ingegneria Informatica presso l'Università di Padova e a tempo perso è consulente informatico su piattaforme Open Source.


Sinistra <- Monitoraggio di sistemi in rete - parte 4 - Indice Generale - Copertina - Preseeding Debian Parte I -> Destra