Per il Webmaster esistono principalmente due strade attraverso le quali pubblicare contenuti destinati al Web:
- Creare una per una le singole pagine che andranno a comporre il suo sito internet utilizzando del semplice codice HTML.
- Utilizzare una tecnologia Server Side che gli permetta di produrre dinamicamente codice HTML attraverso il quale rendere disponibili i contenuti.
Nel primo caso si parla di "pagine web statiche"; nel secondo caso parliamo invece di "pagine web dinamiche", o meglio di pagine web "generate dinamicamente".
Per molti lettori il discorso con cui introduciamo la nostra guida a JSP (Java Server Page), non rappresenterà certo una novità; ma la distinzione fondamentale tra linguaggi client side e server side, si rivela sempre più importante soprattutto per coloro che affrontano i primi passi nella produzione per il Web.
Oggi, a distanza di oltre una decina d’anni dalla diffusione di Internet presso il grande pubblico, diventa molto importante comprendere quanto sia marcata la differenza tra la gestione di un sito "statico" è un sito "dinamico". Passati i tempi (ma sono mai esistiti?) in cui ogni "tag" sembrava potersi trasformare in oro, oggi i Webmaster hanno una concezione più elevata del valore del loro lavoro, del loro tempo e della professionalità dei loro prodotti.
Un sito composto da pagine "statiche" non è certo comodo da gestire, bisogna impaginare e formattare "a mano" i nuovi contenuti e così anche tutto ciò che gravita attorno ad essi: layout, menu, eventuali mappe.. Utilizzando il semplice HTML sarà poi arduo mettere a disposizione degli utenti servizi addizionali come forum di discussione, newsletter, guestbook.. Certo si potrà sempre ricorrere a risorse esterne, ma il nostro discorso si rivolge a chi vuole fare del Web il proprio mestiere.
L’utilizzo di tecnologie server side per la produzione "dinamica di contenuti" come PHP, ASP e non ultima quella riferita alle JSP, ci consente di costruire siti professionali semplici da gestire, compatibili con i più diffusi browser esistenti e soprattutto capaci di "interagire" con gli utenti soddisfando le loro richieste sulla base del meccanismo "input/output", "domanda/risposta".
Le pagine Web concepite secondo tecnologie Server Side funzionano in linea generale sempre nello stesso modo:
- L’utente, attraverso il suo browser invia una richiesta, per esempio utilizzando il protocollo HTTP tramite la digitazione di una url.
- La richiesta viene raccolta e interpretata da un Web server che ricerca la risorsa desiderata all’interno del server in cui è installato.
- Trovata la risorsa richiesta, il Web Server la trasmette al browser del client sotto forma di codice HTML.
La tecnologia per le JSP consente la creazione di "pagine dinamiche" capaci di interloquire da una parte con l’utente e dall’altra con un Web Server, o per meglio dire con Servlet Engine JSP come per esempio Tomcat. Per comprendere il funzionamento e i passaggi necessari all’installazione e alla configurazione di Tomcat invitiamo il lettore a consultare la guida presente nell’apposita sezione. In queste pagine ci dedicheremo invece a conoscere le basi del linguaggio di scripting server side per le JSP.
Architettura delle JSP: come funzionano le Java Server Pages
Nel capitolo introduttivo di questa guida, abbiano anticipato alcuni elementi riguardanti le regole generali che stanno alla base del funzionamento dei siti web "dinamici", sottolineando come, al di là delle specifiche proprie di ogni linguaggio, i meccanismi che hanno luogo attraverso di essi siano nella maggioranza dei casi molto simili. Alla base di tutto vi è in effetti una logica basata sul’interscambio "input/output" che non caratterizza soltanto i linguaggi di scripting server side ma il mondo dell’informatica in generale.
In questo capitolo ci concentreremo sull’architettura delle JSP e sulle dinamiche specifiche che essa mette in atto al momento della nota iterazione tra client e server che sta alla base della Rete.
Il linguaggio indispensabile per la concezione di pagine ".jsp" segue determinate specifiche che vengono messe a disposizione dalla notissima casa madre di Java la Sun, conosciuta presso il grande pubblico anche per progetti altrettanto importanti come il portale di aste on line eBay e il sistema operativo Sun Solaris. Le pagine Web create utilizzando la tecnologia per le JSP sono comuni file testuali contenenti codice di scripting server side, cioè stringhe di testo che se interpretate sono destinate a produrre determinati comportamenti, e semplici tags HTML.
Quello utilizzato per le JSP è quindi un linguaggio html embedded, cioè "immerso" e "nascosto" all’interno dei tags HTML con i quali convive ed interagisce a regola d’arte; quindi, in ogni pagina con estensione ".jsp" possiamo individuare due elementi perfettamente distinguibili: il codice "dinamico" derivante da Java e destinato ad essere interpretato e quindi processato (parser) dal Web server e, il codice client side (HTML, Javascript, CSS …) interpretato dal browser.
Nel caso specifico, al momento dell’invocazione di una pagina ".jsp" si succederanno le fasi seguenti:
- Chiamata di una pagina ".jsp" tramite browser.
- Raccolta della chiamata da parte del Web server.
- Il Web server "vede" la pagina ".jsp", la riconosce e la consegna nelle mani dell’Engine JSP, ad esempio Tomcat.
- La pagina ".jsp" viene processata una prima volta.
- Il file ".jsp" viene tradotto in una classe Java e compilato in una Servlet (un’applicazione residente sul server ).
- Vengono chiamati i metodi init e service in modo che la pagina ".jsp" non debba subire nuovamente lo stesso processo di riconoscimento, traduzione e compilazione ad ogni nuova chiamata.
- La richiesta effettuata attraverso la chiamata viene soddisfatta sotto forma di un output costituito da una pagina recante codice HTML prodotto dinamicamente.
La Servlet ottenuta dalla traduzione e compilazione del codice per le JSP si avvale del metodo init, quest’ultimo viene chiamato un prima volta quando la Servlet viene caricata, da quel momento essa girerà in esecuzione sulla JVM (Java Virtual Machine) e sarà pronta a rispondere ad ogni successiva chiamata.
Init però, si occuperà soltanto di inizializzare i processi, ogni successiva chiamata del file ".jsp" sarà gestita dal metodo service.
Le Servlet
Essendo degli elementi fondamentali e peculiari all’interno della tecnologia che sta alla base dell’architettura per le JSP, le Servlet meritano alcune righe di approfondimento in modo da comprenderne più a fondo il funzionamento, siamo infatti davanti a dei veri e propri applicativi prodotti dall’esecuzione di un codice di scripting server side.
Come anticipato nel capitolo precedente, con il termine Servlet viene denominata un’applicazione, scritta in linguaggio Java, che opera in esecuzione sulla Java Virtual Machine nella costante attesa di soddisfare le chiamate che vengono raccolte dal Web server e passate al Servlet Engine JSP.
La JVM, conosciuta anche come "macchina virtuale Java", è parte integrante della distribuzione ufficiale messa a disposizione dalla casa madre Sun per il linguaggio Java, cioè il J2SE SDK (Java 2 Standard Edition Software Development Kit), noto anche come JDK; la JVM rappresenta un software di appoggio per il JRE (Java Runtime Environment), o "ambiente Java", durante l’esecuzione di applicazioni scritte in Java.
In pratica, la Java Virtual Machine non è altro che un software con il compito di interpretare il linguaggio Java lato web, una "macchina virtuale" in grado di lavorare su differenti architetture hardware e di decifrare istruzioni scritte in un codice compilato appositamente per essa.
Il compito delle Servlet, è peculiarmente quello di eseguire determinate operazioni con la finalità di produrre dinamicamente, in output, codice HTML da inviare come risposta al browser del client che ha effettuato la richiesta di una qualsiasi risorsa presente nel server.
Dato che in pratica stiamo parlando di Web applications, qualche lettore più inserito nel mondo della produzione per Internet avrà già pensato a una similitudine con le CGI (Common Gateway Interface).
Vi è però una differenza fondamentale tra applicativi prodotti tramite JSP e applications CGI: le prime infatti, una volta concepite non necessitano di un nuovo processo creativo per ogni chiamata, si limitano ad aspettare ed entrano in gioco al momento delle successive richieste, tutto questo con un notevole risparmio in termini di utilizzo delle risorse messe a disposizione dalla macchina server.
Naturalmente le Servlet sono "persistenti" ma non per questo necessariamente "immortali". Hanno un momento d’inizio (creazione), o meglio d’inizializzazione, consentito dalla chiamata del metodo init; un’attività vitale gestita dal metodo service al servizio delle successive chiamate; infine, vengono eliminate tramite il metododestroy.
All’occorrenza del metodo destroy, le Servlet "muoiono" ma non vengono dimenticate, saranno infatti archiviate in memoria tutte le informazioni necessarie per i successivi processi creativi.
Un primo script per le JSP
Dopo alcune pagine dedicate interamente alla teoria, in questo capitolo passeremo ad un approccio più pratico cominciando ad introdurre qualche frammento di codice per le Java Server Page. Perchè i nostri scripts per JSP possano essere eseguiti, dovremo salvare i file in cui sono stati creati utilizzando un’apposita estensione.
A pensarci bene, quella appena descritta è una pratica comune a tutti i linguaggi di scripting server side: salveremo il nostro codice PHP in una pagina ".php", i nostri script ASP in una pagina ".asp" e, i nostri file per JSP avranno appunto in ".jsp" la loro estensione.
Nei capitoli precedenti, abbiamo insistito sul fatto che quando eseguiamo un file ".jsp", questo viene riconosciuto dal Web server, dirottato al Server Engine, tradotto e compilato in modo da generare una Servlet a disposizione dei metodi init e service. Tutti questi passaggi implicano, esclusivamente per la prima chiamata, un certo lasso di tempo necessario per la loro esecuzione.
Facciamo un piccolo esempio, creiamo un semplice file ".html" con poche righe di codice all’interno
<html>
<head>
<title>Pagina HTML</title>
</head>
<body>
<h1>Prova</h1>
</body>
</html>
Salviamo il codice appena digitato con un nome qualsiasi, per esempio "prova.html" e inviamolo alla root del Servlet Engine; poi, apriamo il nostro browser preferito e digitiamo l’url necessaria per raggiungere il file appena creato, ad esempio:
http://localhost:8080/prova.html
Dovendo essere interpretato unicamente dal programma di navigazione, il documento non subirà alcun processo lato server e verrà caricato in pochi attimi visualizzando la stringa attesa: "Prova".
Ora, modifichiamo l’estensione del file che da ".html" cambierà in ".jsp"; torniamo al nostro browser e digitiamo la relativa url:
http://localhost:8080/prova.jsp
Nonostante il fatto che anche in questo caso visualizzeremo in output la medesima schermata, stavolta noteremo un tempo di caricamento leggermente più lungo. Ciò avverrà unicamente a causa dei processi di cui abbiamo parlato in precedenza; dopo la prima esecuzione però, il tempo di caricamento del file sarà più breve in quanto si saranno esaurite le procedure d’inizializzazione.
Passiamo ora ad un piccolo script d’esempio, scriveremo il nostro primo codice per JSP in grado di produrre dinamicamente HTML, nel caso specifico richiederemo la stampa a video di una breve frase. Creiamo una nuova pagina chiamata "jsp_prova.jsp", apriamola utilizzando un qualsiasi editor di testo come il Blocco Note di Windows o Vim di Linux e digitiamo:
<html>
<head>
<title>Pagina JSP</title>
</head >
<body>
<% out.println("<h1>Prova</h1>"); %>
</body>
</html>
Inviamo la pagina alla root del Servlet Engine e lanciamola digitando la sua url col nostro browser:
http://localhost:8080/jsp_prova.jsp
Come avrete avuto modo di notare, il codice Java della pagina "jsp_prova.jsp" è stato isolato tra i delimitatori "<%" e "%>"(chi ha pratica con ASP li avrà sicuramente utilizzati tante volte) in modo da poter essere riconosciuto come tale.
L’istruzione out.println ha il compito di stampare a video il parametro che le viene passato.
Dichiarazioni, Scriptlet, Espressioni e Action nelle JSP
Tutto sommato è abbastanza semplice creare scripts per le JSP sfruttando le opportune specifiche, la loro sintassi e i loro costrutti infatti non si differenziano poi tanto da quelli di altri linguaggi Server Side come PHP o ASP. L’architettura delle JSP si presenta però articolata in varie componenti che necessitano di essere analizzate prima di cominciare a scrivere del codice un po più complesso rispetto a quello proposto nel capitolo precedente.
Innanzitutto, è importante chiarire i concetti correlati ad alcuni elementi fondamentali che si presentano spesso all’interno dello scripting JSP:
- Le Dichiarazioni.
- Le Scriptlet.
- Le Espressioni.
- Le Actions o Standard Actions
Le Dichiarazioni vengono espresse sintatticamente in questo modo:
<%! codice %>
non vi sono quindi particolari novità rispetto alla sintassi standard degli scripts se non per il punto esclamativo ("!") posto a seguito del primo delimitatore; esse vengono inglobate all’interno della Servlet, non sono destinate a generare output, ma a riprodurre determinati comportamenti e possono essere utilizzate sia per le variabili che per metodi.
Per esempio, attraverso questo semplice script:
<%! private int accessCount = 0; %>
<%= ++accessCount %>
creeremo un efficiente contatore di accessi per le nostre pagine Web. Nella prima riga è stata espressa la Dichiarazione e il nostro contatore partirà da zero, successivamente, nella seconda riga indichiamo un incremento unitario ("++") per ogni accesso rilevato.
Le Scriptlet sono frammenti di codice che dovrà essere eseguito quando sarà necessario processare una richiesta; la loro sintassi è quella già nota per il codice delle JSP:
<% codice %>
Tutto il codice interno ai delimitatori " <%" e "%>" verrà inserito nel metodo _jspService() della Servlet durante la compilazione.
Anche in questo caso facciamo un piccolo esempio:
<%
java.util.Date data_di_oggi = new java.util.Date();
out.println( String.valueOf( data_di_oggi ));
%>
Testando le poche righe di codice appena digitate, visualizzeremo in output la data odierna completa di giorno, mese, anno, ore, minuti e secondi.
Le Espressioni vengono utilizzate per introdurre valori all’interno dell’output della Servlet e seguono questa sintassi:
<%= espressione java%>.
I valori, a seconda della loro entità, subiscono una valutazione di carattere logico, letterale o matematico e il risultato finale subisce la conversione in una java.lang.String.
L’uso delle Espressioni da parte dello sviluppatore viene facilitato dall’esistenza di oggetti predefiniti che possono essere immediatamente utilizzati per produrre il comportamento per cui sono deputati. Ad esempio:
<%= request.getRemoteHost() %>
sfrutta l’oggetto request per richiedere il nome di Host del server (se testiamo lo script su Tomcat in locale a meno di nostre modifiche otterremo il classico 127.0.0.1).
Le Actions o Standard Actions sono tags specifici che agiscono sul comportamento dei file ".jsp" e sugli output destinati a soddisfare le richieste; abbiamo numerose tipologie di Standard Actions, tra cui assumono un’importanza particolare quelle che richiamano i JavaBeans di cui ci occuperemo tra breve.
Come esempio, proponiamo due piccoli script basati sui tags jsp:include e jsp:forward:
<html>
<head>
<title>jsp:include</title>
<b>Output<b>:
<jsp:include page="jsp_prova.jsp"/>
</body>
</html>
<html>
<head>
<title>jsp:forward</title>
<b>Output<b>:
<jsp:forward page="jsp_prova.jsp"/>
</body>
</html>
I due frammenti di codice appena digitati possono essere salvati in due file: "include.jsp" e "forward.jsp" e testati sottoponendoli all’azione del Servlet Engine; il primo "includerà" l’output previsto in "jsp_prova.jsp" all’interno di "include.jsp", il secondo "inoltra" l’output di "jsp_prova.jsp" in "forward.jsp".
Le Direttive
Le Direttive non producono output ma mettono a disposizione definizioni, notifiche e informazioni valide e disponibili in tutto il documento ".jsp". La sintassi più utilizzata per le Direttive è la seguente:
<%@ Codice %>
Come avrete avuto modo di notare, a livello sintattico è sufficiente far seguire al primo delimitatore una chiocciolina ("@") per introdurre una Direttiva.
A livello sostanziale, abbiamo invece tre tipologie principali di Direttive utilizzabili:
- Page: attraverso la quale vengono direttamente coinvolti i criteri di compilazione delle pagine.
- Include: include stringhe di testo o ulteriore codice all’interno di un file.
- Taglib: abbreviazione di tag library, attraverso di essa possiamo utilizzare tags personalizzati, indicare la libreria in cui sono definiti e associare loro un prefisso che li renda univoci.
Potremo quindi dire che la Direttiva Page esprime una "definizione di attributi"; Include esprime una "notifica" al Servlet Engine riguardo a un punto determinato del file ".jsp" in cui và incluso del codice esterno; infine, Taglib "autorizza" l’uso di costrutti sintattici definiti dallo sviluppatore.
Anche in questo caso sarà utile proporre alcuni esempi pratici utili a chiarire l’argomento trattato.
Inseriamo per esempio il codice seguente in un file chiamato "d_page.jsp":
<%@ page import="java.util.*" %>
<html>
<head>
<% Date data_di_oggi = new Date(); %>
<%= data_di_oggi %>
</head>
</html>
Come avremo modo di notare testando lo script appena proposto, con esso otteniamo un modo alternativo per visualizzare la data odierna rispetto a quello creato nel capitolo 5 di questa guida.
Nel codice appena proposto, abbiamo utilizzato la Direttiva Page per importare il package java.util, sarebbe stato poi possibile introdurre ulteriori packages semplicemente separandoli con una virgola; in secondo luogo abbiamo utilizzato la comune sintassi per le JSP in modo da assegnare un valore al parametro stringa "data_di_oggi"; infine, abbiamo introdotto un’Espressione per la produzione dell’output desiderato.
Facciamo ora un esempio riguardate la Direttiva include, per alcuni versi o se non altro per una semplice questione di omonimia, essa potrebbe essere confusa con la Standard Actions jsp:include, ma la logica che sottende al suo funzionamento è differente.
Creiamo un file, chiamato per esempio "d_include.jsp" e salviamolo con il seguente codice al suo interno:
<html>
<head>
<b>Output<b>:
<%@ include file="jsp_prova.jsp" %>
</head>
</html>
Sarà possibile testare il breve script precedente sostituendo il richiamo al documento "jsp_prova.jsp" con quello riferito ad un file dotato di estensione differente come ".txt" o ".htm", non noteremo alcuna differenza, in quanto la Direttiva include si occupa dell’inclusione "fisica" della pagina che le viene passata come parametro.
Come abbiamo avuto modo di notare, l’output ottenuto è lo stesso visualizzato in precedenza utilizzando l’Actions jsp:include, ma è importante tener presente che quest’ultima non opera una vera e propria inclusione "fisica" dei documenti ma più propriamente ne esegue il codice all’interno del file in cui viene richiamata.
Abbiamo infine Taglib che come è stato anticipato consente l’impiego di tags definiti dall’utente. La sintassi di questa direttiva si presenta nella forma seguente
<%@ taglib uri="tag library" prefix="prefisso per i tag" %>
L’uri indica l’archivio della tag library scelto dallo sviluppatore, mentre prefix indica il prefisso utilizzato per il richiamo dei tags. Un esempio dell’utilizzo di Taglib potrebbe essere questo:
<%@ taglib uri="http://www.sito.it/tags" prefix="tgs" %>
<tgs:Tag attribute="value"> STRINGA </tgs:Tag>
La questione riguardante l’archiviazione della tag library è quindi molto semplice in quanto perchè esse vengano reperite basterà posizionare l’archivio in un qualsiasi punto del server raggiungibile tramite url.
I tipi di dato e le variabili predefinite nelle JSP
Probabilmente, chi ha già una certa pratica nello Scripting Server Side, troverà in questo capitolo numerosi elementi con i quali ha avuto più volte a che fare. Parliamo infatti dei tipi di dato, in pratica le informazioni con le quali le JSP lavorano, interagiscono e producono i loro ouput.
I tipi di dato maggiormente utilizzati nelle JSP sono:
- Booleani: per definizione questi dati possono avere esclusivamente due valori, possono essere cioè o veri o falsi (TRUE o FALSE). Un dato booleano può essere immediatamente dichiarato come vero o falso (ad esempio dato=TRUE), oppure è possibile porre delle condizioni (ad esempio dato=2>3, falso; dato=2<3, vero).
- Byte: dati utilizzati per la memorizzazione di valori interi positivi o negativi compresi in un range che và da 127 a -128.
- Short: dati utilizzati per la memorizzazione di valori interi positivi o negativi compresi in un range delimitato tra 32767 e -32768.
- Char: dati utilizzati per la memorizzazione di valori interi positivi in un range tra 0 e 65535.
- Int: dati utilizzati per la memorizzazione di valori interi positivi o negativi compresi tra 2147483647 e -2147483648.
- Long int: dati utilizzati per la memorizzazione di valori interi positivi o negativi compresi in un range che và da 9223372036854775807 a -9223372036854775808.
- Float: tipi di dato in "virgola mobile", utilizzati per la memorizzazione di valori interi positivi o negativi compresi i decimali (formati da 32 bit).
- Double: tipi di dato in "virgola mobile", utilizzati per la memorizzazione di valori interi positivi o negativi compresi i decimali (formati da 64 bit).
- Stringhe: si tratta di un tipo particolare, infatti non vengono considerate come tipi predefiniti ma sono comunque utilizzate di frequente e riconosciute da Java grazie all’azione dei doppi apici ("stringa").
I tipi di dato propongono valori che è possibile assegnare a variabili e array. Una variabile è un costrutto destinato a contenere informazioni che le verranno passate, appunto, sotto forma di valori. Per fare un esempio possiamo attribuire ad una variabile chiamata "var" il valore numerico intero e positivo "100" e sincerarci dell’avvenuta assegnazione attraverso una stampa a video:
<% int var = 100; %>
<%
out.println(var);
%>
Utilizzando lo stesso sistema potremo assegnare un valore di tipo stringa con l’accortezza di specificare il tipo di dato (String):
<% String var = "Guida alle JSP"; %>
<%
out.println(var);
%>
Gli array sono invece particolari tipi di variabili destinate all’assegnazione di più valori, vediamone un esempio:
<% String[] numeri = {"uno", "due", "tre", "quattro"}; %>
<%
out.println(numeri[0]);
out.println(numeri[1]);
out.println(numeri[2]);
out.println(numeri[3]);
%>
Come avremo modo di notare testando lo script, gli array numerano da 0 a n i valori che vengono loro assegnati.
Un’altro argomento molto importante per lo sviluppo delle JSP e quello che fa riferimento alle variabili predefinite, note anche come oggetti impliciti; stiamo parlando di variabili che vengono automaticamente definite nel linguaggio stesso.
Nella creazione di pagine ".jsp" possiamo avvalerci di otto differenti oggetti impliciti:
- request: la HttpServletRequest associata alla richiesta di risorse generata in input dall’utente; grazie ad essa abbiamo la possibilità di rilevare parametri fondamentali (getParameter) come: metodi utilizzati per la richiesta (Post, Get..), intestazioni (headers..). Nel caso in cui il protocollo sia diverso da HTTP avremo in associazione ServletRequest, si tratta comunque di un’opzione raramente utilizzata.
- response: la HttpServletResponse associata alla risposta generata in output dal Servlet Engine; attraverso questa variabile possiamo notificare errori, spedire intestazioni, settare cookies, etc…
- application: il ServletContext generato sulla base dell’azione operata sui parametri passati a getServletConfig().getContext(); permette di accedere al contesto in cui viene eseguita la Web application, sarà quindi possibile ottenere informazioni sull’Engine JSP e reperire parametri inizializzati.
- config: la ServletConfig riferita alla pagina; dato che le informazioni messe a disposizione da config sono comunque generalmente settate e rilevate automaticamente, questo oggetto implicito viene spesso lasciato inutilizzato.
- pageContext: la classe PageContext e stata specificamente introdotta per le JSP; l’oggetto pageContext è in grado di rappresentare ogni elemento riconducibile al contesto in cui viene eseguita la pagina.
- out: il cosiddetto PrintWriter, a cui spetta la funzione fondamentale di inviare l’ouput al client da cui è stata spedita la richiesta attraverso il protocollo di comunicazione.
- session: l’oggetto HttpSession associato alla richiesta; questa variabile consente d’identificare l’utente rendendo la sua sessione valida per tutto l’ambito di un’applicazione. I tempi di soddisfazione delle richieste potranno quindi essere abbreviati memorizzando le preferenze già espresse da ogni utente.
- Page: è il sinonimo della keyword This, più utilizzata in altri linguaggi di programmazione piuttosto che per la produzione di JSP.
Le istruzioni condizionali nelle JSP
Anche per quanto riguarda i prossimi due capitoli, è necessaria la stessa avvertenza fatta nel precedente, coloro che già conoscono altri linguaggi di produzione server side troveranno nelle prossime pagine costrutti sintattici a loro familiari. Chi invece ha deciso di cominciare dalle JSP una lunga e fortunata carriera nella produzione dinamica per il Web, si renderà conto di quanto siano semplici da utilizzare elementi importantissimi per lo scripting come istruzioni condizionali e cicli.
Le istruzioni, o per meglio dire le istruzioni condizionali, permettono la generazione in output di determinati comportamenti sulla base del verificarsi o meno di determinate condizioni.
L’istruzione if – else prevede il verificarsi di un comportamento se (if) certe condizioni sono valide, altrimenti (else) avrà vita un comportamento alternativo. Ecco un esempio:
<% int valore = 5; %>
<%
if (valore > 3)
{
out.println("Valore superiore a 3.");
}
else
{
out.println("valore inferiore a 3.");
}
%>
Chiaramente else rappresenta un’istruzione accessoria, utile per proporre un’alternativa al mancato verificarsi della condizione introdotta da if, infatti, il nostro script avrebbe funzionato comunque egregiamente anche nella seguente forma semplificata:
<% int valore = 5; %>
<%
if (valore > 3)
{
out.println("Valore superiore a 3.");
}
%>
Oltre ad if ed else, abbiamo: else if; tramite questa istruzione, introduciamo una seconda condizione che dovrà essere presa in considerazione quando la prima, proposta tramite if, risulta falsa. Sarà possibile imporre con else un’alternativa che avrà effetto se anche la seconda condizione non potrà verificarsi.
<% int valore = 1; %>
<%
if (valore == 3)
{
out.println("Valore identico a 3.");
}
else if (valore == 1)
{
out.println("Valore identico a 1.");
}
else
{
out.println("Nessun valore.");
}
%>
Nel codice appena proposto, la condizione introdotta da if non può verificarsi e l’istruzione non viene eseguita; viene invece visualizzata la stringa: "Valore identico a 1.", perchè risulta vera la condizione proposta da else if; else invece non dà luogo ad output, dato che si verifica la condizione proposta da else if.
Tramite l’istruzione switch, è possibile introdurre un argomento da valutare sulla base del suo valore; attraverso il costrutto case verranno iniziati una serie confronti con il valore proposto; se viene trovato un valore corrispondente, si realizzarà il comportamente previsto e l’istruzione break fermerà il processo.
<% int valore = 1; %>
<%
switch (valore)
{
case 4:
out.println("Valore identico a 4.");
break;
case 3:
out.println("Valore identico a 3.");
break;
case 2:
out.println("Valore identico a 2.");
break;
case 1:
out.println("Valore identico a 1.");
break;
default:
out.println("Nessun valore.");
}
%>
Nel codice proposto, attraverso switch abbiamo dato vita ad una serie di confronti introdotti da case e separati con break; quando (e se) viene rilevato un valore corrispondente a quello attribuito inizialmente, l’istruzione lancia comportamento voluto. L’istruzione default (opzionale), introduce invece un’ultima alternativa, che avrà luogo solo se nessuno dei confronti precedenti sarà in grado di restituire un valore corrispondente a quello proposto.
I cicli nelle JSP
In questo capitolo ci dedicheremo all’argomento riguardante i cicli o istruzioni di iterazione, tramite questi costrutti è infatti possibile eseguire ripetutamente (ciclicamente) determinati comportamenti. I cicli, quindi, consistono nella ripetizione di determinati comandi per un determinato numero di occorrenze.
Il ciclo for è certamente uno dei più utilizzati dagli sviluppatori, non solo per le JSP, cominciamo la sua descrizione con un semplice script:
<% int var, valore=100;%>
<%
for (var=0; var<100; var++)
{
out.println(valore = valore-1);
}
%>
Testando il codice appena proposto otterremo in output la stampa di tutti i numeri dal 99 allo 0.
Il ciclo for si realizza attraverso una sintassi composta dal costrutto for che deve essere seguito dalle istruzioni che definiscono il ciclo; seguono poi le istruzioni da eseguire ciclicamente. Le tre istruzioni che seguono for, hanno ognuna una specifica funzione:
- la prima (var=0) crea un valore iniziale, deve essere eseguita una sola volta all’inizio del ciclo. Nell’esempio, con essa abbiamo assegnato il valore iniziale del nostro ciclo.
- la seconda (var<100;) è una condizione di terminazione da valutare prima di ogni nuova iterazione, restituisce FALSE quando il ciclo si interrompe. Nell’esempio, abbiamo stabilito come condizione che le cifre da stampare debbano avere un valore inferiore a 100.
- la terza (var++) agisce incrementando o decrementando il valore assegnato nella prima istruzione. Essa viene rieseguita ad ogni iterazione del ciclo fino a che la condizione di terminazione non restituisce FALSE. Nell’esempio, il valore di "var" subisce un decremento unitario ad ogni iterazione.
Il ciclo while, che svolge funzione simile a quella di un’istruzione if ripetuta, ha costrutto sintattico abbastanza semplice: ad un ciclo while deve seguire una condizione da valutare e il comportamento da ripetere; quando la condizione restituisce FALSE il ciclo si arresta. Ecco un esempio:
<% int valore=0;%>
<%
while (valore<100)
{
out.println(valore = valore+1);
}
%>
Lo script proposto ha il semplice compito di visualizzare in output tutti i numeri da 1 a 100; while viene quindi ripetuto per 100 occorrenze e, ad ogni ripetizione il valore inizialmente settato a 0 subisce un incremento unitario; una volta assegnato il valore 100, la condizione prefissata (valore<100) non potrà più restituire TRUE e il ciclo si arresterà.
I lettori più attenti, avranno potuto osservare una caratteristica che accomuna for e while, infatti per entrambi se la condizione proposta si dimostra falsa già ad inizio ciclo il flusso di iterazione si arresta ancora prima di cominciare. Tramite il costrutto do while, invece, le istruzioni previste vengono eseguite almeno per una prima volta. do while possiede una sintassi simile a quella propria di while, vi è però la differenza che nel primo la condizione è proposta alla fine e non all’inizio. Facciamo un esempio:
<% int valore=0;%>
<%-- Esecuzione di un ciclo do while--%>
<%
do
{
out.println (valore = valore--);
}
while (valore>0);
%>
Tramite il ciclo do while visualizziamo in output la stampa della cifra 0, quindi, abbiamo comunque un risultato dovuto ad una singola iterazione; ponendo la condizione dopo le istruzioni, infatti, il blocco di istruzioni viene in ogni caso eseguito almeno per una prima volta.
La stringa:
<%-- Esecuzione di un ciclo do while--%>
inserita nel precedente script è un commento, esso non viene visualizzato in output e non ha la funzione di produrre comportamenti, serve invece allo sviluppatore per tenere traccia degli stati di avanzamento nella scrittura del codice. I commenti, racchiusi tra i delimitatori "<%–" e "–%>", si rivelano particolarmente utili quando devono essere realizzati scripts dai listati particolarmente complessi.
I JavaBeans
I JavaBeans, piccoli applicativi scritti i linguaggio Java, costituiscono una peculiarità delle JSP e rappresentano un grande vantaggio per lo sviluppatore sia in termini di risparmio di tempo che di pulizia del codice.
Gli esempi di Java Server Pages proposti in questa guida hanno seguito sino ad ora la stessa logica: il codice degli script è stato posizionato all’interno delle pagine stesse, "immerso" o no, a seconda dei casi, tra i tags HTML "miscelando" componenti statiche e dinamiche.
Certo fino ad adesso i listati proposti non presentano particolari complessità, ma se dovessimo costruire applicativi più strutturati la leggibilità del codice ne risentirebbe certamente rendendo più ardui eventuali aggiornamenti o correzioni.
Vi è poi un ulteriore discorso di cui tenere conto, altrettanto importante, è infatti sempre consigliabile creare codice "riutilizzabile" e "portabile", se per esempio dovessimo impiegare un determinato applicativo in più di una JSP sarebbe di certo seccante doverlo riscrivere e adattare per ognuna di esse.
Fortunatamente i JavaBeans esistono proprio per fornire una soluzione comoda e professionale alle problematiche appena descritte.
Essi sono destinati a contenere gran parte delle componenti dinamiche e funzionali di una Web application con il vantaggio di poterle omettere al momento della stesura delle JSP; inoltre, essendo realizzati secondo le specifiche del linguaggio Java, i JavaBeans posseggono consolidate doti in termini di portabilità.
Per essere utilizzati essi devono essere semplicemente "integrati" nelle JSP, dopo di chè sarà possibile sfruttarne tutti i metodi.; le JSP mettono a disposizione tre istruzioni per il richiamo dei JavaBeans.
La prima istruzione è <jsp:useBean>: associa la classe del JavaBean ad un oggetto posto all’interno della JSP, è così possibile richiamarne i metodi senza ulteriori riferimenti al file. A <jsp:useBean> vanno associati come attributi l’ID univoco per l’oggetto istanziato e Scope, cioè il contesto d’istanza dell’oggetto:
<jsp:useBean
id="<strong>javaBean</strong>"
scope="application"
class="nome_classe" />
Abbiamo poi l’azione <jsp:setProperty>, con cui possiamo settare il valore proprio di una delle proprietà di un JavaBeans. <jsp:setProperty> accetta come attributi: name, il nome dell’istanza; value, il valore della proprietà; param, cioè il nome del parametro da settare; property, che identifica la proprietà a cui assegnare il valore:
<jsp:setProperty
name="<strong>nomeIstanza</strong>"
property="proprietà"
param="parametro" />
Infine, abbiamo l’istruzione <jsp:getProperty> che visualizza in output il valore della proprietà di un’istanza inserendolo nella variabile predefinita out. Quest’ultima azione accetta come attributi il name e la property:
<jsp:getProperty
name="<strong>nomeIstanza</strong>"
property="proprietà" />
I JavaBeans utilizzano delle proprietà capaci di descrivere le informazioni poste al loro interno e destinate alla produzione dei comportamenti. Le variabili dei JavaBeans vengono rese inaccessibili agli utenti in quanto sono i di tipo private o protected, a renderle raggiungibili (si noti bene, non "accessibili") ci pensano dei metodi detti public.
I metodi utilizzabili per la raggiungibilità dei dati sono:
- public void setNome_Proprietà() a cui devono essere passati come parametri la tipologia dei dati, le proprietà e il loro valore.
- public Tipo_Proprietà getNome_Proprietà() che rileva informazioni sulla proprietà.
- public boolean isNome_Proprietà() che, come il secondo metodo, rileva informazioni sulla proprietà.
I JavaBeans sono un argomento veramente vasto perchè riguardano molto da vicino la programmazione orientata agli oggetti, come finale per questo capitolo presentiamo l’ossatura di un possibile JavaBean:
package hall;
public class NomeBean
{
private String stringa = "Nessuna notifica";
public String getStringa()
{
return(stringa);
}
public void setStringa(Nome Stringa)
{
this.stringa = stringa;
}
}
Come si nota leggendo il codice appena proposto, nella sintassi dei metodi essi vengono introdotti da get e set minuscoli da unire al nome del parametro con iniziale maiuscola; se dovessimo trovarci davanti a nomi composti anche l’iniziale della seconda parola sarà maiuscola (setPrimonomeSecondonome).
E’ poi utile ricordare che i JavaBeans non vanno conservati nello stesso percorso della root del Servlet Engine utilizzato per le JSP, ma hanno uno spazio a loro dedicato, generalmente la cartella di default sarà per Tomcat: "\WEB-INF\classes".
Gestire gli errori con le JSP
Come per tutti i linguaggi di scripting server side (e non solo), anche nella creazione delle JSP abbiamo la possibilità gestire i comportamenti e gli output che normalmente non dovrebbero avere luogo, le cosiddette "exceptions", attraverso componenti built-in forniti dal linguaggio stesso.
Nella maggior parte dei linguaggi, gli errori vengono gestiti attraverso la visualizzazione di una error page recante la notifica dei malfunzionamenti ed eventuali informazioni che possano portare alla loro soluzione.
Facciamo un breve esempio, riprendiamo lo script utilizzato per descrivere il ciclo while nel capitolo 9 di questa guida e modifichiamolo eliminando il primo delimitatore "<%" dal codice ; eseguendo il nuovo codice tramite il nostro Servlet Engine otterremo certamente una notifica simile a questa:
HTTP Status 500 -
type Exception report
message
description The server encountered an internal error ()
that prevented it from fulfilling this request.
exception
org.apache.jasper.JasperException:
Unable to compile class for JSP
An error occurred at line: 2 in the jsp file: /while2.jsp
Generated servlet error:
valore cannot be resolved
An error occurred at line: 2 in the jsp file: /while2.jsp
Generated servlet error:
valore cannot be resolved
An error occurred at line: 2 in the jsp file: /while2.jsp
Generated servlet error:
valore cannot be resolved
(................)
note The full stack trace of the root cause
is available in the Apache Tomcat/5.5.9 logs.
Apache Tomcat/5.5.9
Eliminando il primo delimitatore, abbiamo "corrotto" la parte di codice in cui viene assegnato un valore alla variabile "valore", Tomcat ci invia infatti un messaggio molto chiaro "valore cannot be resolved".
Questi "Exception reports" sono molto utili in fase di sviluppo per venire velocemente a capo degli errori; in fase di produzione è invece consigliabile (anche per una semplice questione formale) non mostrare questi "ineleganti" output agli utenti.
Sarà quindi buona norma creare una errorpage personalizzata da richiamare nel caso in cui dovessero verificarsi delle Exceptions. Se decidessimo di chiamare la nostra pagina di errore "errore.jsp", potremo indicarla al Servlet Engine con una semplice stringa come questa:
<%@ page errorPage="errore.jsp" %>
Per esempio, potremo creare una errorpage "errore.jsp" semplicissima contenente questo codice:
<h1>Errore nell'esecuzione della JSP</h1>
Con un po di fantasia la grafica risulterà certamente più piacevole, ma per ora ci basti osservare l’efficacia del risultato. Inseriamo la pagina appena creata nella root del Servlet Engine e passiamo alla seconda parte del nostro esempio.
Creeremo un piccolo script in cui cercheremo di passare un valore assurdo e formalmente errato ad una variabile senza dimenticarci di specificare all’inizio del codice l’opportuno richiamo alla pagina di errore:
<%@ page errorPage="errore.jsp" %>
<%
int valore = valido/valido;
%>
A questo punto basterà eseguire il codice appena digitato dopo averlo salvato in un pagina ".jsp" per visualizzare il risultato desiderato.
Le JSP e i database
Come per ogni architettura dinamica per il Web che si rispetti anche le JSP hanno la possibilità di interagire con i database, tramite esse sarà infatti possibile inserire, mostrare, aggiornare ed eliminare i dati presenti in un DB.
La JDBC, acronimo di Java DataBase Connectivity mette a disposizione un’ interfaccia in linguaggio Java con la quale eseguire istruzioni SQL; in pratica la JDBC funziona sulla base dell’azione di due driver: JDBC rappresenta il ponte (bridge) essenziale per l’accesso al DB tramite il driver ODBC del server. Oltre a questo metodo ve ne sono altri due utili per le stesse finalità:
- Driver Java: deputato all’interazione col DB senza la mediazione di driver bridge; il Driver Java in pratica traduce i comandi di connettività utilizzando direttamente il protocollo del Database Manager System (ad esempio: MySQL per i database da esso gestiti)
- Driver API: sistema che prevede la traduzione dei comandi per la Connectivity in richieste provenienti dal Database Manager.
Nel caso si utilizzi un driver bridge esso dovrà interagire con un’ODBC funzionante all’interno del file system del server; per rendere questo possibile, nei sistemi Windows andiamo su:
Pannello di Controllo
Strumenti di amministrazione
Origine dati ODBC
Quindi selezioniamo il tipo di DB a cui desideriamo connettere le nostre JSP; confermiamo la scelta effettuata con "aggiungi" e scegliamo la tipologia di file del DB selezionato; clicchiamo su fine e terminiamo la nostra istallazione del driver ODBC.
L’interazione tra le JSP e i dati contenuti nei database avviene come nella maggior parte dei linguaggi di scripting server side con alcune particolarità sintattiche proprie di questa architettura.
Innanzitutto avremo la fase di connessione che potrà anche essere assegnata come valore ad una variabile:
connessione = DriverManager.getConnection
("jdbc:mysql://path/db","u","p");
(da scrivere su di una sola riga).
Come si nota dalla stringa proposta, abbiamo assegnato quale valore alla variabile "connessione" il risultato dell’azione svolta dalla funzione DriverManager.getConnection sui seguenti parametri: il driver necessario per la tipologia di DBMS (nel nostro caso MySQL); il percorso al database; la user e la parola chiave necessarie per l’autenticazione dell’utente.
A questo punto entrano in gioco i noti comandi SQL, supponiamo per esempio di voler operare una SELECT sui dati di una determinata tabella "tb" corrispondenti ad un certo parametro; innanzitutto passeremo il parametro "par" alla funzione request.getParameter:
par = request.getParameter("par");
Fatto questo potremo avviare la query (osservate come in valori vengono concatenati dall’operatore "+"):
connessione.prepareStatement
("SELECT * FROM tb WHERE dato = '" + par + "'");
(da scrivere su di una sola riga).
I risultati dei comandi SQL potranno quindi essere eseguiti passandoli come parametri ad una funzione come sql.executeQuery().
Riportiamo di seguito un semplice esempio di connessione ad un database con inserimento di dati:
<%@ page language="java" import="java.sql.*" %>
<%
int var = 100;
int result;
Connection connessione = null;
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connessione = DriverManager.getConnection
("jdbc:odbc:nome_db","usr","pwr");
stat = connessione.createStatement();
result = stat.executeUpdate
("INSERT INTO tab (campo) values ("+var+")"));
connessione.close();
%>
La stringa:
<%@ page language="java" import="java.sql.*" %>
Permette l’importazione del package java.sql.*senza il quale attraverso le JSP non potremo eseguire comandi SQL.
Di seguito vengono assegnati i valori alle variabili e caricata la Class del driver:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Avviene la connessione tra pagina e DB:
connessione = DriverManager.getConnection
("jdbc:odbc:nome_db","usr","pwr");
Viene creato lo Statement, cioè un oggetto utilizzato per l’invio di richieste e comandi al DB:
stat = connessione.createStatement();
Finalmente viene eseguita la query d’inserimento:
result = stat.executeUpdate
("INSERT INTO tab (campo) values ("+var+")"));
(da scrivere su di una sola riga).
Infine viene chiusa la connessione:
connessione.close();