JSP = Java Server Pages by Andrea Mantoni Ultima modifica: %%mtime(%d %B %Y) = Introduzione = Le *JSP = Java Server Pages* sono una estensione dei servlet utilizzate per pagine web con ridotto contenuto dinamico. JSP può essere utilizzato come un linguaggio di scripting "(X)HTML-embedded" (~JavaScript). funzionamento: al suo primo accesso, una pagina JSP viene convertita in un servlet dal *JSP container*, quindi compilata e mandata in esecuzione come un servlet. tipi di elementi di una pagina JSP: - *template text* = codice HTML statico -> viene stampato automaticamente nel metodo "service" con "out.println" - *commenti*: <%-- JSP comment --%> OSS.: i commenti JSP non sono visibili al client, i commenti HTML sono passati al client. - *direttive* -> sono interpretate direttamente dal JPS container senza compilazione (valutate una sola volta a compile-time) <%@ direttiva attr="valore" ... %> - *azioni/actions* (valutate ogni volta a request-time) - *scriplet* = codice Java incluso _NEL_ metodo "service" <% Java Statement; ... %> - *dichiarazioni* -> codice Java incluso _FUORI_ dal metodo "service", all'interno della classe che estende Servlet (dichiarazioni di metodi/funzioni, campi privati, etc.) <%! declaration %> - *espressioni* -> Java value convertito automaticamente in 1 oggetto String e stampata come codice HTML statico nel metodo "service" <%= Java Value %> - *azioni standard* -> tags XML estesi automaticamente in codice Java - *custom tags / tag personalizzati* ... OSS.: per le dichiarazioni la posizione nella pagina NON è rilevante, mentre per gli scriplet e le espressioni lo è. Ad es. una espressione può accedere ad un campo privato anche prima di averlo dichiarato ma non può accedere ad una variabile locale di "service" prima della sua dichiarazione. Per migliorare la separazione tra *content vs. presentation*, è consigliabile evitare di mischiare codice Java e codice (X)HTML. Sono possibili varie soluzioni, una l'evoluzione dell'altra: - develop separate utility classes and invoke them in JSP pages -> mediante la direttiva "page import" - JavaBeans, manipolati mediante le azioni standard - custom tags - *MVC = Model View Controller* architecture: un servlet analizza la request e compila un bean (il "model") contenente tutti i dati della risposta che salva. Quindi forwarda la request ad una pagina JSP, che si limita a visualizzare i dati della response (il "view"). REGOLE CHIAVE: Il servlet NON effettua alcun output sulla response. Le pagine JSP NON modificano i beans. -> può essere implementato mediante un framework (ad es. Apache Struts) == XML syntax == E' un'alternativa alla sintassi "classica" usata per generare documenti totalmente XML-compilant: template text ... ... ... ... Per evidenziare le pagine scritte con questa sintassi si usa l'estensione dei file ".jspx". == JSP 2.0 EL=Expression Language == E' una sintassi semplificata per le azioni JSP introdotta in JSP 2.0: { expression } "expression" può essere: - una variabile di pagina, della request, della sessione, o del ServletContext (ricercata in that order) - un campo privato di un bean (senza bisogno di importarlo prima!) - uno dei seguenti implicit objects: -> accessibili anche come collections pageContext pageContext.request pageContext.request.method pageContext.request.contextPath pageContext.request.pathInfo pageContext.request.pathTranslated pageContext.request.queryString pageContext.request.requestURI pageContext.request.contentLength pageContext.request.contentType pageContext.response pageContext.session pageContext.session.maxInactiveInterval pageContext.session.id pageContext.session.new pageContext.session.creationTime pageContext.session.lastAccessedTime pageContext.out pageContext.exception pageContext.exception.message pageContext.exception.stackTrace ... -> cercare elenco completo pageScope requestScope sessionScope applicationScope param -> parametri della request paramValues header headerValues cookie initParam "expression" può contenere diversi operatori: ... (gli stessi del C) empty -> test !=null & !="" == -> anche per il confronto tra stringhe not and or eq ne lt gt le ge div mod instanceof e costanti: true|false 'stringa' ... Consente l'uso di variabili Java all'interno dei tag HTML (standard e non), altrimenti impossibile. esempi: ${customer.firstName} ${customerNames[0]} ${stateCapitals["maryland"]} ${pageContext.session.id} ${param.custID} ${header.Accept} ${header["Accept"]} <%-- equivalente al precedente --%> ${cookie.userCookie.value} ${cookie["userCookie"].value} ${initParam.defaultColor} ${sessionScope.username} Nelle pagine JSP in cui si usa è bene specificare la direttiva: <%@ page isELIgnored="false" %> = Direttive = sintassi generale: <%@ directive attribute="value" ... %> <%@ directive attribute1="value1" attribute2="value2" attribute3="value3" ... attributeN="valueN" %> sono di 3 tipi principali: - *page*, con vari attributi possibili: <%@ page import="package.class1,package.class2,..." %> (default: java.lang.*, javax.servlet.*, javax.servlet.jsp.*, javax.servlet.http.*) -> ~= Java import statement OSS.: _NON è possibile accedere a classi nel package di default._ -> per poter essere accessibili, TUTTE le classi esterne devono essere incluse in un package, e quindi importate. <%@ page contentType="MIME-Type" %> (default: "text/html") <%@ page contentType="MIME-Type; charset=CharsetName" %> (default: "ISO-8859-1") <%@ page pageEncoding="CharacterSet" %> (default: "ISO-8859-1") <%@ page session="true|false" %> (default: "true") OSS.: in ogni pagina JSP, se non specificato diversamente, viene invocato automaticamente "request.getSession( true );" <%@ page isELIgnored="true|false" %> (default: "false") -> se "true" disattiva il parsing dello JSP Expression Language (EL) <%@ page buffer="sizekb|none" %> (default: >=8kb) -> La response diventa committed solo quando si sono scritti "sizekb" in essa (~"response.setBufferSize(int size);") <%@ page autoFlush="true|false" %> (default: "true") <%@ page info="Some Message" %> <%@ page errorPage="Relative URL" %> -> designa un'altra pagina (HTML o JSP) per la gestione delle eccezioni non catturate <%@ page isErrorPage="true|false" %> (default: "false") -> dichiara che la pagina corrente può gestire le eccezioni sollevate da un altra pagina per mezzo della variabile "exception" OSS.: nel caso si sollevi un eccezione non catturata nella pagina JSP, la request corrente viene forwardata _lato-server_ alla pagina designata. - *include* = importa il codice JSP di altre pagine _a compile-time_. <%@ include file="Relative URL" %> DIFFERENZA CHIAVE: la direttiva "include" importa il codice JSP, l'azione standard "include" importa solo l'output della pagina inclusa. la direttiva "include" agisce a compile-time, l'azione standard "include" agisce a request-time. - *taglib* = importa una libreria di custom tags per l'utilizzo nella pagina, e vi associa un prefisso. <%@ taglib uri="Relative URL" prefix="tagprefix" %> esempi: <%@ page pageEncoding="UTF-8"%> <%@ page session="false" %> <%@ page errorPage="error.jsp" %> <%@ include file="header.jsp" %> <%@ taglib uri="mail.tld" prefix="mail" %> = Scriplets ed espressioni = Come in Javascript, vi sono degli oggetti istanziati implicitamente (*implicit objects*): - ServletRequest request - ServletResponse response - javax.servlet.jsp.JspWriter out (il body della response) - HttpSession session (solo se la direttiva session==true) - ServletContext application - ServletConfig config - javax.servlet.jsp.PageContext pageContext (utile come aggregatore di references agli altri implicit objects) - page == this (non molto utile) - JspException exception (solo per le pagine di errore designate) Questi sono istanziati come _variabili locali_ del metodo "service", quindi sono accessibili negli scriplets e nelle espressioni, ma NON nelle dichiarazioni. Per lo stesso motivo, non sono accessibili da utility classes esterne. _Tuttavia è possibile passare normalmente questi oggetti ad altri metodi/classi._ TRICK: per differenziare il comportamento tra GET e POST, è possibile usare: if( request.getMethod().equals("GET") ) { // doGet } else if( request.getMethod().equals("POST") ) { // doPost } else ... = Dichiarazioni = Le dichiarazioni dei campi con inizializzazione sono eseguite una sola volta (come nei servlet). Ad es.: <%! int counter=0; %> // contatore (globale) inizializzato una sola volta <% counter++; %> // incrementa il contatore ogni volta che viene visitata la pagina Per le inizializzazioni più complesse, è possibile overloadare i metodi: jspInit() jspDestroy() OSS.: "_jspService" non può essere overloadato, ne "doPost" e "doGet". Per evitare che più thread accedano contemporaneamente ad un campo (race conditions), si devono usare i blocchi "synchronized": <% synchronized( this ) { counter++; } %> MEMO: il lock non può essere preso sui tipi primitivi! Piuttosto che dichiarare molti metodi in una pagina JSP è preferibile inserire i metodi in utility classes esterne e dichiararli statici. vantaggi: - facilita la riusabilità del codice - migliore separazione content vs. presentation ... = Azioni standard = Sono tradotte in codice Java a compile-time. ... -> ~= RequestDispatcher.forward NOTA: con forward si delega TOTALMENTE la scrittura della pagina di output l'output corrente viene resettato, e l'elaborazione della pagina corrente NON prosegue! -> ~= RequestDispatcher.include (richiesto in JSP<1.1) NOTA: la request corrente viene reindirizzata, l'output della pagina accodato, e l'elaborazione della pagina corrente prosegue aggiunta di parametri alla richiesta corrente: ... OSS.: le limitazioni per queste redirezioni sono analoghe a quelle del RequestDispatcher dei servlet: l'URL può fare riferimento solo a risorse dinamiche (servlet o pagine jsp) nella stessa webapp. == JavaBeans == Un *JavaBean* è una classe Java che segue delle convenzioni particolari: - must have a zero-argument (default) constructor; OSS.: SE non viene definito alcun costruttore, la JVM ne aggiunge automaticamente uno senza argomenti - no public fields, all fields must be private (and named as "fieldName"); - private fields can be accessed through public *getter and setter methods* only: type getXx() // getter boolean isXx() // getter for booleans void setXx(type) // setter OSS.: i campi sono anche detti *properties*. esempio: package vehicles; // SEMPRE NECESSARIO PER POTER ACCEDERE ALLA CLASSE! class Car { Car() { } // ... (altri costruttori) private int numPassengers; public int getNumPassengers() { // getter method for "numPassengers" return numPassengers; } // if no setter is defined then the field is read-only private boolean leased; public boolean isLeased() { return leased; } public void setLeased(boolean leased) { this.leased = leased; } } E' possibile manipolare i JavaBeans nelle pagine JSP con delle azioni standard specifiche: - creazione/importazione di una istanza: OSS.: Lo *scope*=visibilità dei beans può essere di 4 tipi: - *page* (default) = visibile solo nella stessa pagina JSP, non condiviso; - *request* = distrutto alla chiusura della richiesta corrente, può essere condiviso se la richiesta è forwardata; - *session* = distrutto alla chiusura della sessione corrente, _condiviso tra tutte le pagine richieste dallo stesso utente_ nella stessa sessione; - *application* = distrutto alla chiusura del server, condiviso tra tutte le pagine JSP nello stesso web application context, _anche da utenti diversi_. OSS.: Un JavaBean viene istanziato ex-novo sse non ne è presente un altro con lo stesso "id" e "scope", _altrimenti viene ritornata una reference ad un oggetto preesistente_. se l'oggetto viene creato ex-novo, equivale a: <% package.class nomeIstanza = new package.class(); %> - creazione ed inizializzazione: statements di inizializzazione eseguiti solo se il beam è creato ex-novo - creazione/importazione di una istanza serializzata: - lettura/output del valore di un campo nella pagina: equivale a: <%= nomeIstanza.getCampo() %> - modifica: -> legge il nuovo valore da un parametro della richiesta corrente -> come il precedente + assume param="campo" -> prova a settare _tutte_ le properties dai parametri omonimi della request OSS.: se un parametro non è presente nella request o se il casting fallisce, il campo è lasciato inalterato. -> So, you usually design your beans to have identifiable default values that let you determine if a property has been modified. -> some developers eschew the automatic conversion, define all of their settable bean properties to be of type String, and use explicit try/catch blocks to handle malformed data. OSS.: un JavaBean condiviso potrebbe essere settato congiuntamente da più pagine. equivale a: <% nomeIstanza.setCampo(...); %> == JSTL = JSP Standard Tag Library == Sono ulteriori azioni standard che sostituiscono alcuni costrutti tipici del linguaggio Java e forniscono molti tags di uso comune: - assegnazioni di variabili nei vari scopes - strutture di controllo, looping, etc. ("if...then", etc.) - connessione a database e invio di statements in SQL - manipolazione di stringhe, formattazione ... -> http://www.tutorialspoint.com/jsp/jsp_standard_tag_library.htm Sono spesso usate in combinazione con lo JSP 2.0 EL. Vengono importati nella pagina che le usa con la direttiva "taglib": <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %> <%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> sintassi generale: core tags: formatting tags: SQL tags: XML tags: standard functions (most string-manilupating): === Core Tags === There are following Core JSTL Tags: Like <%= ... >, but for expressions. Inserisce automaticamente gli escapes XML. Sets the result of an expression evaluation in a 'scope' Removes a scoped variable (from a particular scope, if specified). Catches any Throwable that occurs in its body and optionally exposes it. Simple conditional tag which evalutes its body if the supplied condition is true. Simple conditional tag that establishes a context for mutually exclusive conditional operations, marked by and Subtag of that includes its body if its condition evalutes to 'true'. Subtag of that follows tags and runs only if all of the prior conditions evaluated to 'false'. Retrieves an absolute or relative URL and exposes its contents to either the page, a String in 'var', or a Reader in 'varReader'. The basic iteration tag, accepting many different collection types and supporting subsetting and other functionality . Iterates over tokens, separated by the supplied delimeters. Adds a parameter to a containing 'import' tag's URL. Redirects to a new URL. (redirect client-side) Creates a URL with optional query parameters esempi: ... ... ... ... Item

<%-- default scope: page --%> OSS.: l'attributo "var" NON può contenere un espressione! <%-- variabile booleana --%> .... ... === Formatting tags === Following is the list of Formatting JSTL Tags: To render numerical value with specific precision or format. Parses the string representation of a number, currency, or percentage. -> PRODUCE 1 STRINGA FORMATTATA (DA 1 OGGETTO DATE) -> PRODUCE 1 OGGETTO DATE (DA 1 STRINGA) Loads a resource bundle to be used by its tag body. Stores the given locale in the locale configuration variable. Loads a resource bundle and stores it in the named scoped variable or the bundle configuration variable. Specifies the time zone for any time formatting or parsing actions nested in its body. Stores the given time zone in the time zone configuration variable To display an internationalized message. Sets the request character encoding === SQL tags === Following is the list of SQL JSTL Tags: Apre la connessione con un DB Executes 1 (AND ONLY 1) SQL query defined in its body or through the sql attribute. Executes 1 (AND ONLY 1) SQL update defined in its body or through the sql attribute. OPTIONAL: Sets a parameter in an SQL statement to the specified value. OPTIONAL: Sets a parameter in an SQL statement to the specified java.util.Date value. Provides nested database action elements with a shared Connection, set up to execute all statements as one transaction. esempi: SELECT * FROM Table WHERE NOME='${nome}' <%-- testa che il risultato non sia vuoto --%> ... <%-- se il risultato contiene una singola tupla --%> <%-- se il risultato contiene più tuple --%> === XML tags === === Standard functions === Following is the list of JSTL Functions: fn:contains() Tests if an input string contains the specified substring. fn:containsIgnoreCase() Tests if an input string contains the specified substring in a case insensitive way. fn:endsWith() Tests if an input string ends with the specified suffix. fn:escapeXml() Escapes characters that could be interpreted as XML markup. fn:indexOf() Returns the index withing a string of the first occurrence of a specified substring. fn:join() Joins all elements of an array into a string. fn:length() Returns the number of items in a collection, or the number of characters in a string. fn:replace() Returns a string resulting from replacing in an input string all occurrences with a given string. fn:split() Splits a string into an array of substrings. fn:startsWith() Tests if an input string starts with the specified prefix. fn:substring() Returns a subset of a string. fn:substringAfter() Returns a subset of a string following a specific substring. fn:substringBefore() Returns a subset of a string before a specific substring. fn:toLowerCase() Converts all of the characters of a string to lower case. fn:toUpperCase() Converts all of the characters of a string to upper case. fn:trim() Removes white spaces from both ends of a string. = Oracle ADF = Application Development Framework = Framework proprietario di Oracle contente diverse librerie di tag personalizzati: - JSF = JavaServer Faces - Apache Struts = Tag personalizzati = Possono essere di 3 tipi: - senza attributi e senza body - con attributi e senza body: - con attributi e con body: body OSS.: il "body" può contenere template text e/o altro codice JSP. == Classic tag API (JSP <=2.3) == Vengono definiti mediante classi Java che implementano l'interfaccia javax.servlet.jsp.tagext.Tag -> senza body o con body inalterterato javax.servlet.jsp.tagext.BodyTag -> con modifica del body o estendono gli adapters: TagSupport BodyTagSupport dette *tag handlers*. esempio Tag: package ...; // RICHIESTO! import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; import java.io.*; class SampleTag extends TagSupport { public int doStartTag() // RICHIESTO: elabora il primo "blocco" del tag throws JspException // OPZIONALE: l'unica eccezione che può lanciare è questa { // ottiene dal campo ereditato "pageContext" altri oggetti su cui effettuare l'I/O JspWriter out = pageContext.getOut(); ServletRequest request = pageContext.getRequest(); ServletResponse response = pageContext.getResponse(); ServletContext context = pageContext.getServletContext(); HttpSession session = pageContext.getSession(); // effettua l'I/O // REQUIRED: TUTTE LE ECCEZIONI DEVONO ESSERE CATTURATE INTERNAMENTE! try { out.println(...); // ... } catch(Exception ex) { throw new JspException( ex.getMessage() ); // OPZIONALE: reindirizza l'eccezione all'esterno } return SKIP_BODY|EVAL_BODY_INCLUDE; // dichiara se si deve eseguire+includere il body del tag o no } // END of doStartTag public int doEndTag() // OPZIONALE: viene _sempre_ eseguito dopo doStartTag e dopo il body (se presente). { // ... return EVAL_PAGE|SKIP_PAGE; // dichiara se si deve continuare l'elaborazione della pagina JSP dopo il tag corrente o no } // OPZIONALE: getters and setters per la lettura degli attributi private int attributeName = 0; public void setAttributeName(String attributeName) { // invocato automaticamente dal JSP engine per il passaggio del valore del parametro this.attributeName = Integer.parseInt(attributeName); } // OSS.: il getter method è opzionale. //... (altri attributi) // OPZIONALE: altri campi privati -> N.B.: _vengono condivisi tra tutti i tags dello stesso tipo, anche in pagine diverse!_ -> problemi race conditions, usare sempre blocchi "synchronized" per l'accesso } // END of class esempio BodyTag: package ...; // RICHIESTO! import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; import java.io.*; class SampleTag extends BodyTagSupport { ?? // ... (stesse regole di prima + doStartTag DEVE ritornare EVAL_BODY_BUFFERED) ?? public int doAfterBody() { // modifica il contenuto del body PRIMA dell'elaborazione del JSP container BodyContent body = this.getBodyContent(); String bodyString = body.getString(); // ritorna il body come una stringa STATICA Reader bodyReader = body.getReader(); JspWriter out = body.getEnclosingWriter(); // ritorna il body come uno stream MODIFICABILE // ... (effettua I/O nel body) return SKIP_BODY; // = la modifica è finita return EVAL_BODY_INCLUDE; // = richiama ricorsivamente se stessa } } E' inoltre richiesto un *file .TLD = Tag Library Descriptor* (in XML), posto in una subdirectory di "WEB-INF", che descriva al JSP engine le caratteristiche dei tags, e che deve essere importato dalle pagine JSP mediante la direttiva "taglib". esempio: 1.0 1.1 Nome libreria Descrizione libreria tagName package.className descrizione tag empty|JSP|tagdependent attributeName true // OSS.: se un attributo non viene specificato, il suo valore viene lasciato inalterato true // se "true" acconsente che il valore dell'attributo venga specificato con un'espressione JSP // ... (altri attributi) //... (altri tags) Il body può essere di 3 tipi: - empty = no body allowed - JSP = body with JSP code allowed, viene eseguito automaticamente dal JSP engine - tagdependent = RAW body allowed, _non_ viene eseguito automaticamente dal JSP engine == SimpleTag API (only for JSP >=2.4) == A differenza della classic tag API, viene creata una nuova istanza della classe per ogni occorrenza del tag nella pagina -> i campi privati non sono condivisi Un'altra differenza riguarda il "bodycontent" nel TLD: ?? - JSP è accettato, ma il codice JSP non viene effettivamente eseguito; ?? - è supportato anche "scriptless" = body senza codice JSP. N.B.: when using the SimpleTag API, it is illegal to include scripting elements in the body of the tag. esempio: public class ExampleTag extends SimpleTagSupport { public void doTag() throws JspException, IOException { JspWriter out = getJspContext().getOut(); out.print("Hello World!"); getJspBody().invoke(null); // OPZIONALE: esegue+include il body (se ammesso e presente) } } == JSP-based .tag files (only for JSP >=2.x ) == Consentono la definizione di custom tags usando codice JSP invece di codice Java. VANTAGGIO: _NON_ richiedono un TLD. -> non è necessario definire anticipatamente le caratteristiche del tag (attributi, body, etc.) Per essere usate è sufficiente salvarle in una subdir di "WEB-INF/tags", quindi includerle con: <%@ taglib tagdir="/WEB-INF/tags" prefix="csajsp" %> In base al loro nome, verranno caricate automaticamente a run-time dalla dir specificata. Le regole sintattiche sono le stesse del codice JSP standard, in più sono fornite: - la direttiva "attribute", per la definizione degli attributi -> _salvati automaticamente come variabili locali di service_; - l'azione standard "" -> esegue+espande il contenuto del body (se presente) ... esempio: <%@ attribute name="length" required="false" %> <% int len = 50; try { len = Integer.parseInt(length); } catch(NumberFormatException nfe) {} %> Body:
<%= coreservlets.Primes.nextPrime (coreservlets.Primes.random(len)) %> = Fonti = http://java.sun.com/products/jsp/tags/11/tags11.html http://java.html.it/guide/leggi/23/guida-jsp/ http://www.jsptut.com