Skip to content

3. Nozioni di base sullo sviluppo web in Java

Passiamo ora allo sviluppo di applicazioni web dinamiche, c.a.d, ovvero applicazioni in cui le pagine HTML inviate all’utente sono generate da programmi.

3.1. Creazione di un progetto web in Eclipse

Svilupperemo una prima applicazione web con Eclipse/Tomcat. Seguiremo un approccio analogo a quello utilizzato per creare un’applicazione web senza Eclipse. Una volta avviato Eclipse, creiamo un nuovo progetto:

Image

che definiamo come progetto web dinamico:

Image

Nella prima pagina della procedura guidata di creazione, specifichiamo il nome del progetto [1] e la sua posizione [2]:

Image

Nella seconda pagina della procedura guidata accettiamo i valori predefiniti:

Image

L'ultima pagina della procedura guidata ci chiede di definire il contesto [3] dell'applicazione:

Image

Una volta confermata la procedura guidata da [Finish], Eclipse si connette al sito [http://java.sun.com] per recuperare alcuni documenti che intende memorizzare nella cache, al fine di evitare accessi di rete superflui. Viene quindi richiesta l’autorizzazione della licenza:

Image

La si accetta. Eclipse crea il progetto web. Per visualizzarlo, utilizza un ambiente, chiamato prospettiva, diverso da quello utilizzato per un progetto Java classico:

Image

La prospettiva associata a un progetto web è la prospettiva J2EE. La accettiamo per vedere... Il risultato ottenuto è il seguente:

Image

La prospettiva J2EE è in realtà inutilmente complessa per i progetti web semplici. In questo caso, la prospettiva Java è sufficiente. Per ottenerla, utilizziamo l’opzione [Window -> Open perspective -> Java]:

Image

src: conterrà il codice Java delle classi dell’applicazione, nonché i file che devono essere presenti nel Classpath dell’applicazione.

build/classes (non raffigurato): conterrà i file .class delle classi compilate e una copia di tutti i file diversi dai file .java presenti in src. Un’applicazione web utilizza spesso i cosiddetti file “di risorse”, che devono trovarsi nel Classpath dell’applicazione, ovvero il c.a.d. L'insieme delle cartelle che vengono esplorate dalla JVM quando l'applicazione fa riferimento a una classe, sia durante la compilazione che in fase di esecuzione. Eclipse fa in modo che la cartella build/classes faccia parte del web. I file "risorsa" vengono inseriti nella cartella src, sapendo che Eclipse li copierà automaticamente in build/classes.

WebContent: conterrà le risorse dell'applicazione web che non devono trovarsi nel Classpath dell'applicazione.

WEB-INF/lib: conterrà gli archivi .jar necessari all’applicazione web.

Esaminiamo il contenuto del file [WEB-INF/web.xml] che configura l'applicazione [personne]:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>    personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Abbiamo già incontrato questo tipo di configurazione quando abbiamo studiato la creazione delle pagine iniziali nel paragrafo 2.3.4. Questo file non fa altro che definire una serie di pagine iniziali. Ne conserviamo solo la prima. Il file [web.xml] diventa il seguente:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Il contenuto del file XML sopra riportato deve rispettare le regole sintattiche definite nel file indicato dall’attributo [xsi:schemaLocation] del tag di apertura <web-app>. In questo caso, tale file è [http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd]. Si tratta di un file XML che può essere richiesto direttamente tramite un browser. Se il browser è sufficientemente recente, sarà in grado di visualizzare un file XML:

Image

Eclipse cercherà di verificare la validità del documento XML utilizzando il file .xsd specificato nell’attributo [xsi:schemaLocation] del tag di apertura <web-app>. A tal fine effettuerà un accesso di rete. Se il computer si trova su una rete privata, è necessario indicare a Eclipse il server da utilizzare per uscire dalla rete privata, denominato proxy HTTP. Ciò avviene tramite l’opzione [Window -> Preferences -> Internet]:

Image

Si seleziona (1) se ci si trova su una rete privata. In (2) si indica il nome del computer che supporta il proxy HTTP e in (3) la porta di ascolto dello stesso. Infine, in (4), si indicano i computer per i quali non è necessario passare attraverso il proxy, ovvero quelli che si trovano sulla stessa rete privata del computer con cui si sta lavorando.

Ora creeremo il file [index.html] della pagina iniziale.

3.2. Creazione di una pagina iniziale

Facciamo clic con il tasto destro sulla cartella [WebContent], quindi selezioniamo l’opzione [New -> Other]:

Image

Scegliamo il tipo [HTML] e trasformiamo [Next] in ->

Image

Qui sopra, selezioniamo la cartella principale [WebContent] in (1) o in (2), quindi specifichiamo in (3) il nome del file da creare. Fatto ciò, passiamo alla pagina successiva della procedura guidata:

Image

Con (1) possiamo generare un file HTML precompilato con i dati di (2). Se deselezioniamo (1), viene generato un file HTML vuoto. Lasciamo selezionata l’opzione (1) per ottenere uno scheletro di codice. Concludiamo la procedura guidata con [Finish]. Viene quindi creato il file [index.html]:

Image

con il seguente contenuto:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

Modifichiamo questo file come segue:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Application personne</title>
</head>
<body>
Application personne active...
<br>
<br>
Vous êtes sur la page d'accueil
</body>
</html>

3.3. Test della pagina iniziale

Se non è presente, visualizziamo la vista [Servers] con l'opzione [Window - > Show View -> Other -> Servers], quindi facciamo clic con il tasto destro del mouse sul server Tomcat 5.5:

Image

L’opzione [Add and Remove Objects] sopra indicata consente di aggiungere o rimuovere applicazioni web dal server Tomcat:

Image

I progetti web riconosciuti da Eclipse sono visualizzati in (1). È possibile registrarli sul server Tomcat tramite (2). Le applicazioni web registrate sul server Tomcat compaiono in (4). È possibile cancellarne la registrazione tramite (3). Registriamo il progetto [personne]:

Image

quindi completiamo la procedura guidata di registrazione con [Finish]. La vista [Servers] mostra che il progetto [personne] è stato registrato su Tomcat:

Image

Ora avviamo il server Tomcat:

Avviamo il browser web:

Image

quindi inseriamo l'URL [http://localhost:8080/personne]. Questo URL corrisponde alla radice dell'applicazione web. Non viene richiesto alcun documento. In questo caso, viene visualizzata la pagina iniziale dell’applicazione. Se questa non esiste, viene segnalato un errore. In questo caso la pagina iniziale esiste. Si tratta del file [index.html] che abbiamo creato in precedenza. Il risultato ottenuto è il seguente:

Image

È conforme a quanto previsto. Ora utilizziamo un browser esterno a Eclipse e richiediamo lo stesso URL:

Image

L’applicazione web [personne] è quindi riconoscibile anche al di fuori di Eclipse.

3.4. Creazione di un modulo HTML

Ora creiamo un documento statico HTML [formulaire.html] nella cartella [personne]:

Image

Per crearlo, seguiremo la procedura descritta al paragrafo 3.2, pagina 33. Il suo contenuto sarà il seguente:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Personne - formulaire</title>
</head>
<body>
  <center>
    <h2>Personne - formulaire</h2>
    <hr>
    <form action="" method="post">
    <table>
      <tr>
        <td>Nom</td>
        <td><input name="txtNom" value="" type="text" size="20"></td>
      </tr>
      <tr>
        <td>Age</td>
        <td><input name="txtAge" value="" type="text" size="3"></td>
      </tr>
    </table>
    <table>
      <tr>
        <td><input type="submit" value="Envoyer"></td>
        <td><input type="reset" value="Retablir"></td>
        <td><input type="button" value="Effacer"></td>
      </tr>
    </table>
    </form>
  </center>
</body>
</html>

Il codice HTML sopra riportato corrisponde al modulo riportato di seguito:

Image

tipo HTML
nome
codice HTML
ruolo
1
<input type="text">
txtNom
riga 14
inserimento del nome
2
<input type="text">
txtAge
riga 18
inserimento dell'età
3
<input type="submit">
 
riga 23
invio dei valori inseriti al server all'URL /personne1/main
4
<input type="reset">
 
riga 24
per riportare la pagina allo stato in cui è stata ricevuta inizialmente dal browser
5
<input type="button">
 
riga 25
per cancellare il contenuto dei campi di immissione [1] e [2]

Salviamo il documento nella cartella <persona>/WebContent. Avviamo Tomcat se necessario. Con un browser, richiediamo l'URL http://localhost:8080/personne/formulaire.html:

Image

L’architettura client/server di questa applicazione di base è la seguente:

Image

Il server web si trova tra l'utente e l'applicazione web e non è stato rappresentato in questa figura. [formulaire.html] è un documento statico che fornisce lo stesso contenuto a ogni richiesta del client. La programmazione web mira a generare contenuti adeguati alla richiesta del client. Tali contenuti vengono quindi generati dal programma. Una prima soluzione consiste nell’utilizzare una pagina JSP (Java Server Page) al posto del file statico HTML. È proprio ciò che vedremo ora.

3.5. Creazione di una pagina JSP


Letture [ref1]: capitolo 1, capitolo 2: 2.2, 2.2.1, 2.2.2, 2.2.3, 2.2.4


La precedente architettura client/server viene trasformata come segue:

Image

Una pagina JSP è una variante configurata della pagina HTML. Alcuni elementi della pagina ricevono il proprio valore solo al momento dell’esecuzione. Questi valori vengono calcolati dal programma. Si tratta quindi di una pagina dinamica: richieste successive alla pagina possono portare a risposte diverse. Con il termine «risposta» si intende qui la pagina HTML visualizzata dal browser client. Alla fine, il browser riceve sempre un documento HTML. Questo documento HTML viene generato dal server web a partire dalla pagina JSP, che funge da modello. I suoi elementi dinamici vengono sostituiti dai valori effettivi al momento della generazione del documento HTML.

Per creare una pagina JSP, facciamo clic con il tasto destro sulla cartella [WebContent] e selezioniamo l’opzione [New -> Other]:

Image

Scegliamo il tipo [JSP] e passiamo a [Next] ->

Image

Qui sopra, selezioniamo la cartella principale [WebContent] in (1) o in (2), quindi specifichiamo in (3) il nome del file da creare. Fatto ciò, passiamo alla pagina successiva della procedura guidata:

Image

Con (1) possiamo generare un file JSP precompilato con i dati di (2). Se deselezioniamo (1), viene generato un file JSP vuoto. Lasciamo selezionata l’opzione (1) per ottenere uno scheletro di codice. Concludiamo la procedura guidata con [Finish]. Viene quindi creato il file [formulaire.jsp]:

Image

con il seguente contenuto:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

La riga 1 indica che si tratta di una pagina JSP. Trasformiamo il testo sopra riportato nel modo seguente:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    // si recuperano i parametri
  String nom=request.getParameter("txtNom");
  if(nom==null) nom="inconnu";
  String age=request.getParameter("txtAge");
  if(age==null) age="xxx";  
%>

<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
      <title>Personne - formulaire</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire</h2>
      <hr>
      <form action="" method="post">
          <table>
            <tr>
              <td>Nom</td>
            <td><input name="txtNom" value="<%= nom %>" type="text" size="20"></td>
          </tr>
          <tr>
              <td>Age</td>
            <td><input name="txtAge" value="<%= age %>" type="text" size="3"></td>
          </tr>
        </table>
        <table>
            <tr>
              <td><input type="submit" value="Envoyer"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" value="Effacer"></td>
          </tr>
        </table>
      </form>
    </center>
  </body>
</html>

Il documento, inizialmente statico, è ora diventato dinamico grazie all’inserimento di codice Java. Per questo tipo di documento, procederemo sempre come segue:

  • inseriamo il codice Java all’inizio del documento per recuperare i parametri necessari alla visualizzazione del documento. Questi si trovano spesso nell’oggetto request. Tale oggetto rappresenta la richiesta del client. Questa può passare attraverso diversi servlet e pagine JSP che potrebbero averla arricchita. In questo caso, ci arriverà direttamente dal browser.
  • Il codice HTML si trova a seguire. Il più delle volte si limiterà a visualizzare variabili calcolate in precedenza nel codice Java tramite i tag <%= variabile %>. Si noti qui che il segno = è attaccato al segno %. Questa è una causa frequente di errori.

Cosa fa il documento dinamico precedente?

  • righe 6-9: recupera dalla richiesta due parametri denominati [txtNom] e [txtAge] e assegna i loro valori alle variabili [nom] (riga 6) e [age] (riga 8). Se non trova i parametri, assegna alle variabili associate dei valori predefiniti.
  • Visualizza il valore delle due variabili [nom, age] nel codice HTML che segue (righe 25 e 29).

Facciamo un primo test. Avviamo Tomcat se necessario, quindi con un browser richiediamo l’URL http://localhost:8080/personne/formulaire.jsp:

Image

Il documento formulaire.jsp è stato richiamato senza passare alcun parametro. Sono stati quindi visualizzati i valori predefiniti. Ora proviamo a richiamare il documento URLhttp://localhost:8080/personne/formulaire.jsp?txtNom=martin&txtAge=14:

Image

Questa volta abbiamo passato al documento formulaire.jsp i parametri txtNom e txtAge che esso richiede. Il documento li ha quindi visualizzati. Sappiamo che esistono due metodi per passare parametri a un documento web: GET e POST. In entrambi i casi, i parametri passati si trovano nell’oggetto predefinito request. In questo caso, sono stati passati tramite il metodo GET.

3.6. Creazione di un servlet


Letture [ref1]: capitolo 1, capitolo 2: 2.1, 2.1.1, 2.1.2, 2.3.1


Nella versione precedente, la richiesta del client veniva elaborata da una pagina JSP. Al primo richiamo di tale pagina, il server web, in questo caso Tomcat, crea una classe Java a partire da essa e la compila. È il risultato di questa compilazione che, in definitiva, elabora la richiesta del client. La classe generata dalla pagina JSP è un servlet poiché implementa l’interfaccia [javax.Servlet]:

Image

La richiesta del client può essere elaborata da qualsiasi classe che implementi questa interfaccia. Ora creiamo una classe di questo tipo: ServletFormulaire. L’architettura client/server precedente viene trasformata come segue:

Image

Con l’architettura basata sulla pagina JSP, il documento HTML inviato al cliente veniva generato dal server web a partire dalla pagina JSP che fungeva da modello. In questo caso, il documento HTML inviato al cliente sarà interamente generato dal servlet.

3.6.1. Creazione del servlet

In Eclipse, facciamo clic con il tasto destro sulla cartella [src] e selezioniamo l’opzione per la creazione di una classe:

Image

quindi definiamo le caratteristiche della classe da creare:

Image

In (1) si inserisce il nome del pacchetto, in (2) il nome della classe da creare. Quest’ultima deve derivare dalla classe indicata in (3). Non è necessario digitare manualmente il nome completo di quest’ultima. Il pulsante (4) consente di accedere alle classi attualmente presenti nel Classpath dell’applicazione web:

Image

In (1) si digita il nome della classe ricercata. In (2) vengono visualizzate le classi del Classpath il cui nome contiene la stringa digitata in (1).

Dopo la convalida della procedura guidata di creazione, il progetto web [personne] viene modificato come segue:

Image

È stata creata la classe [ServletFormulaire] con uno scheletro di codice:

Image

La schermata qui sopra mostra che Eclipse segnala un [warning] nella riga che dichiara la classe. Facciamo clic sull'icona (lampadina) che segnala questo [warning]:

Image

Dopo aver cliccato su (1), in (2) ci vengono proposte alcune soluzioni per eliminare il [warning]. Selezionandone una, in (3) compare la modifica al codice che ne deriverà.

Java 1.5 ha introdotto modifiche al linguaggio Java e ciò che era corretto in una versione precedente può ora essere oggetto di [warnings]. Questi non segnalano errori che potrebbero impedire la compilazione della classe. Servono a richiamare l’attenzione dello sviluppatore su punti del codice che potrebbero essere migliorati. Il codice [warning] indicato qui sopra segnala che una classe dovrebbe avere un numero di versione. Questo viene utilizzato per la serializzazione/deserializzazione degli oggetti, c.a.d. quando un oggetto Java .class in memoria deve essere trasformato in una sequenza di bit inviati in modo sequenziale in un flusso di scrittura, o viceversa quando un oggetto Java .class in memoria deve essere creato a partire da una sequenza di bit letti in modo sequenziale in un flusso di lettura. Tutto ciò è ben lontano dalle nostre attuali preoccupazioni. Chiederemo quindi al compilatore di ignorare questo avviso scegliendo la soluzione [Add @SuppressWarnings ...]. Il codice diventa quindi il seguente:

Image

Non c'è più [warning]. La riga aggiunta si chiama "annotazione", un concetto introdotto con Java 1.5. Completeremo questo codice in seguito.

3.6.2. Classpath di un progetto Eclipse

Il Classpath di un’applicazione Java è l’insieme delle cartelle e dei file archives.jar esplorati quando il compilatore la compila o quando il JVM la esegue. Questi due Classpath non sono necessariamente identici, poiché alcune classi sono utili solo in fase di esecuzione e non in fase di compilazione. Sia il compilatore Java che il JVM dispongono di un argomento che consente di specificare il Classpath dell’applicazione da compilare o eseguire. In modo più o meno trasparente per l’utente, Eclipse garantisce la creazione e il passaggio di tale argomento al JVM.

Come si possono conoscere gli elementi del Classpath di un progetto Eclipse? Con l’opzione [<projet> / Build Path / Configure Build Path]:

Image

Si ottiene quindi la seguente finestra della procedura guidata di configurazione:

Image

La scheda (1) [Libraries] consente di definire l’elenco degli archivi .jar che fanno parte del Classpath dell’applicazione. Questi vengono quindi analizzati dal JVM quando l’applicazione richiede una classe. I pulsanti [2] e [3] consentono di aggiungere archivi al Classpath. Il pulsante [2] consente di selezionare archivi presenti nelle cartelle dei progetti gestiti da Eclipse, mentre il pulsante [3] consente di selezionare qualsiasi archivio presente nel file system del computer.

Sopra sono visibili tre librerie (Libraries):

  • [JRE System Library]: libreria di base per i progetti Java di Eclipse:

Image

  • [Tomcat v5.5 runtime]: libreria fornita dal server Tomcat. Contiene le classi necessarie per lo sviluppo web. Questa libreria è inclusa in ogni progetto web di Eclipse associato al server Tomcat.

Image

È l'archivio [servlet-api.jar] che contiene la classe [javax.servlet.http.HttpServlet], classe padre della classe [ServletFormulaire] che stiamo creando. È proprio perché questo archivio si trova nell’archivio Classpath dell’applicazione che è stato proposto come classe padre nella procedura guidata riportata di seguito.

Image

Se così non fosse stato, non sarebbe apparsa tra i suggerimenti relativi a [2]. Pertanto, se in questa procedura guidata si desidera fare riferimento a una classe padre e questa non viene proposta, significa che o si è commesso un errore nel nome di tale classe, oppure l’archivio che la contiene non si trova nel Classpath dell’applicazione.

  • [Web App Libraries] raccoglie gli archivi presenti nella cartella [WEB-INF/lib] del progetto. In questo caso è vuoto:

Image

Gli archivi del Classpath del progetto Eclipse sono presenti nell’esploratore dei progetti. Ad esempio, per il progetto web [personne]:

Image

L'esploratore dei progetti ci consente di accedere al contenuto di questi archivi:

Image

Come si può vedere sopra, è l’archivio [servlet-api.jar] a contenere la classe [javax.servlet.http.HttpServlet].

3.6.3. Configurazione del servlet


Letture [ref1]: capitolo 2: 2.3, 2.3.1, 2.3.2, 2.3.3, 2.3.4


Il file [WEB-INF/web.xml] serve a configurare l'applicazione web:

Image

Questo file, relativo al progetto [personne], è attualmente il seguente (cfr. pagina 32):


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Indica solo l'esistenza di un file di benvenuto (riga 8). Lo modifichiamo per dichiarare:

  • l'esistenza del servlet [ServletFormulaire]
  • i URL gestiti da questa servlet
  • i parametri di inizializzazione del servlet

Il file web.xml della nostra applicazione «persona» sarà il seguente:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>formulairepersonne</servlet-name>
        <url-pattern>/formulaire</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

I punti principali di questo file di configurazione sono i seguenti:

  • le righe da 7 a 24 riguardano la presenza del servlet [ServletFormulaire]
  • righe 7-20: la configurazione di un servlet avviene tra i tag <servlet> e </servlet>. Un'applicazione può contenere più servlet e quindi altrettante sezioni di configurazione <servlet>...</servlet>.
  • riga 8: il tag <servlet-name> assegna un nome al servlet; può essere qualsiasi nome
  • righe 9-11: il tag <servlet-class> indica il nome completo della classe corrispondente al servlet. Tomcat cercherà questa classe nel file Classpath del progetto web [personne]. La troverà in [build/classes]:

Image

  • righe 12-15: il tag <init-param> serve a passare i parametri di configurazione al servlet. Questi vengono generalmente letti nel metodo init del servlet, poiché i suoi parametri di configurazione devono essere noti sin dal suo primo caricamento.
  • righe 13-14: il tag <param-name> definisce il nome del parametro e <param-value> il suo valore.
  • le righe 12-15 definiscono un parametro [defaultNom,"inconnu"] e le righe 16-19 un parametro [defaultAge,"XXX"]
  • righe 21-24: il tag <servlet-mapping> serve ad associare un servlet (servlet-name) a un modello URL (url-pattern). In questo caso il modello è semplice. Indica che ogni volta che un URL avrà la forma /formulaire, sarà necessario utilizzare il servlet formulairepersonne, c.a.d. la classe [istia.st.servlets.ServletFormulaire] (righe 8-11). Pertanto, esiste un solo URL accettato dal servlet [formulairepersonne].

3.6.4. Il codice del servlet [ServletFormulaire]

Il servlet [ServletFormulaire] avrà il seguente codice:

package istia.st.servlets.personne;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ServletFormulaire extends HttpServlet {

     // parametri dell'istanza
    private String defaultNom = null;
    private String defaultAge = null;

     // inizializzazione
    public void init() {
         // si recuperano i parametri di inizializzazione del servlet
        ServletConfig config = getServletConfig();
        defaultNom = config.getInitParameter("defaultNom");
        if (defaultNom == null)
            defaultNom = "NNNNNNNNNNNNNNN";
        defaultAge = config.getInitParameter("defaultAge");
        if (defaultAge == null)
            defaultAge = "AAA";
    }

     // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // si recuperano i parametri del modulo
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
         // si visualizza il modulo
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println(
                "<html>"+
                  "<head>"+
                    "<title>Personne - formulaire</title>"+
                  "</head>"+
                  "<body>"+
                    "<center>"+
                      "<h2>Personne - formulaire</h2>"+
                      "<hr>"+
                      "<form action='' method='post'>"+
                        "<table>"+
                          "<tr>"+
                            "<td>Nom</td>"+
                            "<td><input name='txtNom' value='"+nom+"' type='text' size='20'></td>"+
                          "</tr>"+
                          "<tr>"+
                            "<td>Age</td>"+
                            "<td><input name='txtAge' value='"+ age +"' type='text' size='3'></td>"+
                          "</tr>"+
                        "</table>"+
                        "<table>"+
                          "<tr>"+
                            "<td><input type='submit' value='Envoyer'></td>"+
                            "<td><input type='reset' value='Rétablir'></td>"+
                            "<td><input type='button' value='Effacer'></td>"+
                          "</tr>"+
                        "</table>"+
                      "</form>"+
                    "</center>"+
                  "</body>"+
                "</html>"
      );
    }

     // POST
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // si passa il controllo a GET
        doGet(request, response);
    }
}

