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();