SERVLET & JSP DISPENSE PROGRAMMAZIONE LATO SERVER Un server deve rispondere alle richieste del client e permettere di visualizzare le pagine Web. Questo compito è svolto da un software ben definito, il Web server. Quando si invia ad un Web server la richiesta di una pagina statica (ad esempio index.html) questo: • Riconosce la richiesta. • Cerca e, se presente, trova la pagina nel computer server. • Invia la pagina al browser client che la visualizzerà. Il Web server, quindi, non ha una logica di controllo; non è in grado di garantire alcuna interattività con il visitatore tranne quella di fornire pagine web da visualizzare. Ma se volessimo interagire con l’utente, rispondere dinamicamente, memorizzare dati in database, eseguire quindi genericamente algoritmi un Web server propriamente detto non è più sufficiente. Avremo bisogno di inserire della logica dietro alle semplici pagine HTML, degli algoritmi che ci permettano, ad esempio, di effettuare dei calcoli o tenere a memoria dei valori. Questo è permesso dagli Application server su cui possiamo creare delle Web Application Visualizzando semplicemente la pagina di un sito non è semplice distinguere apriori delle pagine generate da un server “statico” da quelle generate da una Web application. Questo perchè in entrambi casi ci troviamo difronte pagine html. La differenza sta nell’origine di quelle pagine. Nel primo caso le pagine sono file statici (file .html) che vengono semplicemente prelevati dal server e visualizzati nel browser. Nel caso di Web application, invece, le pagine vengono costruite dinamicamente al tempo della chiamata da un programma che gira sul server e che può essere scritto in qualsiasi linguaggio. Nel caso quindi di Web Application, quando si richiedere una pagina (è riduttivo ora parlare di pagine), viene eseguito prima l'algoritmo che c'è dietro, poi visualizzato il risultato. In genere un'applicazione web si sviluppa su tre livelli: 1. Livello di presentazione: rappresenta l’interfaccia utente dell’applicazione e si occupa di acquisire dati e visualizzare risultati. 2. Livello intermedio: si occupa delle elaborazioni dei dati; di eseguire la parte algoritmica e generare i risultati poi visualizzati dal precedente livello. 3. Livello dati: memorizzazione e gestione dei dati, come per esempio un database. Per l'esecuzione di questi programmi quindi non serve un semplice Web Server ma è necessario il supporto di un Application Server. Questo, a differenza del Web server, non si limita a rispondere alla richiesta dell’utente con la pagina HTML ma è capace di eseguire degli algoritmi per fare calcoli, ricerche, memorizzare, ecc. Grazie ad esso possiamo: • affiancare alle normali pagine HTML statiche delle pagine dinamiche che cambieranno il loro aspetto ed il loro contenuto in base a dei parametri che saremo noi a decidere. • inserire lato server dei veri e propri algoritmi che ricevano dalle pagine Web delle informazioni, effettuino le opportune elaborazioni e restituiscano i risultati ad altre pagine Web per la visualizzazione. In base al linguaggio con cui si vuole programmare e creare i programmi lato server, bisogna scegliere un opportuno Application Server che lo supporti. Nel caso di Java l'Application Server più diffuso è Tomcat, che è open source ed è usato per quasi il 70% dei server della rete mondiale . Ci sono poi altri Application Server rivolti ad una nicchia di clienti di fascia alta, grosse aziende o grandi organizzazioni: • JBoss, un altro AS open source • WebSphere, l’AS di casa IBM che vanta innumerevoli estensioni. • WebLogic, la proposta di BEA, una software house americana specializzata in soluzioni enterprise. • Oracle, la piattaforma per la gestione di enormi quantitativi di dati che include anche un ottimo Application server. Ritornando a Tomcat, volendo esser pignoli, è un Servlet Container ed un JSP Engine. Un motore quindi in grado di eseguire lato server applicazioni Web basate sulla tecnologia J2EE e costituite da componenti Servlet e da pagine JSP. In genere Tomcat è utilizzato insieme al Web server Apache: la sezione statica è gestire con Apache, quella dinamica con Tomcat. Nello sviluppo di applicazioni Web molto semplici è inutile utilizzare entrambi gli strumenti, visto che Tomcat si comporta benissimo anche da Web server. LE SERVLET Una Servlet è emplicemente, un programma scritto in Java e residente su un server, in grado di gestire le richieste generate da uno o più client, attraverso uno scambio di messaggi tra il server ed i client stessi che hanno effettuato la richiesta. Girano all'interno di un Application Server e possono essere considerate delle classi (quindi dei programmi) che estendono le funzionalità del server. Quindi le Servlet sono classi Java e possono avvalersi interamente di tutte le librerie Java viste; bisogna però sottolineare il fatto che le Servlet, a differenza degli Applet, non hanno delle GUI (interfacce grafiche) associate direttamente ad esse. Pertanto, le librerie AWT e Swing non verranno mai utilizzate direttamente quando si desidera implementare una Servlet. Il flusso di una Servlet Vediamo come lavora una Servlet: 1. Un client invia una richiesta (request) per una servlet ad un web application server. 2. Qualora si tratti della prima richiesta, il server istanzia e carica la servlet in questione avviando un thread che gestisca la comunicazione con la servlet stessa. Nel caso, invece, in cui la Servlet sia già stata caricata in precedenza (il che, normalmente, presuppone che un altro client abbia effettuato una richiesta antecedente quella attuale) allora verrà, più semplicemente, creato un ulteriore thread che sarà associato al nuovo client, senza la necessità di ricaricare ancora la Servlet. 3. Il server invia alla servlet la richiesta pervenutagli dal client 4. La servlet costruisce ed imposta la risposta (response) e la inoltra al server 5. Il server invia la risposta al client. Il contenuto della risposta non è necessariamente calcolato da un unico algoritmo contenuto tutto all’interno della Servlet invocata (questo può essere, semmai, il caso di applicazioni molto elementari) ma, anzi, è spesso legato ad interazioni della Servlet stessa con altre sorgenti di dati (data source) rappresentate, ad esempio, da Data Base, file di risorsa e, non di rado, altre Servlet. La Classe HttpServlet Tutte le servlet devono implementare l'interfaccia Servlet, i cui metodi sono invocati automaticamente dall'Application Server. public interface Servlet { public void init(ServletConfig config) throws ServletException; public ServletConfig getServletConfig(); public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; public String getServletInfo(); public void destroy(); } In particolare le Servlet che tratteremo dovranno estendere la classe astratta HttpServlet (del package javax.servlet.http) che implementa appunto questa interfaccia. Vediamo i metodi dell'interfaccia a cosa si riferiscono: 1. void init( ServletConfig config ): inizializza la servlet una volta sola durante il ciclo di esecuzione della servlet; 2. ServletConfig getServletConfig( ): ritorna un oggetto che implementa l'interfaccia ServletConfig e fornisce l'accesso alle informazioni sulla configurazione della servlet, tra cui i parametri di inizializzazione e il ServletContext, ovvero il suo ambiente (il servlet engine in cui vengono eseguite); 3. String getServletInfo( ): viene definito in modo da restituire una stringa con informazioni quali autore e versione; 4. void service(ServletRequest request, ServletResponse response): viene mandato in esecuzione in risposta alla richiesta mandata da un client alla servlet; 5. void destroy( ): invocato quando la servlet viene terminata; usato per rilasciare le risorse (connessioni a basi di dati, file aperti, etc). Non ha nulla a che fare con il browser. I metodi su cui porremo attenzione sono init, service, destroy. Il metodo init viene invocato solo quando la servlet viene caricata in memoria, di solito a seguito della prima richiesta per quella servlet. Solo dopo che il metodo è stato eseguito, il server può soddisfare la richiesta del client invocando il metodo service, che riceve la richiesta, la elabora e prepara la risposta per il client. Quindi il metodo service viene richiamato ogni volta che si riceve una richiesta. Tipicamente, per ogni nuova richiesta il servlet engine crea una nuova thread di esecuzione in cui viene mandato in esecuzione service. Solo quando il servlet engine termina la servlet, viene invocato il metodo destroy per rilasciare le risorse della servlet. Quindi di fatto, il codice del programma (o ovviamente il codice da cui partire che poi chiama altre classi), va inserito in service in quanto è il metodo che viene chiamato ogni volta che un client contatta il server (il metodo init viene chiamato solo quando la servlet viene avviata la prima volta, ovvero quando è contattata dal primo client). HttpServletRequest e HttpServletResponse Il metodo più significativo in una servlet è quindi il metodo service, che prende in ingresso: • un oggetto ServletRequest, corrispondente ad uno stream di ingresso, da cui leggere la richiesta del client; • un oggetto ServletResponse, corrispondente ad uno stream di uscita, su cui scrivere la risposta. Nella classe HttpServlet, il metodo service() viene sovrascritto ed i parametri che utilizza sono del tipo specifico: • HttpServletRequest request: che rende accessibili i dati relativi alla richiesta inoltrata dal client; • HttpServletResponse response: in cui inserire la risposta da passare al client. Quindi sono i parametri tramite i quali posso gestire il flusso client-server di cui parlavamo in precedenza: ho una richiesta (request, inviata dal client verso il server) ed una coseguente risposta (response, inviata dal server verso il client). In particolare sugli oggetti di questo tipo abbiamo a disposizione diversi metodi per appunto leggere informazioni sulla richiesta del client e per scrivere informazioni da ritornare come risposta. Metodi dell'interfaccia HttpServletRequest: • String getParameter(String name): torna il valore del parametro name passato nella get/post; • Enumeration getParameterNames( ): parametri nella post; • String[] getParameterValues(String name): se name ha valori multipli • Cookie[] getCookies( ): memorizzati dal server nel client; • HttpSession getSession(boolean create): se l'oggetto non esiste e create = true, allora lo crea. • Metodi dell'interfaccia HttpServletResponse: • void addCookie( Cookie cookie ): nell'header della risposta passata al client; essa viene memorizzata a seconda dell'età massima e dell'abilitazione o meno ai cookie disposta nel client; • ServletOutputStream getOutputStream( ): stream basato su byte per dati binari; • PrintWriter getWriter( ): stream basato su caratteri per dati testuali; • void setContentType(String type): specifica il formato MIME. In particolare ci interesseranno i metodi getParameter(String name) per ricavare gli eventuali parametri passati dal client nella sua richiesta e getWriter() per ottenere lo stream su cui scrivere la risposta. Servlet Context Un’altra importante interfaccia messa a disposizione dal Servlet engine è la javax.servlet.ServletContext. Attraverso di essa è possibile trovare un riferimento al contesto (context) di un’applicazione, ovvero ad una serie di informazioni a livello globale condivise tra i vari componenti che costituiscono l’applicazione stessa. L'HttpServlet possiede il metodo getServletContext che ritorna appunto il riferimento al contesto della Servlet. Tra i vari metodi a disposizione sull'oggetto context ottenuto abbiamo per esempio getRealPath( String virtualPath) a cui posso passare come parametro un path virtuale e che ritorna la stringa contenente il Path reale corrispondente (utilizzabile per esempio per creare file nel contesto dell'applicazione web). Scrivere una Servlet Creare una Servlet vuol dire, in termini pratici, definire una classe che estende la classe HttpServlet e fare l'override dei metodi che ci interessano. In precedenza abbiamo detto che principalmente ci interesserà principalmente il metodo service ( ); in realtà Java può differenziare le richieste di tipo GET e quelle di tipo POST ed eseguire di conseguenza il metodo appropiato tra i seguenti due (metodi propri della classe HttpServlet): • void doGet(HttpServletRequest req, HttpServletResponse resp) Gestisce le richieste HTTP di tipo GET. Viene invocato da service() • void doPost(HttpServletRequest req, HttpServletResponse resp) Gestisce le richieste HTTP di tipo POST. Viene invocato da service() In particolare, se non sovrascriviamo il metodo service( ) questo, in base al tipo di richiesta che ha avuto dal client, chiamerà automaticamente doGet o doPost passandogli la request e la response. Quindi sono questi i metodi che veramente dobbiamo andare a sovrascrivere ed in cui dobbiamo definire il codice dell'algoritmo (nulla ci vieta di fare l'override di service e scrivere lì in codice se non ci interessa la differenzazione tra Get e Post). All'interno del mio codice potrò prendere eventuali parametri inclusi nella richiesta tramite il metodo getParameter sull'oggetto HttpServletRequest: . . . //prendo il valore del parametro nome String name = request.getParameter("nome"); . . . Oppure scrivere una risposta inserendola nell'oggetto HttpServletResponse: . . . //indico che il contenuto della mia risposta sarà del codice HTML response.setContentType("text/html;charset=UTF­8"); //scrivo il codice PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>La Mia Prima Servlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>La mia servlet</h1>"); out.println("</body>"); out.println("</html>"); . . . Tale classe va compilata ed il file class posizionato all'interno della cartella della Web Application. Se per esempio il nome della classe è MyServlet (e quindi avrò il file MyServlet.class) nella Web Application, posso accedere alla servlet indicando nel browser l'indirizzo del suo path: miosito.it/myapplication/MyServlet. Il browser ci mostrerà il contenuto dell'HttpServletResponse che abbiamo tra l'altro indicato essere codice HTML. Primi Esempi Semplice Stampa: import java.io.IOException; import java.io.PrintWriter; import javax.servlet.http.*; public class NewServlet1 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF­8"); PrintWriter out = response.getWriter(); try { out.println("<html>"); out.println("<head>"); out.println("<title>La Mia Prima Servlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Questa è un Servlet</h1>"); out.println("</body>"); out.println("</html>"); } finally { out.close(); } } } Prendere Parametri col Get / Post import java.io.IOException; import java.io.PrintWriter; import javax.servlet.http.*; public class NewServlet1 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("nome"); response.setContentType("text/html;charset=UTF­8"); PrintWriter out = response.getWriter(); try { out.println("<html>"); out.println("<head>"); out.println("<title>La Mia Prima Servlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Nome: " + name + "</h1>"); out.println("</body>"); out.println("</html>"); } finally { out.close(); } } } Pagina HTML che richiama la Servlet (con il get): <html> <head> <meta http­equiv="Content­Type" content="text/html; charset=UTF­8"> <title>La mia pagina</title> </head> <body> <h1>Prova 1</h1> <form action="NewServlet1" metod="get"> Inserisci il nome: <input type="text" name="nome"><br> <input type="submit" value="Invia"> </form> </body> </html> Analizziamo il codice: • Creiamo una classe "NewServlet1" che estende la classe HttpServlet che implementa a sua volta l'interfaccia Servlet • Non sovrascriviamo il metodo service ( ) ma i due metodi doGet e doPost • In particolare, non esigendo un comportamento diverso per ognuno di essi, mettiamo le operazioni in un metodo a parte processRequest che definiamo noi e che facciamo chiamare sia a doGet che a doPost. • Nel nostro codice con il metodo setContentType stabiliamo il tipo MIME della pagina di risposta. In questo caso e' HTML • Il metodo getWriter è un modo per restituire dati all'utente, in particolare getWriter ritorna un writer, cioè un outputstream con il quale sarà possibile ritornare la pagina di risposta al client. Chiamiamo questo metodo sul parametro HttpServletResponse che rappresenta i dati che verranno restiuiti al client. • Nel caso in cui prevediamo la lettura di parametri in input, utilizzaiamo HttpServletRequest. In particolare utilizziamo il metodo getParameter( .. ) in cui indichiamo il nome del parametro che ci interessa e di restuisce il valore che gli è stato associato dal client. I vantaggi delle Servlet Efficienza. Le servlet vengono istanziate e caricate una volta soltanto, alla prima invocazione. Tutte le successive chiamate da parte di nuovi client vengono gestite creando dei nuovi thread che si prendono carico del processo di comunicazione (un thread per ogni client) fino al termine delle rispettive sessioni. Portabilità: Grazie alla tecnologia Java, le servlet possono essere facilmente programmate e “portate” da una piattaforma ad un’altra senza particolari problemi. Persistenza: Dopo il caricamento, una servlet rimane in memoria mantenendo intatte determinate informazioni (come la connessione ad un data base) anche alle successive richieste. Gestione delle sessioni: Il protocollo HTTP è un protocollo stateless (senza stati) e, pertanto non in grado di ricordare i dettagli delle precedenti richieste provenienti da uno stesso client. Le servlet sono in grado di superare questa limitazione. JSP : JAVA SERVER PAGE Nella visione di una Web Application in cui la parte di visualizzazzione dei dati è separata da quella di elaborazione dei dati, le pagine JSP si occupano della visualizzazzione offrendo però strumenti per renderla dinamica. Di fatto una pagina JSP è una pagina di testo formata da: • un template statico, espresso in un qualsiasi formato testuale (HTML, SVG, WML, XML, ...) • istruzioni Java Quando un client richiede al server una pagina JSP, il server elabora le istruzioni Java producendo l'opportuno output; quel che alla fine il client ottiene è una pagina statica contenente solo codice HTML (o simili). Come per le Servlet quindi è il server che esegue il codice Java, al client non arriverà null'altro che una pagina HTML. Architettura di una pagina JSP Come già detto quindi una pagina JSP (quindi con estensione .jsp) è una pagina HTML con codice Java immerso all'interno dei tags HTML con i quali convive ed interagisce; tale codice vene eseguito dal server ed all'utente arriva quindi una pagina interamente HTML. Volendo andare nello specifico, al momento dell'invocazione di una pagina ".jsp" si succederanno le fasi seguenti: 1. Chiamata di una pagina ".jsp" tramite browser. 2. Raccolta della chiamata da parte del Web server. 3. Il Web server "vede" la pagina ".jsp", la riconosce e la consegna nelle mani dell'Engine JSP, ad esempio Tomcat. 4. La pagina ".jsp" viene processata una prima volta. 5. Il file ".jsp" viene tradotto in una classe Java e compilato in una Servlet. 6. 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. 7. La richiesta effettuata attraverso la chiamata viene soddisfatta sotto forma di un output costituito da una pagina recante solo codice HTML prodotto però dinamicamente. Tutto questo processo sarà però nascosto al programmatore che invece si deve limitare a scrivere una pagina HTML con all'interno codice Java (racchiuso in determinati identificatori) Un primo esempio Prima di tutto bisogna dire che i file per essere riconosciuti dal server come pagine JSP devono essere salvati con estensione .jsp. Iniziamo con il classico messaggio “Ciao Mondo!” da stampare a video. <html> <body> <% out.println("Ciao Mondo!"); %> </body> </html Come avevamo detto è una normale pagine HTML con la differenza che c'è una porzione di codice Java immersa al suo interno. Come si evince dall'esempio il codice Java della pagina è stato isolato tra i delimitatori <% e %> Ricordando quanto detto prima, sappiamo che la prima volta che si effettua la richiesta del file, quest’ultimo viene compilato, creando una servlet, che sarà archiviata in memoria (per servire le richieste successive); solo dopo questi passaggi viene elaborata la pagina HTML che viene mandata al browser. Ad ogni richiesta successiva alla prima il server controlla se sulla pagina .jsp è stata effettuata qualche modifica, in caso negativo richiama la servlet già compilata, altrimenti si occupa di eseguire nuovamente la compilazione e memorizzare la nuova servlet. L'architettura delle JSP risulta quindi abbastanza semplice; però oltre ai semplici delimitatori appena visti, è possibile utilizzare varie componenti che necessitano di essere analizzate. In particolare vedremo: 1. Le Dichiarazioni 2. Le Espressioni 3. Le Scriptlet 4. Le Direttive 5. Le Actions o Standard Actions Le Dichiarazioni La sintassi per le dichiarazioni è la seguente: <%! dichiarazione %> In pratica si aggiunge il punto esclamativo dopo il primo delimitatore. Viene utilizzata questa sintassi sia per la dichiarazioni di variabili, sia per la dichiarazione di metodi. Questi (variabili e metodi) diventano membri della classe ottenuta dalla traduzione della JSP; quindi saranno in comune tra tutti i client che utilizzano la servlet ricavata dalla traduzione. Se un client accede ad una pagina jsp che prevede l'incremento di una variabile dichiarata in questo modo, il client che accede successivamente troverà quella variabile incrementata. Inoltre i metodi e le variabili dichiarate nelle dichiarazioni JSP vengono inizializzate nel momento in cui la JSP viene inizializzata e possono essere usate da tutti gli scriptlet e le espressioni all'interno di quella JSP. Le Espressioni La sintassi per le espressioni è la seguente: <%= espressione %> In pratica si aggiunge l'uguale dopo il primo delimitatore. Viene valutata l'espressione e stampato l'output (in pratica l'intero codice nella pagina HTML finale verrà sostituito dalla stringa contenente il risultato dell'espressione). Esempi: Consideriamo di avere un metodo somma: <%= somma (2,3)%> Messa all'interno di una JSP produrrà la stringa “5” nella posizione in cui è scritta; all'interno dell'HTML definitivo vedremo quindi la stringa “5”. In genere sono utili per utilizzare a volo il risultato di metodi (magari di oggetti di sistema): <%= request.getRemoteHost() %> In questo caso sfrutta l'oggetto request per richiedere il nome di Host del server. Le Scriplet La sintassi è la seguente: <% codice java %> Le Scriptlet sono frammenti di codice java che dovranno essere eseguiti. Vanno a riscrivere in pratica le cose all'interno del metodo service; possono anche essere convertite in nulla che io vedo direttamente ma eseguire semplicemente righe di codice dell'algoritmo. Posso metterci in esso qualsiasi istruzione Java. Se poi voglio stampare qualcosa (che quindi andrà inserita nella pagina HTML prodotta), utilizzo il metodo out.println( …. ). Esempio: <% java.util.Date data_di_oggi = new java.util.Date(); out.println( String.valueOf( data_di_oggi )); %> Le Direttive La sintassi è la seguente: <%@ directive {attributo="value"}* %> Le Direttive non producono output ma mettono a disposizione definizioni, notifiche e informazioni valide e disponibili in tutto il documento ".jsp". Abbiamo 3 tipologie di direttive: Direttiva page: Specifica le impostazioni della pagina. Attributi possibili: • language: specifica il linguaggio da utilizzare in fase di compilazione (es: language="Java"); • import: specifica quali package dovranno venire inclusi nella pagina, (es: import="java.util.*"); • isThreadSafe: indica se la pagina può servire più richieste contemporaneamente; (es: istreadSafe = "true"); • info: contiene delle informazioni riguardanti la pagina, consultabili grazie al metodo Servlet.getServletInfo (es: info="Prima prova"); • errorPage e isErrorPage: entrambi riguardanti la gestione delle pagine di errore; Vi possono essere diverse occorrenze di page, ma una sola occorrenza per attributo, eccetto l'import Direttiva include: Include contenuti da altre risorse (possono per esempio essere file HTML semplici file di testo); tali contenuti verranno poi tradotti come fossero originariamente nelle JSP. Unico attributo: • file: indica il file con i contenuti da caricare Direttiva taglib: Permette di utilizzare una libreria di tag personalizzati (custom tag libraries). Attributi: • uri (del file descrittore della libreria); • tagPrefix (esclusi: jsp, jspx, java, javax, servlet, sun, sunw); Le Actions Un altro importante componente delle JSP è dato dalle azioni standard. Sintassi: <jsp:action>. Azioni possibili: • <jsp:include> permette di includere risorse aggiuntive di tipo sia statico che dinamico. Il risultato è quindi quello di visualizzare la risorsa, oltre alle informazioni già inviate al client. Sintassi: <jsp:include page="URLRisorsa" flush="true | false" /> Parametri: • page: URL della risorsa fa includere (parte della stessa applicazione Web); • flush: indica se il buffer deve essere svuotato o meno (deve sempre essere true in JSP 1.1); • <jsp:forward>: inoltra la richiesta a un'altra JSP, servlet o pagina statica; fa terminare l'esecuzione della JSP corrente. Sintassi: <jsp:forward page="URLRisorsa"/> • <jsp:plugin>: permette di aggiungere ad una pagina un componente plug-in, sotto forma di un elemento HTML object o embed specifico di quel browser. Nel caso si tratti di un applet Java, l'azione provoca lo scaricamento del plug-in Java, se non è già installato sul client. • <jsp:param>: permette di dichiarare ed inizializzare dei parametri all'interno della pagina, utilizzabili in include, forward e plugin. Sintassi: <jsp:params> <jsp:param name="nomeParametro" value="valore"> </jsp:params> Dove: – name: nome del parametro dichiarato (se il nome esiste già, il valore viene aggiornato); – value: valore del parametro appena dichiarato. Tutti i valori di ogni parametro vengono ottenuti applicando il metodo getParameterValues sull'oggetto implicito request, e ottenendo come valore di ritorno, un array di stringhe. Gli Oggetti Impliciti Sono oggetti automaticamente disponibili ed utilizzabili in una servlet. Vediamo quali sono: Request: E' lo stesso request visto per le Servlet: incapsula le informazioni sulla richiesta del client e le rende disponibili attraverso alcuni suoi metodi. Il metodo più utilizzato è il getParameter(“nomeParametro”), che restituisce una stringa con il valore del parametro specificato. Altri metodi a disposizione sono: – getCookies() che restituisce un array di cookies; – getAttributeNames() restituisce una variabile di tipo Enumeration contenente i nomi di tutti gli attributi coinvolti nella richiesta. – getContentLength() restituisce un intero che corrisponde alla lunghezza in byte dei dati richiesti. – getContentType() restituisce il tipo MINE della richiesta, cioè il tipo di codifica dei dati. – getInputStream() restituisce un flusso di byte che corrisponde ai dati binari della richiesta. Particolarmente utile per funzioni di upload di file da client a server. – getParameter(String) restituisce una tringa con il valore del parametro richiesto. – getParameterNames() restituisce una variabile di tipo Enumeration contente i nomi dei parametri della richiesta. – getParameterValues(String) restituisce un array contenente tutti i valori del parametro specificato (nel caso ci siano più parametri con lo stesso nome). – getProtocol() corrisponde alla variabile CGI SERVER_PROTOCOL. Rappresenta il protocollo e la versione della richiesta. – getremoteHost() corrisponde alla variabile CGI REMOTE_HOST. – getServerName() corrisponde alla variabile CGI SERVER_NAME e restituisce l’indirizzo IP del server – getServerPort() corrisponde alla variabile CGI SERVER_PORT, la porta alla quale in server è in ascolto. – getremoteAddr() corrisponde alla variabile CGI REMOTE_ADDR. Restituisce in pratica l’indirizzo IP del visitatore. – getremoteUser() come per REMOTE_USER restituisce lo username della macchina richiedente – getMethod() come per la variabile CGI REQUEST_METHOD e restituisce GET o POST. – getPathInfo() restituisce informazioni extra sul path, corrisponde alla varibile CGI PATH_INFO – getQueryString() restituisce una stringa contenete l’intera querySting (tutti i caratteri dopo il punto di domanda), come per la variabile CGI QUERY_StrING. – request.getServletPath() restituisce il percorso relativo della pagina jsp Esempio: <% String n = getParameter(“nome”); %> Response: E' lo stesso response visto per le Servlet: fornisce tutti gli strumenti per inviare i risultati dell’esecuzione della pagina jsp. Metodi a disposizione: – setBuffersize(int) imposta la dimensione in byte del buffer per il corpo della risposta, escuse quindi le intestazioni. – setContentType(“tipo”) imposta il tipo MINE per la risposta al client. – flushBuffer() forza l’invio dei dati contenuti nel buffer al client. Out: Questo oggetto ha principalmente funzionalità di stampa di contenuti. Con il metodo print(oggetto/variabile) è possibile stampare qualsiasi tipo di dato. Config: Permette di gestire tramite i suoi metodi lo startup del servlet associato alla pagina JSP, di accedere quindi a parametri di inizializzazione e di ottenere riferimenti e informazioni sul contesto di esecuzione del servlet stesso. Exception: Questo oggetto è accessibile solo dalle pagine di errore (dove la direttiva isErrorPage è impostata a true). Contiene le informazioni relative all’eccezione sollevata in una pagina in cui il file è stato specificato come pagina di errore. Il metodo principale è getMessage() che restituisce una stringa con la descrizione dell’errore. I JAVA BEANS I Java Beans sono componenti software contenenti una classe Java, che possono venire inclusi in una pagina JSP, permettendo quindi un ottimo incapsulamento del codice, peraltro riutilizzabile. Al programmatore quindi sarà pressochè invisibile la sezione di codice puro, sostituito da richiami ai metodi delle classi incluse. Posso quindi scrivere una classe, compilarla ed includerla nella Web Application. All'interno delle pagine JSP posso poi utilizzare oggetti di questa classe tramite i suoi metodi. Per essere utilizzati essi devono essere semplicemente "integrati" nelle JSP, dopo di chè sarà possibile sfruttarne tutti i metodi. Ogni classe Java può essere un JavaBean, purché soddisfi alcuni requisiti in merito ai nomi, alla costruzione e al comportamento dei metodi. Queste convenzioni rendono possibile avere tool che possono usare, riusare, sostituire e connettere JavaBeans. Le convenzioni richieste sono: • La classe deve avere un costruttore senza argomenti • I suoi attributi devono avere setter e getter (e vari metodi standard) che rispettano le convezioni dei nomi; • Non dovrebbe contenere alcun metodo richiesto per la gestione degli eventi. Utilizzo dei Java Beans: Esistono tre azioni standard per facilitare l'integrazione dei JavaBean nelle pagine JSP: • <jsp:useBean> Permette di associare un'istanza di un JavaBean (associata ad un determinato ID) ad una variabile script dichiarata con lo stesso ID. In pratica offre la possibilità di associare la classe contenuta nel JavaBean ad un oggetto utilizzabile nel resto della pagina richiamando i metodi definiti nella classe. Sintassi: <jsp:useBean id="nomeBean" scope="session" class="Classe" /> Id: identità dell'istanza dell'oggetto nell'ambito specificato (sarà la variabile contentente l'oggetto). Scope: ambito dell'oggetto, le opzioni sono: ◦ page: gli oggetti con questo ambito sono accessibili solo all'interno della pagina in cui sono stati creati, in pratica possono venire paragonati alle variabili locali di un qualsiasi linguaggio di programmazione, vengono distrutte alla chiusura della pagina e i dati saranno persi; ◦ request: gli oggetti con questo ambito sono accessibili esclusivamente nelle pagine che elaborano la stessa richiesta di quella in cui è stato creato l'oggetto, quest'ultimo inoltre rimane nell'ambito anche se la richiesta viene inoltrata ad un'altra risorsa; ◦ session: gli oggetti definiti in quest'ambito sono accessibili solo alle pagine che elaborano richieste all'interno della stessa sessione di quella in cui l'oggetto è stato creato per poi venire rilasciati alla chiusura della sessione a cui si riferiscono, in pratica restano visibili in tutte le pagine aperte nella stessa istanza (finestra) del Browser, fino alla sua chiusura. Solitamente i bean istanziati in questo modo vengono utilizzati per mantere le informazioni di un utente di un sito; ◦ application: gli oggetti definiti in quest'ambito sono accessibili alle pagine che elaborano richieste relative alla stessa applicazione, in pratica sono validi dalla prima richieta di una pagina al server fino al suo shotdown. Class: nome della classe di cui voglio instanziare l'oggetto, deve ovviamente coincidere con il nome del file .class (senza estensione). • <jsp:setProperty> Permette di impostare il valore di una delle proprietà di un bean. Attributi: ◦ name: nome dell'istanza di bean definita in un'azione <jsp:useBean> ◦ property: rappresenta la proprietà di cui impostare il valore ◦ param: nome del parametro di richiesta il cui valore si vuole impostare ◦ value: valore assegnato alla proprietà specificata Richiama in pratica il setter sull'attributo indicato della classe. Esempio: <jsp:setProperty name="nome_bean" property="prop" param="nome_parametro" /> Permette di assegnare il valore del parametro nome_parametro alla proprietà prop del bean di nome nome_bean. • <jsp:getProperty> Prende il valore di una proprietà di una data istanza di bean e lo inserisce nell'oggetto out implicito (in pratica lo stampa a video). Attributi: ◦ name: nome dell'istanza di bean da cui proviene la proprietà definita da un'azione <jsp:useBean> ◦ property: rappresenta la proprietà del bean di cui si vuole ottenere il valore Richiama in pratica il getter sull'attributo indicato della classe. Un Esempio di Java Bean Un semplice esempio di bean, realizzato per contenere le informazioni di un utente durante la sua permanenza nel sito. public class InfoUtente { private String nome = null; private String email = null; private int pagineViste; public InfoUtente() { pagineViste=0; } public aggiornaPV() { pagineViste++; } public int getPagineViste(){ return pagineViste; } public void setNome(String value) { nome = value; } public String getNome() { return nome; } public void setEmail(String value) { email = value; } public String getEmail() { return email; } public String riassunto(){ String riassunto = null; riassunto = "Il nome dell'utente è"+nome+","; riassunto+= "il suo indirizzo e­mail è: "+email; riassunto+= " e ha visitato "+pagineViste+" del sito"; return riassunto; } } Questo bean contiene il nome dell’utente ed i metodi per modificarlo e restituirlo, il suo indirizzo e-mail con i relativi metodi, il numero di pagine viste dall’utente e un metodo che restituisce un riassunto schematico dei dati dell’utente. Vediamo come utilizzarlo. Creazione un’istanza del bean InfoUtente con ambito session: <html> <head><title>Utilizzo del Bean</title></head> <body> <jsp:useBean id="utente" scope="session" class="InfoUtente"/> Le proprietà del bean possono essere impostate con l’azione setProperty o agendo direttamente con i metodi creati appositamente. <jsp:setProperty name="utente" property="nome" value="Zina& tram"/> <% utente.setNome("Zina& tram"); utente.setEmail("[email protected]"); %> Lo stesso vale per la lettura delle proprietà: <jsp:getProperty name="utente" property="nome"/> <% out.println(utente.getNome()); out.println(utente.riassunto()); %> Per incrementare il numero di pagine viste è sufficiente richiamare il metodo aggiornaPV() e per ottenere il valore getPagineViste(): <% utente.aggiornaPV(); out.println(utente.getPagineViste()); %> ARCHITETTURA DI UNA WEB APPLICATION Abbiamo visto che nel creare una web application significa creare un programma che lavora su un server e può soddisfare le richieste di un client. In particolare le componenti di una web application nel nostro caso sono: – Servlet; – Pagine JSP (con eventuali Java Beans). In genere le Pagine JSP rappresenteranno la parte grafica dell'applicazione, ovvero quella che prende l'input e mostra l'output. Ciò non toglie che comunque posso avere porzioni di algoritmi direttamente nelle pagine (soprattutto se utilizzo Java Beans) che non si riducono ad un semplice richiamo di parametri. In linea di principio posso applicare il seguente ragionamento: se in una pagina JSP la quantità di codice Java supera notevolmente la quantità del codice HTML allora è molto probabile che necessito di una Servlet a cui devo delegare le operazioni di calcolo. Le Servlet dunque sono classi (che possono a loro volta utilizzare classi di appoggio) che vengono richiamate per svolgere operazioni e rimandano poi il risultato e la visualizzazione di esso ad una pagina JSP. Per poter far ciò è possibile utilizzare due metodi: request.getRequestDispatcher( "paginaDest.jsp" ).forward(request,response); oppure: response.sendRedirect("paginaDest.jsp?param="+value); Vediamo le differenze tra Servlet redirect e servlet forward: • Servlet redirect ricontatta il client indicandogli il nuovo indirizzo da contattare, il client allora richiama la pagina indicata ricontattando di nuovo il server. • Servle forward invece inoltra direttamente la richiesta ad un'altra servlet o pagina JSP comprendendo anche tutti i parametri e gli attributi salvati nella request (cosa che non accade con la forward). Inoltre il browser non si rende proprio conto del forward in quanto l'indirizzo nella barra degli indirizzi resta invariato.