Skip to content

3. Nozioni di base sullo sviluppo web in Java

Discuteremo ora dello sviluppo di applicazioni web dinamiche, ovvero applicazioni in cui le pagine HTML inviate all'utente sono generate da programmi.

3.1. Creazione di un progetto web in Eclipse

Svilupperemo la nostra prima applicazione web utilizzando Eclipse/Tomcat. Seguiremo un processo simile a quello utilizzato per creare un'applicazione web senza Eclipse. Con Eclipse in esecuzione, 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 dell'applicazione [3]:

Image

Una volta confermata la procedura guidata cliccando su [Fine], Eclipse si connette al sito [http://java.sun.com] per recuperare alcuni documenti che desidera memorizzare nella cache al fine di evitare traffico di rete superfluo. Viene quindi richiesto un accordo di licenza:

Image

Lo accettiamo. Eclipse crea il progetto web. Per visualizzarlo, utilizza un ambiente, chiamato prospettiva, diverso da quello utilizzato per un progetto Java tradizionale:

Image

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

Image

La prospettiva J2EE è in realtà inutilmente complessa per semplici progetti web. In questo caso, la prospettiva Java è sufficiente. Per accedervi, utilizziamo l'opzione [Finestra -> Apri prospettiva -> Java]:

Image

src: conterrà il codice Java per le classi dell'applicazione, nonché i file che devono trovarsi nel classpath dell'applicazione.

build/classes (non mostrata): conterrà i file .class delle classi compilate, oltre a una copia di tutti i file non .java presenti in src. Un'applicazione web utilizza spesso i cosiddetti file "risorsa" che devono trovarsi nel classpath dell'applicazione, ovvero l'insieme di directory che la JVM cerca quando l'applicazione fa riferimento a una classe, sia durante la compilazione che in fase di esecuzione. Eclipse garantisce che la directory build/classes faccia parte del classpath web. I file "risorsa" vengono collocati nella cartella src, sapendo che Eclipse li copierà automaticamente in build/classes.

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

WEB-INF/lib: contiene i file .jar richiesti dall'applicazione web.

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


<?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 di benvenuto nella Sezione 2.3.4. Questo file non fa altro che definire una serie di pagine di benvenuto. Ne manteniamo 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 specificato dall'attributo [xsi:schemaLocation] del tag di apertura <web-app>. Tale file si trova all'indirizzo [http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd]. Si tratta di un file XML a cui è possibile accedere direttamente tramite un browser web. Se il browser è abbastanza recente, sarà in grado di visualizzare un file XML:

Image

Eclipse tenterà di convalidare il documento XML utilizzando il file .xsd specificato nell'attributo [xsi:schemaLocation] del tag di apertura <web-app>. A tal fine, effettuerà una richiesta di rete. Se il tuo computer si trova su una rete privata, devi indicare a Eclipse quale macchina utilizzare per uscire dalla rete privata, ovvero un proxy HTTP. Questa operazione si effettua tramite l'opzione [Finestra -> Preferenze -> Internet]:

Image

Selezionare la casella (1) se ci si trova su una rete privata. In (2), inserire il nome del computer che ospita il proxy HTTP e in (3) la sua porta di ascolto. Infine, in (4), specificare i computer che devono bypassare il proxy, ovvero quelli che si trovano sulla stessa rete privata del computer su cui si sta lavorando.

Ora creeremo il file [index.html] per la pagina iniziale.

3.2. Creazione di una home page

Fai clic con il pulsante destro del mouse sulla cartella [WebContent] e seleziona [Nuovo -> Altro]:

Image

Selezionare il tipo [HTML] e fare clic su [Avanti] ->

Image

In alto, selezionare la cartella principale [WebContent] in (1) o (2), quindi specificare il nome del file da creare in (3). Una volta fatto ciò, passare alla pagina successiva della procedura guidata:

Image

Con (1), possiamo generare un file HTML precompilato con (2). Se deselezioniamo (1), generiamo un file HTML vuoto. Lasciamo (1) selezionato per beneficiare di un modello di codice. Completiamo la procedura guidata cliccando su [Fine]. 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. Verifica della pagina iniziale

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

Image

L'opzione [Aggiungi e rimuovi oggetti] in alto consente di aggiungere o rimuovere applicazioni web dal server Tomcat:

Image

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

Image

quindi completare la procedura guidata di registrazione facendo clic su [Fine]. La vista [Server] mostra che il progetto [person] è stato registrato su Tomcat:

Image

Ora avviamo il server Tomcat:

Avvia il browser web:

Image

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

Image

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

Image

L'applicazione web [person] è quindi accessibile anche al di fuori di Eclipse.

3.4. Creazione di un modulo HTML

Ora creeremo un documento HTML statico [form.html] nella cartella [person]:

Image

Per crearlo, seguire la procedura descritta nella sezione 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 sottostante:

Image

No.
Tipo HTML
nome
Codice HTML
ruolo
1
<input type="text">
txtName
riga 14
inserisci nome
2
<input type="text">
txtEtà
riga 18
campo età
3
<input type="submit">
 
riga 23
Invia i valori inseriti al server all'URL /person1/main
4
<input type="reset">
 
riga 24
per riportare la pagina allo stato in cui era stata inizialmente ricevuta dal browser
5
<input type="button">
 
riga 25
per cancellare il contenuto dei campi di immissione [1] e [2]

Salviamo il documento nella cartella <person>/WebContent. Avviamo Tomcat se necessario. Utilizzando un browser, accediamo all'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 raffigurato qui. [formulaire.html] è un documento statico che restituisce lo stesso contenuto per ogni richiesta del client. La programmazione web mira a generare contenuti su misura per la richiesta del client. Questo contenuto viene quindi generato a livello di programmazione. Una soluzione consiste nell'utilizzare una JSP (Java Server Page) al posto del file HTML statico. È proprio questo che esamineremo ora.

3.5. Creazione di una pagina JSP


Letture [rif1]: 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 è un tipo di pagina HTML parametrizzata. Alcuni elementi della pagina ricevono i propri valori solo in fase di esecuzione. Questi valori vengono calcolati dal programma. Abbiamo quindi una pagina dinamica: richieste successive alla pagina possono produrre risposte diverse. In questo contesto, ci riferiamo alla pagina HTML visualizzata dal browser del client come alla risposta. In definitiva, 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 loro valori effettivi al momento della generazione del documento HTML.

Per creare una pagina JSP, fare clic con il tasto destro del mouse sulla cartella [WebContent] e selezionare l'opzione [Nuovo -> Altro]:

Image

Selezioniamo il tipo [JSP] e facciamo clic su [Avanti] ->

Image

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

Image

Con (1), possiamo generare un file JSP precompilato con (2). Se deselezioniamo (1), generiamo un file JSP vuoto. Lasciamo (1) selezionato per beneficiare di un modello di codice. Completiamo la procedura guidata cliccando su [Fine]. 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 abbiamo a che fare con una pagina JSP. Trasformiamo il testo sopra riportato 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">
<%
    // on récupère les paramètres
  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'introduzione del 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. Questo oggetto rappresenta la richiesta del client. Potrebbe essere passato attraverso diversi servlet e pagine JSP che potrebbero averlo arricchito. In questo caso, proviene direttamente dal browser.
  • Segue il codice HTML. Di solito visualizzerà semplicemente le variabili precedentemente calcolate nel codice Java utilizzando i tag <%= variabile %>. Si noti qui che il segno = si trova proprio accanto al segno %. Questa è una causa comune di errori.

Cosa fa il documento dinamico precedente?

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

Eseguiamo un test iniziale. Avvia Tomcat se necessario, quindi utilizza un browser per richiedere l'URL http://localhost:8080/personne/formulaire.jsp:

Image

Il documento form.jsp è stato richiamato senza passare alcun parametro. Sono stati quindi visualizzati i valori predefiniti. Ora richiediamo l'URL http://localhost:8080/personne/formulaire.jsp?txtNom=martin&txtAge=14:

Image

Questa volta abbiamo passato i parametri txtNom e txtAge alla pagina form.jsp, come da essa previsto. La pagina li ha quindi visualizzati. Sappiamo che esistono due metodi per passare parametri a una pagina web: GET e POST. In entrambi i casi, i parametri passati vengono memorizzati nell'oggetto request predefinito. In questo caso, sono stati passati utilizzando il metodo GET.

3.6. Creazione di un servlet


Letture [rif1]: Capitolo 1, Capitolo 2: 2.1, 2.1.1, 2.1.2, 2.3.1


Nella versione precedente, la richiesta del client veniva gestita da una pagina JSP. Al primo accesso a questa pagina, il server web — in questo caso, Tomcat — crea una classe Java dalla pagina 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 gestita da qualsiasi classe che implementi questa interfaccia. Ora creeremo una classe di questo tipo: ServletFormulaire. La precedente architettura client/server viene trasformata come segue:

Image

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

3.6.1. Creazione del servlet

In Eclipse, fare clic con il tasto destro sulla cartella [src] e selezionare l'opzione per creare una classe:

Image

quindi definire le caratteristiche della classe da creare:

Image

Nel campo (1) inserire il nome del pacchetto; nel campo (2) inserire il nome della classe da creare. Questa classe deve estendere la classe specificata nel campo (3). Non è necessario digitare manualmente il nome completo della classe. Il pulsante (4) consente di accedere alle classi attualmente presenti nel classpath dell'applicazione web:

Image

In (1), digitare il nome della classe che si sta cercando. In (2), verranno visualizzate le classi nel Classpath i cui nomi contengono la stringa digitata in (1).

Dopo aver confermato la procedura guidata di creazione, il progetto web [person] viene modificato come segue:

Image

La classe [ServletFormulaire] è stata creata con uno scheletro di codice:

Image

La schermata sopra mostra che Eclipse visualizza un [avviso] sulla riga che dichiara la classe. Fare clic sull'icona (lampadina) che indica questo [avviso]:

Image

Dopo aver cliccato su (1), in (2) vengono suggerite delle soluzioni per rimuovere l'[avviso]. Selezionandone una, in (3) appare 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 ora potrebbe generare [avvisi]. Questi non indicano errori che impedirebbero la compilazione della classe. Sono presenti per richiamare l'attenzione dello sviluppatore su aree del codice che potrebbero essere migliorate. L'attuale [avviso] indica che una classe dovrebbe avere un numero di versione. Questo viene utilizzato per la serializzazione/deserializzazione degli oggetti, ovvero quando un oggetto Java .class in memoria deve essere convertito in una sequenza di bit inviati in modo sequenziale in un flusso di scrittura, o il contrario quando un oggetto Java .class in memoria deve essere creato da una sequenza di bit letti in modo sequenziale in un flusso di lettura. Tutto questo è ben lontano dalle nostre attuali preoccupazioni. Chiederemo quindi al compilatore di ignorare questo avviso selezionando l'opzione [Add @SuppressWarnings ...]. Il codice diventa quindi il seguente:

Image

Non ci sono più [avvisi]. La riga aggiunta è chiamata "annotazione", un concetto introdotto in Java 1.5. Completeremo questo codice in seguito.

3.6.2. Classpath di un progetto Eclipse

Il classpath di un'applicazione Java è l'insieme di cartelle e file .jar in cui si effettua la ricerca quando il compilatore la compila o quando la JVM la esegue. Questi due classpath non sono necessariamente identici, poiché alcune classi sono necessarie solo in fase di esecuzione e non durante la compilazione. Sia il compilatore Java che la JVM dispongono di un argomento che consente di specificare il classpath dell'applicazione da compilare o eseguire. In un modo più o meno trasparente per l'utente, Eclipse gestisce la costruzione e il passaggio di questo argomento alla JVM.

Come è possibile determinare gli elementi del classpath di un progetto Eclipse? Utilizzando l'opzione [<progetto> / Build Path / Configure Build Path]:

Image

Viene visualizzata la seguente procedura guidata di configurazione:

Image

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

Sopra compaiono tre librerie:

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

Image

  • [Runtime Tomcat v5.5]: una libreria fornita dal server Tomcat. Contiene le classi necessarie per lo sviluppo web. Questa libreria è inclusa in qualsiasi progetto web Eclipse che sia stato associato al server Tomcat.

Image

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

Image

Se così non fosse stato, non sarebbe apparsa tra i suggerimenti in [2]. Pertanto, se in questa procedura guidata si desidera fare riferimento a una classe padre e questa non viene suggerita, significa che o si è digitato in modo errato il nome della classe, oppure che l’archivio che la contiene non si trova nel classpath dell’applicazione.

  • [Librerie app Web] contiene gli archivi situati nella cartella [WEB-INF/lib] del progetto. Qui è vuoto:

Image

Gli archivi nel classpath del progetto Eclipse sono visibili nell'esploratore di progetto. Ad esempio, per il progetto web [person]:

Image

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

Image

Come mostrato sopra, possiamo vedere che l'archivio [servlet-api.jar] contiene la classe [javax.servlet.http.HttpServlet].

3.6.3. Configurazione del servlet


Letture [rif1]: 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

Per il progetto [person], questo file attualmente ha questo aspetto (vedi 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]
  • gli URL gestiti da questo servlet
  • i parametri di inizializzazione del servlet

Il file web.xml della nostra applicazione 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 7–24 riguardano la presenza del servlet [ServletFormulaire]
  • Righe 7–20: un servlet è configurato tra i tag <servlet> e </servlet>. Un'applicazione può contenere più servlet e quindi più 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> specifica il nome completo della classe del servlet. Tomcat cercherà questa classe nel classpath del progetto web [personne]. La troverà in [build/classes]:

Image

  • Righe 12–15: Il tag <init-param> viene utilizzato per passare i parametri di configurazione al servlet. Questi vengono generalmente letti nel metodo init del servlet perché i suoi parametri di configurazione devono essere noti non appena viene caricato per la prima volta.
  • Righe 13–14: il tag <param-name> imposta il nome del parametro e <param-value> ne imposta il valore.
  • Le righe 12–15 definiscono un parametro [defaultName, "unknown"], mentre le righe 16–19 definiscono un parametro [defaultAge, "XXX"]
  • Righe 21–24: il tag <servlet-mapping> viene utilizzato per associare un servlet (servlet-name) a un modello di URL (url-pattern). In questo caso, il modello è semplice. Specifica che ogni volta che un URL assume la forma /formulaire, deve essere utilizzato il servlet formulairepersonne, ovvero la classe [istia.st.servlets.ServletFormulaire] (righe 8–11). Pertanto, solo un URL è accettato dal servlet [formulairepersonne].

3.6.4. Il codice per il 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 {

    // instance parameters
    private String defaultNom = null;
    private String defaultAge = null;

    // init
    public void init() {
        // retrieve servlet initialization parameters
        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 {

        // retrieve the form parameters
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
        // the form is displayed
        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 {
        // we hand over to GET
        doGet(request, response);
    }
}

Basta leggere il servlet per rendersi conto che è molto più complesso della corrispondente pagina JSP. Questa è una regola generale: un servlet non è adatto alla generazione di codice HTML. Le pagine JSP sono progettate proprio per questo scopo. Avremo modo di tornare su questo argomento più avanti. Chiariamo alcuni punti importanti riguardo al servlet sopra riportato:

  • Quando un servlet viene chiamato per la prima volta, viene chiamato il suo metodo init (riga 20). Questa è l'unica volta in cui viene chiamato.
  • Se il servlet è stato chiamato tramite il metodo HTTP GET, viene chiamato il metodo doGet (riga 32) per elaborare la richiesta del client.
  • Se il servlet è stato chiamato tramite il metodo HTTP POST, viene chiamato il metodo doPost (riga 82) per elaborare la richiesta del client.

Il metodo init viene utilizzato in questo caso per recuperare i valori dei parametri di inizializzazione denominati "defaultName" e "defaultAge" dal file [web.xml]. Il metodo init, eseguito al primo caricamento del servlet, è il punto appropriato 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, recuperiamo il valore String del parametro denominato "defaultName". Questo parametro conterrà il nome di una persona. Se non esiste, il valore sarà nullo.
  • Righe 24–25: Se il parametro denominato "defaultName" non esiste, alla variabile [defaultName] viene assegnato un valore predefinito.
  • Righe 26–29: Facciamo lo stesso per il parametro denominato "defaultAge".

Il metodo doPost fa riferimento al metodo doGet. Ciò significa che il client può inviare i propri parametri utilizzando una richiesta POST o una richiesta GET.

Il metodo doGet:

  • Riga 32: Il metodo riceve due parametri, `request` e `response`. `request` è un oggetto che rappresenta l'intera richiesta del client. È di tipo `HttpServletRequest`, che è un'interfaccia. `response` è di tipo `HttpServletResponse`, che è anch'essa un'interfaccia. L'oggetto `response` viene utilizzato per inviare una risposta al client.
  • request.getParameter("param") viene utilizzato per recuperare il valore del parametro denominato "param" dalla richiesta del client. Alla riga 36, recuperiamo il valore del parametro "txtNom"; alla riga 40, quello del parametro "txtAge". Se questi parametri non sono presenti nella richiesta, il valore del parametro viene impostato su null.
  • 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 viene fatto nelle righe 41–43 per l'età.
  • Riga 45: response.setContentType(String) viene utilizzato per 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() viene utilizzato per ottenere un flusso di scrittura verso il client
  • Righe 47–78: il documento HTML da inviare al client viene scritto nel flusso di scrittura ottenuto alla riga 46.

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

Image

Si invitano i lettori a consultare la documentazione Java sui servlet. A questo scopo è possibile utilizzare Tomcat. Nella home page di Tomcat 5 è presente un link [Documentazione]:

Image

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

Image

3.6.5. Testare il servlet

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

Image

Quindi, utilizzando un browser, richiedere l'URL [http://localhost:8080/personne/formulaire]. In questo caso, stiamo richiedendo l'URL [/form] dal contesto [/person]. Il file [web.xml] per questo contesto specifica che l'URL [/form] è gestito dal servlet denominato [formperson]. Nello stesso file, è specificato che questo servlet è la classe [istia.st.servlets.ServletFormulaire]. Tomcat affiderà quindi a questa classe l'elaborazione della richiesta del client. Se la classe non era già stata caricata, verrà caricata. Rimarrà quindi in memoria per le richieste future.

Otteniamo il seguente risultato utilizzando il browser integrato in Eclipse:

Image

Otteniamo i valori predefiniti per nome ed età, come specificato nel file [web.xml]. Ora richiediamo l'URL [http://localhost:8080/personne/formulaire?txtNom=tintin&txtAge=30]:

Image

Questa volta, otteniamo i parametri passati nella richiesta. Il lettore è invitato a rivedere il codice del servlet [ServletFormulaire] se non comprende questi due risultati.

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 {

        // retrieve the form parameters
        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 attiverà una ricompilazione automatica della classe [ServletFormulaire] da parte di Eclipse, che Tomcat rileverà. Ricaricherà quindi il contesto dell'applicazione web [personne] per riflettere le modifiche. Ciò appare nei log della vista [console]:

Image

Richiediamo l'URL [http://localhost:8080/personne/formulaire] senza riavviare Tomcat:

Image

La modifica è stata applicata con successo.

Ora modifichiamo il file [web.xml] 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>
    <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

Ora che abbiamo finito, salviamo il nuovo file [web.xml]. Nella vista [console], nessun log indica che il contesto dell'applicazione è stato ricaricato. Richiediamo l'URL [http://localhost:8080/personne/formulaire] senza riavviare Tomcat:

Image

La modifica non è stata applicata. Riavviamo Tomcat [clic destro sul server -> Riavvia -> Avvia]:

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 attiva automaticamente un ricaricamento dell'applicazione che incorpori il nuovo file di configurazione. Per forzare il ricaricamento dell'applicazione web, è possibile riavviare Tomcat come abbiamo fatto, ma si tratta di un processo piuttosto lento. È preferibile utilizzare lo strumento [manager] per l'amministrazione delle applicazioni distribuite in Tomcat. Affinché ciò funzioni, Tomcat deve essere stato configurato all'interno di Eclipse come mostrato nella Sezione 2.5.

Per prima cosa, utilizzando il browser interno di Eclipse, inserisci l'URL [http://localhost:8080] e poi segui il link [Tomcat Manager], come spiegato alla fine della Sezione 2.5:

Image

Apriamo un secondo browser [clic destro sul browser -> Nuovo editor]:

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

Image

Modifica il file [web.xml] come segue, quindi salvalo:


<!--  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 richiedi nuovamente l'URL [http://localhost:8080/formulaire]. Possiamo vedere che la modifica non è stata applicata. Ora, vai al primo browser e ricarica l'applicazione [person]:

Image

Quindi richiedere nuovamente l'URL [http://localhost:8080/formulaire] utilizzando il secondo browser:

Image

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

3.7. Interazione tra Servlet e pagine JSP


Letture [rif1]: Capitolo 2: 2.3.7


Torniamo alle due architetture che abbiamo esaminato:

Image

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

  • La soluzione basata su JSP [1] presenta l'inconveniente di mescolare codice HTML e codice Java all'interno della stessa pagina. Non l'abbiamo notato nell'esempio che abbiamo trattato, che era di base. Ma se [formulaire.jsp] dovesse convalidare i parametri [txtNom, txtAge] nella richiesta del client, saremmo stati costretti a inserire codice Java nella pagina. Questo diventa rapidamente ingestibile.
  • La soluzione [2], basata su un servlet, presenta lo stesso problema. Sebbene nella classe sia presente solo codice Java, essa deve generare un documento HTML. Anche in questo caso, a meno che il documento HTML non sia semplice, la sua generazione diventa complicata e quasi impossibile da mantenere.

Eviteremo di mescolare le tecnologie Java e HTML adottando la seguente architettura:

Image

  • L'utente invia la propria richiesta al servlet. Il servlet la elabora e costruisce i valori per i parametri dinamici della pagina JSP [form.jsp], che saranno utilizzati per generare la risposta HTML per il client. Questi valori formano quello che è noto come modello di pagina JSP.
  • Una volta completato il suo lavoro, il servlet chiederà alla pagina JSP [form.jsp] di generare la risposta HTML per il client. Allo stesso tempo, fornirà alla pagina JSP gli elementi necessari per generare questa risposta, ovvero gli elementi che compongono il modello della pagina.

Esploreremo ora questa nuova architettura.

3.7.1. Il servlet [ServletFormulaire2]

Nell'architettura sopra riportata, il servlet si chiamerà [ServletFormulaire2]. Verrà realizzato nello stesso progetto [personne] di prima, insieme a tutti i futuri servlet:

Image

[ServletFormulaire2] viene creato inizialmente copiando e incollando [ServletFormulaire] all'interno di Eclipse:

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

Quindi, modifichiamo il codice di [ServletFormulaire2] come segue:

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 {

    // instance parameters
    private String defaultNom = null;

    private String defaultAge = null;

    // init
    public void init() {
        // retrieve servlet initialization parameters
        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 {

        // retrieve the form parameters
        String nom = request.getParameter("txtNom");
        if (nom == null) {
            nom = defaultNom;
        }
        String age = request.getParameter("txtAge");
        if (age == null) {
            age = defaultAge;
        }
        // the form is displayed
        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 {
        // we hand over to GET
        doGet(request, response);
    }
}

È cambiata solo la parte che genera la risposta HTTP (righe 44–46):

  • Riga 46: La pagina JSP `formulaire2.jsp` è responsabile della generazione della risposta. Questa pagina, che non abbiamo ancora trattato, visualizzerà i parametri recuperati dalla richiesta del client: un nome (righe 35–38) e un'età (righe 39–42).
  • Questi due valori vengono inseriti negli attributi della richiesta, associati a delle chiavi. Gli attributi della richiesta sono gestiti come un dizionario.
  • Riga 44: Il nome viene inserito nella richiesta associato alla chiave "name"
  • Riga 45: L'età viene inserita nella richiesta associata alla chiave "age"
  • Riga 46: Richiede la visualizzazione della pagina JSP [formulaire2.jsp]. Le viene passato come parametro quanto segue:
  • la richiesta del client, che permette alla pagina JSP di accedere ai propri attributi appena inizializzati dal servlet
  • la risposta [response], che consentirà alla pagina JSP di generare la risposta HTTP al 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 viene creata copiando e incollando la 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">
<%
    // on récupère les valeurs nécessaire à l'affichage
  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 4–8:

  • riga 6: recupera il valore dell'attributo denominato "name" nella [richiesta], un 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>
    <!--  Mapping ServletFormulaire -->
    <servlet-mapping>
        <servlet-name>formulairepersonne</servlet-name>
        <url-pattern>/formulaire</url-pattern>
    </servlet-mapping>
    <!--  Mapping ServletFormulaire 2-->
    <servlet-mapping>
        <servlet-name>formulairepersonne2</servlet-name>
        <url-pattern>/formulaire2</url-pattern>
    </servlet-mapping>
    <!--  welcome files -->
    <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 associarlo all'URL /formulaire2

Avviare o riavviare il server Tomcat se necessario. Richiediamo l'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 il compito di inviare la risposta al client a una pagina JSP. D'ora in poi procederemo sempre in questo modo.