Basta una semplice lettura della servlet per constatare che è molto più complessa della corrispondente pagina JSP. Si tratta di una regola generale: una servlet non è adatta a generare codice HTML. A questo scopo sono previste le pagine JSP. Ne riparleremo in seguito. Chiariamo alcuni punti importanti della servlet sopra riportata:

  • quando una servlet viene chiamata per la prima volta, viene richiamato il suo metodo init (riga 20). È l’unico caso in cui viene richiamato.
  • Se la servlet è stata richiamata dal metodo HTTP GET, viene richiamato il metodo doGet (riga 32) per elaborare la richiesta del client.
  • Se il servlet è stato chiamato dal metodo HTTP POST, viene chiamato il metodo doPost (riga 82) per elaborare la richiesta del client.

Il metodo init serve in questo caso a recuperare in [web.xml] i valori dei parametri di inizializzazione denominati "defaultNom" e "defaultAge". Il metodo init, eseguito al caricamento iniziale del servlet, è il punto giusto per recuperare il contenuto del file [web.xml].

  • riga 22: viene recuperata la configurazione [config] del progetto web. Questo oggetto riflette il contenuto del file [WEB-INF/web.xml] dell'applicazione.
  • riga 23: in questa configurazione viene recuperato il valore di tipo String del parametro denominato "defaultNom". Il valore di questo parametro sarà il nome di una persona. Se non esiste, si otterrà il valore null.
  • righe 24-25: se il parametro denominato "defaultNom" non esiste, si assegna un valore predefinito alla variabile [defaultNom].
  • righe 26-29: si procede allo stesso modo per il parametro denominato "defaultAge".

