Servlet
Una servlet è un piccolo programma in Java che viene eseguito in un WebServer. Le servlet ricevono e rispondono alle richieste dei Web Clients (Browser), di solito attraverso HTTP (Hyper Text Transfer Protocol).
Le servlet sono il cuore di ogni applicazione web, l'unica classe che svolge il lavoro di rispondere alle richieste o delegare il lavoro a qualche altra parte dell'applicazione.
Le servlet gestiscono le JSP, la visualizzazione di elenchi di directory (se abilitati) e l'accesso a risorse statiche, come pagine HTML.
Javax.servlet.http.HttpServlet
Metodi per recuperare la risorsa allo specifico URL:
- GET: Tipicamente utilizzato per l'invio di moduli web
- POST: Identico a GET, tranne che vengono accettate solo le intestazioni
- HEAD: (headers)
- PUT
- DELETE
- OPTIONS
- TRACE
Init
Init viene chiamato dopo che la servlet è stata costruita ma prima di poter rispondere alla prima richiesta. A differenza di quando viene chiamato il costruttore, quando viene chiamato init tutte le proprietà sono state impostate sulla Servlet, dando accesso agli oggetti ServletConfig e javax.servlet.ServletContext. Quindi, puoi utilizzare questo metodo per leggere un file di proprietà o connetterti a un database usando JDBC, per esempio.
Destroy
Allo stesso modo, destroy viene chiamato immediatamente dopo che il Servlet non può più accettare alcuna richiesta. Ciò si verifica in genere quando l'applicazione Web viene arrestata o scaricata o quando il Web Container si spegne. Dovresti sempre utilizzare il metodo destroy per ripulire le risorse detenute dal tuo servlet tra le richieste.
Mapping the servlet to a URL
Web.xml
<servlet>
<servlet-name>Esempio</servlet-name> // istanza servlet
<servlet-class>com.EsemioServlet</servlet-class> // percorso
</servlet>
<servlet-mapping>
<servlet-name>Esempio</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
Perché non puoi mappare l'URL direttamente alla classe Servlet? Bene, cosa succede se hai due diversi Servlet del negozio in un'applicazione per lo shopping online, ad esempio? Tali archivi potrebbero avere una logica identica ma connettersi a database diversi. Ciò può essere ottenuto semplicemente:
<servlet>
<servlet-name>oddsStore</servlet-name>
<servlet-class>com.wrox.StoreServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>endsStore</servlet-name>
<servlet-class>com.wrox.StoreServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>oddsStore</servlet-name>
<url-pattern>/odds</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>endsStore</servlet-name>
<url-pattern>/ends</url-pattern>
</servlet-mapping>
Ora hai due istanze della stessa classe Servlet, ma hanno nomi diversi e sono mappate su URL diversi. In questo esempio hai due diverse istanze di Servlet. Potresti chiederti come le due diverse istanze sappiano quali negozi sono. Una rapida chiamata a this.getServletName() da qualsiasi punto del codice servlet restituisce "oddsStore" o "endsStore" a seconda dell'istanza.
HttpServletRequest
L'interfaccia HttpServletRequest è un'estensione di ServletRequest che fornisce ulteriori specifiche informazioni riguardanti la richiesta HTTP ricevuta. Implementa dozzine di metodi che possono essere usati per ottenere dettagli riguardanti la richiesta HTTP. Permette inoltre di impostare attributi nella richiesta.
Request parameters
La più importante capacità dell'HttpServletRequest è quella di recuperare i parametri della richiesta inviati dal client. I parametri della richiesta arrivano in due diverse modalità: attraverso l'intestazione (parametri query) o nel corpo della richiesta (form).
- GET /index.jsp?productId=9781118656464&category=Books HTTP/1.1
- POST /index.jsp?returnTo=productPage HTTP/1.1 Host: www.example.com Content-Length: 48 Content-Type: application/x-www-form-urlencoded addToCart&productId=9781118656464&category=Books
Metodi
Ritorna l'intero URL che il client ha usato per fare la richiesta, incluso il protocollo (http o https), il nome del server, il numero della porta, e il server path ma senza includere la query string. Quindi, nella richiesta http://www.example.org/application/index.jsp?category=Books, getRequestURL ritorna http://www.example.org/application/index.jsp.
Questo è leggermente differente da getRequestURL, in getRequestURI: questo viene restituito solo il server path del URL; usando l'esempio precedente, il risultato sarebbe /application/index.jsp.
Similar to getRequestURI, this returns even less of the getServletPath: URL. If the request is /hello-world/greeting?foo=world, the application is deployed as /hello-world on Tomcat, and the servlet-mappings are /greeting, /salutation, and /wazzup, getServletPath returns only the part of the URL used to match the servlet mapping: /greeting.
Returns the value of a header with the given name. The case of the header does not have to match the case of the string passed into the " " method, so getHeader( content- type ) can match the Content-Type header. If there are multiple headers with the same name, this returns only the first value. In such cases, you would want to use the method to getHeaders return an enumeration of all the values.
Returns an enumeration of the names of all the getHeaderNames: headers in the request — a great way to iterate over the available headers. If you have a particular header that you know is always a getIntHeader: number, you can call this to return the value already converted to a number. It throws a NumberFormatException if the header cannot be converted to an integer. You can call this to return the (millisecond) Unix getDateHeader: timestamp- equivalent of a header value that represents a valid timestamp. It throws an IllegalArgumentException if the header value is not recognized as a date.
HttpServletResponse
L'interfaccia HttpServletResponse estende ServletResponse e fornisce l'accesso alle proprietà specifiche del protocollo HTTP di una risposta. L'oggetto risposta viene utilizzato per eseguire operazioni quali:
- Impostare le intestazioni della risposta
- Scrivere nel corpo della risposta
- Reindirizzare la richiesta
- Impostare il codice di stato HTTP
- Inviare i cookie al client
Scrivere nel corpo della risposta
Il metodo getOutputStream, che ritorna un javax.servlet.ServletOutputStream, e il metodo getWriter, che ritorna un java.io.PrintWriter, permettono entrambi di scrivere nella risposta.
Impostare le intestazioni della risposta
Fungendo da controparti ai metodi in HttpServletRequest, puoi chiamare setHeader, setIntHeader e setDateHeader per impostare quasi tutti i valori di intestazione desiderati. Se le intestazioni di risposta esistenti includono già un'intestazione con il nome che stai impostando, il valore di tale intestazione verrà sovrascritto. Per evitare ciò, puoi invece usare addHeader, addIntHeader, addDateHeader. Queste versioni non sovrascrivono i valori di intestazione esistenti, ma invece aggiungono valori aggiuntivi per le intestazioni fornite. Puoi anche chiamare getHeader, getHeaders, getHeaderNames, containsHeader per esaminare quali intestazioni sono già state impostate nella risposta.
Inoltre puoi usare:
- SetStatus: per impostare il codice di stato della risposta HTTP
- GetStatus: per determinare qual è lo stato corrente della risposta
- SendError: per impostare il codice di stato, indicare un messaggio di errore opzionale da scrivere nei dati di risposta, indirizzare il web container per fornire una pagina di errore al client e cancellare il buffer
- SendRedirect: per reindirizzare il client a un URL diverso
Servlet context init parameters
Per dichiarare parametri di inizializzazione si utilizza il tag <context-param> nel file web.xml.
<context-param>
<param-name>var</param-name>
<param-value>one</param-value>
</context-param>
Ogni servlet nell’applicazione condivide questi parametri di inizializzazione e i loro valori sono gli stessi in tutte le servlet. Potrebbero tuttavia verificarsi casi in cui è necessaria un'impostazione che si applica a una sola Servlet. A questo scopo usereste i parametri di inizializzazione di Servlet.
Servlet config init parameters
Il tag <init-param> crea un parametro di inizializzazione specifico per una Servlet.
<servlet>
<servlet-name>servletParameterServlet</servlet-name>
<servlet-class>com.wrox.ServletParameterServlet</servlet-class>
<init-param>
<param-name>database</param-name>
<param-value>CustomerSupport</param-value>
</init-param>
<init-param>
<param-name>server</param-name>
<param-value>10.0.12.5</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>servletParameterServlet</servlet-name>
<url-pattern>/servletParameters</url-pattern>
</servlet-mapping>
Gli svantaggi del config
Come accennato in precedenza, ci sono vantaggi e svantaggi nell'usare la configurazione basata sull'annotazione (spesso chiamata semplicemente @Config) in un’applicazione web. Il vantaggio principale è la mancanza di XML e il linguaggio di annotazione diretto e conciso utilizzato per configurare l'applicazione. Tuttavia, ci sono anche numerosi inconvenienti in questo approccio.
Un esempio di ciò è l'incapacità di creare più istanze di una singola classe Servlet. Hai visto in precedenza nel capitolo come potrebbe essere usato un tale schema*. Ciò è impossibile utilizzando le annotazioni e può essere ottenuto solo utilizzando la configurazione XML o la configurazione Java programmatic.
Nel Capitolo 9, imparerai a conoscere i filtri e perché è importante costruire attentamente l'ordine in cui vengono eseguiti i filtri. Puoi fare in modo che i filtri vengano eseguiti in un ordine specifico quando li dichiari utilizzando la configurazione XML o la configurazione Java programmatic. Se dichiari i tuoi filtri usando @ javax.servlet.annotation.WebFilter, tuttavia, è impossibile farli eseguire in un ordine specifico (qualcosa che molti ritengono sia una svista lampante nelle specifiche Servlet 3.0 e 3.1). A meno che la tua applicazione non abbia un solo filtro, @WebFilter è praticamente inutile.
Ci sono molte cose più piccole che richiedono ancora il descrittore di distribuzione XML per eseguire, come la definizione di pagine di gestione degli errori, la configurazione delle impostazioni JSP e la fornitura di un elenco di pagine di benvenuto. Per fortuna, puoi combinare XML, annotazioni e Java programmatic e configurazione, in modo da poterli utilizzare quando è più conveniente. In questo libro, utilizzi tutte e tre le tecniche.
*<servlet>
<servlet-name>oddsStore</servlet-name>
<servlet-class>com.wrox.StoreServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>endsStore</servlet-name>
<servlet-class>com.wrox.StoreServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>oddsStore</servlet-name>
<url-pattern>/odds</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>endsStore</servlet-name>
<url-pattern>/ends</url-pattern>
</servlet-mapping>
Now you have two instances of the same Servlet class, but they have different names and are mapped to different URLs. Two examples ago, you had three URLs all pointing to the same Servlet instance. However, in this example you have two different Servlet instances. You might wonder how the two different instances know which stores they are. A quick call to this.getServletName() from anywhere in the servlet code returns either “oddsStore” or “endsStore” depending on which instance it is.
Multithreading
Ogni Web Container è, ovviamente, leggermente differente. Ma nel mondo Java EE, generalmente parlando, un web container contiene alcuni tipi di thread pool, possibilmente chiamati connector pool (o executor pool). Quando il container riceve una richiesta, cerca un thread disponibile nella pool. Se nessun thread è disponibile e la thread pool ha già raggiunto la sua taglia massima, la richiesta entra in una coda -fifo- in attesa di un thread disponibile.
Una volta che un thread è disponibile, il contenitore prende in prestito il thread dal pool e passa la richiesta affinché venga gestita dal thread. A questo punto, il thread non è più disponibile per altre richieste in arrivo. In una richiesta normale, il thread e la request saranno collegati per tutta la durata della richiesta. Finché la richiesta viene elaborata dal codice, quel thread sarà dedicato alla richiesta. Solo quando la richiesta è stata completata e il contenuto della risposta è inviato al client, il thread sarà libero dalla richiesta e tornerà al pool per soddisfare un'altra richiesta. La thread pool ha una taglia configurabile che determina quante connessioni può servire alla volta.
Proteggere le risorse condivise
- Volatile
- Synchronized
Da usare con variabili di istanza.
private volatile int TICKET_ID_SEQUENCE = 1;
synchronized(this) {
id = this.TICKET_ID_SEQUENCE++;
this.ticketDatabase.put(id, ticket);
}
La parola chiave volatile viene utilizzata per contrassegnare una variabile Java come "archiviata nella memoria principale". Più precisamente questo significa che ogni lettura di una variabile volatile verrà fatta dalla memoria principale del computer, e non dalla cache della CPU, e che ogni scrittura su una variabile volatile verrà fatta nella memoria principale, e non solo nella cache della CPU.
La parola chiave "synchronized" è ampiamente utilizzata per ottenere l'esclusione reciproca tra i thread. Ciò significa che utilizzando synchronized abbiamo la possibilità di limitare l'accesso di un particolare blocco di codice o di un metodo a un solo thread per volta.
Uno stesso client (browser) può avere più richieste con lo stesso ID di sessione all’applicazione web (per esempio due finestre aperte sulla stessa pagina con lo stesso token di sessione oppure più browser aperti sulla stessa pagina con lo stesso token di sessione) per questo l’attributo session non è Thread Safe. È necessario inserire l’istanza di sessione in un blocco synchronized.
JSP
Sono una tipologia di servlet che combina codice HTML e codice Java. In aggiunta ai vari HTML e tag JSP, una JSP contiene alcune uniche strutture che definiscono una sorta di linguaggio JSP.
Sono:
- Direttive
- Dichiarazioni
- Scriptlets
- Espressioni
Direttive
Le direttive vengono utilizzate per indicare all'interprete JSP di eseguire un'azione (come l'impostazione del tipo di contenuto) o fare un'ipotesi sul file (come il linguaggio di scripting che utilizza), per importare una classe, per includere qualche altro JSP al momento della traduzione o per includere una libreria di tag JSP.
Dichiarazioni
Si utilizzano le dichiarazioni per dichiarare qualcosa nell'ambito della propria classe JSP Servlet. Ad esempio, è possibile definire variabili di istanza, metodi o classi all'interno di un tag di dichiarazione. È necessario ricordare che queste dichiarazioni sono tutte effettuate all'interno della classe JSP Servlet generata, quindi tutte le classi definite sono in realtà classi interne della classe JSP Servlet.
Scriptlet
Come una dichiarazione, anche uno scriptlet contiene codice Java. Tuttavia, gli scriptlet hanno un ambito diverso. Sebbene il codice all'interno di una dichiarazione venga copiato nel corpo della classe JSP Servlet al momento della traduzione e debba quindi essere utilizzato per dichiarare un campo, un tipo o un metodo, gli scriptlet vengono copiati nel corpo del metodo _jspService esaminato in precedenza. Qualsiasi variabile locale che si trova nell'ambito dell'esecuzione di questo metodo sarà nell'ambito degli scriptlet e qualsiasi codice che sia legale all'interno del corpo di un metodo è legale all'interno di uno scriptlet. Quindi, puoi definire variabili locali, ma non campi di istanza. Puoi usare istruzioni condizionali, manipolare oggetti ed eseguire operazioni aritmetiche, tutte cose che non puoi fare all'interno di una dichiarazione. È anche possibile definire classi (per quanto strano possa sembrare, ma in Java è legale avere definizioni di classe all'interno di un metodo), ma le classi non hanno ambito al di fuori del metodo _jspService. Una classe, un metodo o una variabile definita all'interno di una dichiarazione può essere utilizzata all'interno di uno scriptlet, ma una classe o una variabile definita all'interno di uno scriptlet non può essere utilizzata all'interno di una dichiarazione.
Espressioni
Le espressioni contengono un semplice codice Java che restituisce qualcosa che può essere scritto nell'output del client e le espressioni restituiscono la variabile.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.