Il metodo doPost rimanda al metodo doGet. Ciò significa che il cliente potrà inviare i propri parametri indifferentemente tramite un POST o un GET.

Il metodo doGet:

  • riga 32: il metodo riceve due parametri, request e response. request è un oggetto che rappresenta l’intera richiesta del cliente. È di tipo HttpServletRequest, che è un’interfaccia. response è di tipo HttpServletResponse, anch’esso un’interfaccia. L’oggetto response serve a inviare una risposta al cliente.
  • request.getParameter("param") serve a recuperare dalla richiesta del cliente il valore del parametro denominato "param". Alla riga 36 si recupera il valore del parametro "txtNom", alla riga 40 quello del parametro "txtAge". Se questi parametri non sono presenti nella richiesta, si ottiene il valore null come valore del parametro.
  • righe 37-39: se il parametro "txtNom" non è presente nella richiesta, alla variabile "nom" viene assegnato il nome predefinito "defaultNom", inizializzato nel metodo init. Lo stesso vale per le righe 41-43 relative all’età.
  • riga 45: response.setContentType(String) serve a impostare il valore dell’intestazione HTTP Content-type. Questa intestazione indica al client la natura del documento che riceverà. Il tipo text/html indica un documento HTML.
  • riga 46: response.getWriter() serve a ottenere un flusso di scrittura verso il client
  • righe 47-78: si scrive il documento HTML da inviare al client nel flusso di scrittura ottenuto alla riga 46.

La compilazione di questo servlet produrrà un file .class nella cartella [build/classes] del progetto [personne]:

Image

Si invita il lettore a consultare la guida Java sui servlet. A tal fine è possibile avvalersi di Tomcat. Nella pagina iniziale di Tomcat 5 è presente un link [Documentation]:

Image

Questo link rimanda a una pagina che il lettore è invitato a esplorare. Il link alla documentazione sui servlet è il seguente:

Image

3.6.5. Test del servlet

Siamo pronti per eseguire un test. Avviamo il server Tomcat, se necessario.

Image

Quindi richiediamo con un browser l'URL URL [http://localhost:8080/personne/formulaire]. Qui richiediamo l'URL [/formulaire] del contesto [/personne]. Il file [web.xml] di questo contesto indica che l'URL [/formulaire] viene gestito dal servlet denominato [formulairepersonne]. Nello stesso file è indicato che tale servlet corrisponde alla classe [istia.st.servlets.ServletFormulaire]. È quindi a questa classe che Tomcat affiderà l'elaborazione della richiesta del client. Se la classe non fosse già caricata, verrà caricata. Rimarrà quindi in memoria per le richieste future.

Con il browser interno di Eclipse si ottiene il seguente risultato:

Image

Otteniamo i valori predefiniti per il nome e l’età, quelli riportati nel file [web.xml]. Richiediamo ora URL [http://localhost:8080/personne/formulaire?txtNom=tintin&txtAge=30]:

Image

Questa volta otteniamo i parametri passati nella richiesta. Se non si comprendono questi due risultati, si consiglia di rileggere il codice del servlet [ServletFormulaire].

3.6.6. Ricaricamento automatico del contesto dell’applicazione web

Avviamo Tomcat:

Image

quindi modifichiamo il codice del servlet come segue:

     // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // si recuperano i parametri del modulo
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = "--"+defaultNom+"--";
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
...
  • la riga 8 è stata modificata

Salviamo la nuova classe. Questo salvataggio comporterà, da parte di Eclipse, una ricompilazione automatica della classe [ServletFormulaire] che Tomcat rileverà. A questo punto ricaricherà il contesto dell’applicazione web [personne] per tenere conto delle modifiche. Ciò appare nei log della vista [console]:

Image

Proviamo a richiamare l’URL [http://localhost:8080/personne/formulaire] senza riavviare Tomcat:

Image

La modifica apportata è stata effettivamente applicata.

Ora modifichiamo il file [web.xml] nel modo seguente:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
...
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>INCONNU</param-value>
        </init-param>
...
    </servlet>
...
</web-app>
  • la riga 12 è stata modificata

Fatto ciò, salviamo il nuovo file [web.xml]. Nella vista [console], nessun log segnala il ricaricamento del contesto dell’applicazione. Richiediamo l’URL [http://localhost:8080/personne/formulaire] senza riavviare Tomcat:

Image

La modifica apportata non è stata presa in considerazione. Riavviamo Tomcat [clic droit sur serveur -> Restart -> Start]:

Image

quindi richiediamo nuovamente l’URL [http://localhost:8080/personne/formulaire]:

Image

Questa volta la modifica apportata in [web.xml] è visibile.

Una modifica a [web.xml] non provoca quindi un ricaricamento automatico dell’applicazione che tenga conto del nuovo file di configurazione. Per forzare il ricaricamento dell’applicazione web, è possibile riavviare Tomcat come abbiamo fatto, ma si tratta di un’operazione piuttosto lenta. È preferibile utilizzare lo strumento [manager] per la gestione delle applicazioni distribuite in Tomcat. Affinché ciò sia possibile, è necessario che all’interno di Eclipse Tomcat sia stato configurato come illustrato nel paragrafo 2.5.

Per prima cosa, con il browser interno di Eclipse, accediamo all’URL [http://localhost:8080], quindi seguiamo il link [Tomcat Manager], come spiegato alla fine del paragrafo 2.5:

Image

Apriamo un secondo browser [clic droit sur le navigateur -> New Editor]:

In questa seconda finestra del browser, inseriamo l'URL [http://localhost:8080/formulaire]:

Image

Modifichiamo il file [web.xml] come segue, quindi salviamolo:


<!--   ServletFormulaire -->
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>YYY</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>

Quindi richiediamo nuovamente l’URL [http://localhost:8080/formulaire]. Possiamo notare che la modifica non è stata applicata. Ora passiamo al primo browser e ricarichiamo l’applicazione [personne]:

Image

Quindi richiediamo nuovamente l’URL [http://localhost:8080/formulaire] con il secondo browser:

Image

La modifica di [web.xml] è stata applicata. In pratica, è utile avere un browser aperto sull’applicazione [manager] di Tomcat per gestire questo tipo di casi.

3.7. Interazione tra servlet e pagine JSP


Letture [ref1]: capitolo 2: 2.3.7


Torniamo alle due architetture esaminate:

Image

Nessuna di queste due architetture è soddisfacente. Entrambe presentano l'inconveniente di mescolare due tecnologie: quella della programmazione Java, che si occupa della logica dell'applicazione web, e quella della codifica HTML, che si occupa della presentazione delle informazioni in un browser.

  • La soluzione [1] basata su una pagina JSP presenta lo svantaggio di mescolare codice HTML e codice Java all’interno della stessa pagina. Non l’abbiamo riscontrato nell’esempio trattato, che era di base. Tuttavia, se [formulaire.jsp] avesse dovuto verificare la validità dei parametri [txtNom, txtAge] della richiesta del client, saremmo stati costretti a inserire codice Java nella pagina. La situazione diventerebbe ben presto ingestibile.
  • La soluzione [2] basata su servlet presenta lo stesso problema. Sebbene nella classe sia presente solo codice Java, questa deve generare un documento HTML. Anche in questo caso, a meno che il documento HTML non sia molto semplice, la sua generazione diventa complicata e quasi impossibile da mantenere.

Eviteremo la commistione tra le tecnologie Java e HTML adottando la seguente architettura:

Image

  • l’utente invia la propria richiesta al servlet. Quest’ultimo la elabora e costruisce i valori dei parametri dinamici della pagina JSP [formulaire.jsp] che servirà a generare la risposta HTML al cliente. Questi valori costituiscono il cosiddetto modello della pagina JSP.
  • Una volta terminato il proprio lavoro, il servlet richiederà alle pagine JSP e [formulaire.jsp] di generare la risposta HTML per il cliente. Contemporaneamente, fornirà al client gli elementi necessari alla pagina JSP per generare tale risposta, ovvero gli elementi che costituiscono il modello della pagina.

Esploriamo ora questa nuova architettura.

3.7.1. Il servlet [ServletFormulaire2]

Nell’architettura sopra descritta, il servlet si chiamerà [ServletFormulaire2]. Sarà realizzato nello stesso progetto [personne] di prima, così come tutti i servlet futuri:

Image

[ServletFormulaire2] si ottiene innanzitutto copiando e incollando [ServletFormulaire] all’interno di Eclipse:

  • selezionare [ServletFormulaire.java] -> clic con il tasto destro -> Copia
  • selezionare [istia.st.servlets.personne] -> clic destro -> Incolla -> rinominare in [ServletFormulaire2.java]

Successivamente, modifichiamo il codice di [ServletFormulaire2] nel modo seguente:

package istia.st.servlets.personne;

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ServletFormulaire2 extends HttpServlet {

     // parametri di istanza
    private String defaultNom = null;

    private String defaultAge = null;

     // inizializzazione
    public void init() {
         // si recuperano i parametri di inizializzazione del servlet
        ServletConfig config = getServletConfig();
        defaultNom = config.getInitParameter("defaultNom");
        if (defaultNom == null)
            defaultNom = "NNNNNNNNNNNNNNN";
        defaultAge = config.getInitParameter("defaultAge");
        if (defaultAge == null)
            defaultAge = "AAA";
    }

     // GET
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // si recuperano i parametri del modulo
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
         // si visualizza il modulo
        request.setAttribute("nom", nom);
        request.setAttribute("age", age);
        getServletContext().getRequestDispatcher("/formulaire2.jsp").forward(request, response);
    }

     // POST
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // si passa il controllo a GET
        doGet(request, response);
    }
}

È cambiata solo la parte relativa alla generazione della risposta HTTP (righe 44-46):

  • riga 46: la generazione della risposta viene affidata alla pagina JSP formulaire2.jsp. Quest'ultima, non ancora esaminata, avrà il compito di visualizzare i parametri recuperati dalla richiesta del cliente, ovvero un nome (righe 35-38) e un'età (righe 39-42).
  • Questi due valori vengono inseriti negli attributi della richiesta [request], associati a delle chiavi. Gli attributi di una richiesta sono gestiti come un dizionario.
  • riga 44: il nome viene inserito nella richiesta associato alla chiave "nome"
  • riga 45: l’età viene inserita nella query associata alla chiave «età»
  • riga 46: richiede la visualizzazione della pagina JSP [formulaire2.jsp]. A quest’ultima vengono passati come parametro:
  • la richiesta [request] del client, il che consentirà alla pagina JSP di accedere agli attributi di quest’ultima appena inizializzati dal servlet
  • la risposta [response], che consentirà alla pagina JSP di generare la risposta HTTP per il client

Una volta scritta la classe [ServletFormulaire2], il suo codice compilato appare in [build/classes]:

Image

3.7.2. La pagina JSP [formulaire2.jsp]

La pagina JSP formulaire2.jsp si ottiene copiando e incollando dalla pagina [formulaire.jsp]

Image

e successivamente modificata come segue:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    // si recuperano i valori necessari per la visualizzazione
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");  
%>

<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
      <title>Personne - formulaire2</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire2</h2>
      <hr>
      <form action="" method="post">
          <table>
            <tr>
              <td>Nom</td>
            <td><input name="txtNom" value="<%= nom %>" type="text" size="20"></td>
          </tr>
          <tr>
              <td>Age</td>
            <td><input name="txtAge" value="<%= age %>" type="text" size="3"></td>
          </tr>
        </table>
        <table>
            <tr>
              <td><input type="submit" value="Envoyer"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" value="Effacer"></td>
          </tr>
        </table>
      </form>
    </center>
  </body>
</html>

Rispetto a [formulaire.jsp] sono cambiate solo le righe da 4 a 8:

  • riga 6: recupera il valore dell'attributo denominato "nom" nella richiesta [request], attributo creato dal servlet [ServletFormulaire2].
  • riga 7: fa lo stesso per l’attributo “age”

3.7.3. Configurazione dell’applicazione

Il file di configurazione [web.xml] viene modificato come segue:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>personne</display-name>
    <!--  ServletFormulaire -->
    <servlet>
        <servlet-name>formulairepersonne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXXX</param-value>
        </init-param>
    </servlet>
     <!--  ServletFormulaire 2-->
    <servlet>
        <servlet-name>formulairepersonne2</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletFormulaire2
        </servlet-class>
        <init-param>
            <param-name>defaultNom</param-name>
            <param-value>inconnu</param-value>
        </init-param>
        <init-param>
            <param-name>defaultAge</param-name>
            <param-value>XXX</param-value>
        </init-param>
    </servlet>
    <!--  Mappatura ServletFormulaire -->
    <servlet-mapping>
        <servlet-name>formulairepersonne</servlet-name>
        <url-pattern>/formulaire</url-pattern>
    </servlet-mapping>
     <!--  Mappatura ServletFormulaire 2-->
    <servlet-mapping>
        <servlet-name>formulairepersonne2</servlet-name>
        <url-pattern>/formulaire2</url-pattern>
    </servlet-mapping>
    <!--  file di benvenuto -->
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Abbiamo mantenuto il codice esistente e aggiunto:

  • righe 22-36: una sezione <servlet> per definire il nuovo servlet ServletFormulaire2
  • righe 42-46: una sezione <servlet-mapping> per associarle il modulo URL /formulaire2

Avviare o riavviare il server Tomcat se necessario. Richiediamo il URL

http://localhost:8080/personne/formulaire2?txtNom=milou&txtAge=10:

Image

Otteniamo lo stesso risultato di prima, ma la struttura della nostra applicazione è ora più chiara: un servlet che contiene la logica applicativa e delega a una pagina JSP l'invio della risposta al cliente. D'ora in poi procederemo sempre in questo modo.