Skip to content

5. Applicazione web MVC [personne] – versione 1

5.1. Le viste dell’applicazione

L’applicazione riprende il modulo utilizzato negli esempi precedenti. La prima pagina dell’applicazione è la seguente:

Image

Chiameremo questa vista «[formulaire]». Se si effettuano inserimenti corretti, questi vengono visualizzati in una vista che chiameremo «[réponse]»:

Image

Se i dati inseriti non sono corretti, gli errori vengono segnalati in una vista denominata [erreurs]:

Image

5.2. Architettura dell’applicazione

L’applicazione web [personne1] avrà la seguente architettura:

Image

Si tratta di un'architettura a 1 livello: non sono presenti i livelli [métier] o [dao], ma solo il livello [web]. [ServletPersonne] è il controller dell'applicazione che gestisce tutte le richieste dei client. Per rispondere a tali richieste, utilizza una delle tre viste [formulaire, réponse, erreurs].

Dobbiamo determinare in che modo il controller [ServletPersonne] stabilisce l’azione da intraprendere alla ricezione di una richiesta da parte di un utente. Una richiesta del cliente è un flusso HTTP che varia a seconda che sia effettuata con un comando GET o POST.

Richiesta GET

In questo caso, il flusso HTTP si presenta come segue:

GET /URL HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0,5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
[ligne vide]

La riga 1 specifica l’URL richiesto, ad esempio:

GET /personne1/ HTTP/1.1

È possibile utilizzare questo URL per specificare l'azione da eseguire. Si possono utilizzare diversi metodi:

  1. un parametro dell'URL specifica l'azione, ad esempio [/appli?action=ajouter&id=4]. In questo caso, il parametro [action] indica al controller l'azione che gli viene richiesta.
  2. l'ultimo elemento dell'URL specifica l'azione, ad esempio [/appli/ajouter?id=4]. In questo caso, l'ultimo elemento dell'URL [/ajouter] viene utilizzato dal controller per determinare l'azione che deve eseguire.

Sono possibili altre soluzioni. Le due precedenti sono quelle più comuni.

Richiesta POST

In questo caso, il flusso HTTP è simile al seguente:

POST /URL HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: fr-fr,fr;q=0.8,en;q=0.6,en-us;q=0.4,de;q=0.2
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:8080/persona1/main
Cookie: JSESSIONID=9F5E5BFA29643FC6B1601EEED907E1F9
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
[ligne vide]
txtNom=&txtAge=&action=validationFormulaire

La riga 1 specifica l'URL richiesto, ad esempio:

POST /personne1/main HTTP/1.1

È possibile utilizzare questo URL per specificare l'azione da eseguire, come nel caso di GET. Nel caso di GET, il parametro [action] era integrato in URL. Ciò può verificarsi anche in questo caso, come in:

POST /appli?action=ajouter&id=4 HTTP/1.1

Ma il parametro [action] può essere incluso anche nei parametri inviati (riga 15 sopra) come in:

POST /appli HTTP/1.1
...
[ligne vide]
action=ajouter&id=4

Di seguito utilizzeremo queste diverse tecniche per indicare al controller cosa deve fare:

  • inserire il parametro action nell'URL richiesto:
POST /appli?action=ajouter&id=4 HTTP/1.1
  • inviare il parametro action:
POST /appli HTTP/1.1
...
[ligne vide]
action=ajouter&id=4
  • utilizzare l'ultimo elemento dell'URL come nome dell'azione:
POST /appli/ajouter?id=4 HTTP/1.1

5.3. Il progetto Eclipse

Per creare il progetto Eclipse [mvc-personne-01] dell'applicazione web [personne1], seguire la procedura descritta al paragrafo 3.1.

Image

Non si manterrà il contesto [mvc-personne-01] proposto di default. Si sceglierà [personne1] come indicato di seguito:

Image

Il risultato ottenuto è il seguente:

Image

Se, per caso, si desidera modificare il contesto dell'applicazione web, si utilizzerà l'opzione [clic droit sur projet -> Properties -> J2EE]:

Image

Si indicherà il nuovo contesto in [1].

Creeremo una sottocartella [vues] all’interno della cartella [WEB-INF]: [clic droit sur WEB-INF -> New -> Folder]:

Il nuovo progetto è ora questo:

Image

Una volta completato, il progetto sarà il seguente:

Image

  • il controller [ServletPersonne] si trova nella cartella [src]
  • le pagine JSP delle viste [formulaire, réponse, erreurs] si trovano nella cartella [WEB-INF/vues], il che impedisce all'utente di richiederle direttamente, come mostra l'esempio qui sotto:

Image

Descriviamo ora i diversi componenti dell’applicazione web [/personne1]. Il lettore è invitato a crearli man mano che procede nella lettura.

5.4. Configurazione dell’applicazione web [personne1]

Il file web.xml dell’applicazione /personne1 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>mvc-personne-01</display-name>
    <!--  ServletPersonne -->
    <servlet>
        <servlet-name>personne</servlet-name>
        <servlet-class>
            istia.st.servlets.personne.ServletPersonne
        </servlet-class>
        <init-param>
            <param-name>urlReponse</param-name>
            <param-value>
                /WEB-INF/vues/reponse.jsp
            </param-value>
        </init-param>
        <init-param>
            <param-name>urlErreurs</param-name>
            <param-value>
                /WEB-INF/vues/erreurs.jsp
            </param-value>
        </init-param>
        <init-param>
            <param-name>urlFormulaire</param-name>
            <param-value>
                /WEB-INF/vues/formulaire.jsp
            </param-value>
        </init-param>
    </servlet>
    <!--  Mappatura ServletPersonne-->
    <servlet-mapping>
        <servlet-name>personne</servlet-name>
        <url-pattern>/main</url-pattern>
    </servlet-mapping>
    <!--  file di benvenuto -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Cosa dice questo file di configurazione?

  • righe 34-37: il file URL /main viene gestito dal servlet denominato «persona»
  • righe 10-13: il servlet denominato «personne» è un'istanza della classe [ServletPersonne]
  • righe 14-19: definiscono un parametro di configurazione denominato [urlReponse]. Si tratta dell'URL della vista [réponse].
  • righe 20-25: definiscono un parametro di configurazione denominato [urlErreurs]. Si tratta dell’URL della vista [erreurs].
  • righe 26-31: definiscono un parametro di configurazione denominato [urlFormulaire]. Si tratta dell'URL della vista [formulaire].
  • riga 40: [index.jsp] sarà la pagina iniziale dell'applicazione.

Gli URL delle pagine JSP delle viste [formulaire, réponse, erreurs] sono oggetto, ciascuno, di un parametro di configurazione. Ciò consente di spostarli senza dover ricompilare l’applicazione.

Quando l’utente richiederà l’URL [/personne1], sarà il file [index.jsp] a inviare la risposta (file di benvenuto, riga 40). Questo file si trova nella directory principale della cartella [WebContent]:

Image

Il suo contenuto è il 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">
<%
  response.sendRedirect("/personne1/main");
%>

La pagina [index.jsp] si limita a reindirizzare il client all’URL [/personne1/main]. Pertanto, quando il browser richiede l'URL [/personne1], [index.jsp] gli invia la seguente risposta HTTP:

1
2
3
4
5
6
7
HTTP/1.x 302 Déplacé Temporairement
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=9F5E5BFA29643FC6B1601EEED907E1F9; Path=/personne1
Location: http://localhost:8080/persona1/main
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 0
Date: Thu, 18 May 2006 15:45:23 GMT
  • riga 1: risposta HTTP/1.1 per indicare al server di reindirizzarsi verso un altro URL
  • riga 4: l'URL verso cui il browser deve essere reindirizzato

Dopo questa risposta, il browser richiederà quindi l'URL [/personne1/main] come gli è stato indicato (riga 4). Il file [web.xml] dell’applicazione [/personne1] indica che questa richiesta verrà gestita dal controller [ServletPersonne] (righe 35-36).

5.5. Il codice delle viste

Iniziamo a scrivere l’applicazione web partendo dalle sue viste. Queste consentono di definire le esigenze dell’utente in termini di interfaccia grafica e possono essere testate senza la presenza del controller.

5.5.1. La vista [formulaire]

Questa vista corrisponde al modulo per l’inserimento del nome e dell’età:

Image

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

Viene generata dalla pagina JSP [formulaire.jsp]. Il suo modello è costituito dai seguenti elementi:

  • [nom]: un nome (String) presente negli attributi di sessione associati alla chiave "nom"
  • [age]: un'età (String) presente negli attributi di sessione associati alla chiave "age"

La vista [formulaire] viene ottenuta quando l'utente richiede l'URL [/personne1/main], c.a.d. L'URL del controller è [ServletPersonne]. Il codice della pagina JSP [formulaire.jsp] che genera la vista [formulaire] è il 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 dati dal modello
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
    
<html>
    <head>
      <title>Personne - formulaire</title>
  </head>
  <body>
      <center>
        <h2>Personne - formulaire</h2>
      <hr>
      <form 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>
            <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>
        <input type="hidden" name="action" value="validationFormulaire"> 
      </form>
    </center>
  </body>
</html>

  • righe 6-7: la pagina JSP inizia recuperando dalla richiesta [request] gli elementi [nom, age] del proprio modello. Nel normale funzionamento dell’applicazione, sarà il controller [ServletPersonne] a costruire questo modello.
  • righe 18-38: la pagina JSP genererà un modulo HTML (tag <form>)
  • riga 18: il tag <form> non presenta l'attributo action per indicare l'URL che dovrà elaborare i valori inviati tramite il pulsante [Envoyer] di tipo submit (riga 32). I valori del modulo verranno quindi inviati all'URL da cui è stato ottenuto il modulo, ovvero l'URL del controller [ServletPersonne]. Pertanto, quest’ultimo viene utilizzato sia per generare il modulo vuoto richiesto inizialmente da un GET, sia per elaborare i dati inseriti che gli verranno inviati tramite il pulsante [Envoyer].
  • I valori inviati sono quelli dei campi HTML, [txtNom] (riga 22), [txtAge] (riga 26) e [action] (riga 37). Quest’ultimo parametro consentirà al controllore di sapere cosa deve fare.
  • Alla visualizzazione iniziale del modulo, i campi di immissione [txtNom, txtAge] vengono inizializzati rispettivamente con le variabili [nom] (riga 22) e [age] (riga 26). Queste variabili ottengono i valori dei propri attributi dalla richiesta (righe 6-7), attributi che, come sappiamo, vengono inizializzati dal servlet. È quindi quest’ultimo a determinare il contenuto iniziale dei campi di immissione del modulo.
  • riga 33: il pulsante [Rétablir] di tipo [reset] consente di riportare il modulo allo stato in cui si trovava quando è stato ricevuto dal browser.
  • riga 34: il pulsante [Effacer] di tipo [reset] non ha, per il momento, alcuna funzione.

In seguito, chiameremo questa vista «vista [formulaire(nom, age)]» quando vorremo specificare sia il nome della vista che il suo modello. Inoltre, ricordiamo che quando l’utente clicca sul pulsante [Envoyer], i parametri [txtNom, txtAge] vengono inviati all’URL [/personne1/main].

5.5.2. La vista [reponse]

Questa vista visualizza i valori inseriti nel modulo quando questi sono validi:

Image

Viene generata dalla pagina JSP [reponse.jsp]. Il suo modello è costituito dai seguenti elementi:

  • [nom]: un nome (String) che si troverà negli attributi di sessione, associato alla chiave "nom"
  • [age]: un'età (String) che si troverà negli attributi di sessione, associata alla chiave "età"

Il codice della pagina JSP [reponse.jsp] è il 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 dati dal modello
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Personne - réponse</h2>
    <hr>
    <table>
        <tr>
          <td>Nom</td>
        <td><%= nom %>
      </tr>
        <tr>
          <td>Age</td>
        <td><%= age %>
      </tr>
    </table>      
  </body>
</html>

  • righe 6-7: la pagina JSP inizia recuperando dalla richiesta [request] gli elementi [nom, age] del proprio modello. Nel normale funzionamento dell’applicazione, sarà il controller [ServletPersonne] a costruire questo modello.
  • Gli elementi [nom, age] del modello vengono quindi visualizzati alle righe 20 e 24

Successivamente, chiamiamo questa vista «[réponse(nom, age)]».

5.5.3. La vista [erreurs]

Questa vista segnala gli errori di inserimento nel modulo:

Image

Viene generata dalla pagina JSP [erreurs.jsp]. Il suo modello è costituito dai seguenti elementi:

  • [erreurs]: un elenco (ArrayList) di messaggi di errore che si troverà negli attributi della richiesta, associato alla chiave "errori"

Il codice della pagina JSP [erreurs.jsp] è il 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">
<%@ page import="java.util.ArrayList" %>

<%
// si recuperano i dati dal modello
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Les erreurs suivantes se sont produites</h2>
    <ul>
        <%
          for(int i=0;i<erreurs.size();i++){
            out.println("<li>" + (String) erreurs.get(i) + "</li>\n");
        }//per
      %>
    </ul>
  </body>
</html>

  • riga 8: la pagina JSP inizia recuperando dalla richiesta [request] l’elemento [erreurs] del proprio modello. Questo elemento rappresenta un oggetto di tipo ArrayList composto da elementi di tipo String. Questi elementi sono messaggi di errore. Nel normale funzionamento dell’applicazione, sarà il controller [ServletPersonne] a costruire questo modello.
  • righe 18-22: visualizzano l’elenco dei messaggi di errore. A tal fine, è necessario scrivere codice Java nel corpo HTML della pagina. Si deve sempre cercare di ridurlo al minimo per non appesantire il codice HTML. Vedremo in seguito che esistono soluzioni che consentono di ridurre la quantità di codice Java nelle pagine JSP.
  • riga 4: da notare il tag di importazione dei pacchetti necessari alla pagina JSP

Successivamente, chiameremo questa vista «[erreurs(erreurs)]».

5.6. Test delle viste

È possibile verificare la validità delle pagine JSP senza aver ancora scritto il controller. A tal fine sono necessarie due condizioni:

  • è necessario poterle richiedere direttamente all’applicazione senza passare attraverso il controller
  • la pagina JSP deve inizializzare autonomamente il modello che normalmente verrebbe costruito dal controller

Per eseguire questi test, duplichiamo le pagine JSP delle viste nella cartella [/WebContent/JSP] del progetto Eclipse:

Image

Quindi, nella cartella JSP, le pagine vengono modificate come segue:

[formulaire.jsp]:


...

<%
  // -- test: si crea il modello della pagina
  request.setAttribute("nom","tintin");
  request.setAttribute("age","30");
%>

<%
    // si recuperano i dati dal modello
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
    
<html>
    <head>
...

Le righe 3-7 sono state aggiunte per creare il modello necessario alla pagina delle righe 11-12.

[reponse.jsp]:


...

<%
  // -- test: si crea il modello della pagina
  request.setAttribute("nom","milou");
  request.setAttribute("age","10");
%>

<%
    // si recuperano i dati dal modello
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

    
<html>
    <head>
...

Le righe 3-7 sono state aggiunte per creare il modello richiesto dalla pagina alle righe 11-12.

[erreurs.jsp]:


...

<%
  // -- test: si crea il modello della pagina
  ArrayList<String> erreurs1=new ArrayList<String>();
  erreurs1.add("erreur1");
  erreurs1.add("erreur2");
  request.setAttribute("erreurs",erreurs1);
%>

<%
// si recuperano i dati dal modello
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

    
<html>
    <head>
...

Le righe da 3 a 9 sono state aggiunte per creare il modello necessario alla pagina della riga 13.

Avvia Tomcat, se non l’hai già fatto, quindi richiedi i seguenti URL:

 

Otteniamo effettivamente le visualizzazioni previste. Ora che abbiamo una ragionevole fiducia nelle pagine JSP dell'applicazione, possiamo passare alla scrittura del relativo controller [ServletPersonne].

5.7. Il controller [ServletPersonne]

Resta da scrivere il cuore della nostra applicazione web, il controller. Il suo ruolo consiste nel:

  • recuperare la richiesta del client,
  • elaborare l’azione richiesta dal cliente,
  • inviare in risposta la vista appropriata.

Il controller [ServletPersonne] gestirà le seguenti azioni:

n.
richiesta
origine
elaborazione
1
[GET /personne1/main]
URL digitato dall'utente
- inviare la vista [formulaire] vuota
2
[POST /personne1/main]
con parametri [txtNom,
txtAge, azione] pubblicati
cliccando sul pulsante
[Envoyer] della vista
[formulaire]
- verificare i valori dei parametri [txtNom, txtAge]
- se non sono corretti, inviare la vista [erreurs(erreurs)]
- se sono corretti, inviare la vista [reponse(nom,age)]

L'applicazione si avvia quando l'utente richiede l'URL [/personne1/main]. In base al file [web.xml] dell'applicazione (cfr. paragrafo 5.4), questa richiesta viene elaborata da un'istanza di tipo ServletPersonne che descriviamo ora.

5.7.1. Struttura del controller

Il codice del controller [ServletPersonne] è il seguente:

package istia.st.servlets.personne;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

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 ServletPersonne extends HttpServlet {
...

     // inizializzazione
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
    }

    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
...
    }

     // visualizzazione della vista iniziale
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
...
    }

     // convalida del modulo
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
...
    }

     // invio
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // passaggio di controllo a GET
        doGet(request, response);
    }
}
  • righe 20-22: il metodo [init] eseguito al caricamento iniziale del servlet
  • righe 25-28: il metodo [doGet] chiamato dal server web quando viene effettuata una richiesta di tipo GET all’applicazione
  • righe 42-46: il metodo [doPost] viene chiamato dal server web quando viene inviata all’applicazione una richiesta di tipo POST. Come mostrato, anche questa verrà gestita dal metodo [doGet] (riga 45).
  • righe 31-33: il metodo [doInit] gestisce l’azione n. 1 [GET /personne1/main]
  • righe 36-39: il metodo [doValidationFormulaire] elabora l’azione n. 2 [POST /personne1/main] con i parametri inviati tramite POST [txtNom, txtAge, action].

Descriviamo ora i diversi metodi del controller

5.7.2. Inizializzazione del controller

Quando la classe del controller viene caricata dal contenitore di servlet, viene eseguito il suo metodo [init]. Ciò avverrà una sola volta. Una volta caricato in memoria, il controller vi rimarrà e gestirà le richieste dei diversi client. Ogni client è gestito da un thread di esecuzione e i metodi del controller vengono quindi eseguiti simultaneamente da thread diversi. Si ricorda che, per questo motivo, il controller non deve avere campi che i suoi metodi potrebbero modificare. I suoi campi devono essere di sola lettura. Essi vengono inizializzati dal metodo [init], il cui ruolo principale è proprio questo. Questo metodo ha infatti la particolarità di essere eseguito una sola volta da un unico thread. Non sussistono quindi problemi di accesso concorrente ai campi del controller in questo metodo. Il metodo [init] ha lo scopo di inizializzare gli oggetti necessari all’applicazione web, che saranno condivisi in sola lettura da tutti i thread client. Questi oggetti condivisi possono essere collocati in due posizioni:

  • i campi privati del controller
  • il contesto di esecuzione dell’applicazione (ServletContext)

Il codice del metodo [init] del controller [ServletPersonne] è il seguente:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
     // parametri di istanza
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();

     // inizializzazione
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
         // si recuperano i parametri di inizializzazione del servlet
        ServletConfig config = getServletConfig();
         // si elaborano gli altri parametri di inizializzazione
        String valeur=null;
        for(int i=0;i<paramètres.length;i++){
             // valore del parametro
            valeur=config.getInitParameter(paramètres[i]);
             // il parametro è presente?
            if(valeur==null){
                 // si registra l'errore
                erreursInitialisation.add("Le paramètre ["+paramètres[i]+"] n'a pas été initialisé");
            }else{
                 // si memorizza il valore del parametro
                params.put(paramètres[i],valeur);
            }
             // l'URL della vista [erreurs] richiede un trattamento particolare
            urlErreurs = config.getInitParameter("urlErreurs");
            if (urlErreurs == null)
                throw new ServletException(
                        "Le paramètre [urlErreurs] n'a pas été initialisé");
        }
    }
...
}
  • riga 16: si recupera la configurazione dell’applicazione web, c.a.d. Il contenuto del file [web.xml]
  • righe 19-29: si recuperano i parametri di inizializzazione del servlet, i cui nomi sono definiti nella tabella [paramètres] alla riga 9
  • riga 21: viene recuperato il valore del parametro
  • riga 25: se il parametro è assente, l’errore viene aggiunto all’elenco degli errori [erreursInitialisation] inizialmente vuoto (riga 8).
  • riga 28: se il parametro è presente, viene memorizzato con il suo valore nel dizionario [params], inizialmente vuoto (riga 10).
  • righe 31-35: il parametro [urlErreurs] deve essere obbligatoriamente presente poiché indica l'URL della vista [erreurs] in grado di visualizzare eventuali errori di inizializzazione. Se non esiste, l’applicazione viene interrotta avviando una [ServletException] (riga 33).

5.7.3. Il metodo [doGet]

Il metodo [doGet] gestisce sia le richieste GET che quelle POST al servlet, poiché il metodo [doPost] rimanda al metodo [doGet]. Il suo codice è il seguente:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
     // parametri di istanza
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();

...
    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

         // si verifica l'esito dell'inizializzazione del servlet
        if (erreursInitialisation.size() != 0) {
             // si passa il controllo alla pagina degli errori
            request.setAttribute("erreurs", erreursInitialisation);
            getServletContext().getRequestDispatcher(urlErreurs).forward(
                    request, response);
             // fine
            return;
        }

         // si recupera il metodo di invio della richiesta
        String méthode=request.getMethod().toLowerCase();
         // si recupera l'azione da eseguire
        String action=request.getParameter("action");
         // azione?
        if(action==null){
            action="init";
        }
         // esecuzione dell'azione
        if(méthode.equals("get") && action.equals("init")){
             // avvio dell'applicazione
            doInit(request,response);
            return;
        }
        if(méthode.equals("post") && action.equals("validationFormulaire")){
             // convalida del modulo di inserimento dati
            doValidationFormulaire(request,response);
            return;
        }
         // altri casi
        doInit(request,response);
    }

     // invio
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // si passa il controllo a GET
        doGet(request, response);
    }
}
  • righe 18-25: si verifica che l'elenco degli errori di inizializzazione sia vuoto. In caso contrario, viene visualizzata la vista [erreurs(erreursInitialisation)] che segnalerà l'errore o gli errori.

Per comprendere questo codice, occorre ricordare il modello della vista [erreurs]:

<%
// si recuperano i dati dal modello
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

La vista [erreurs] richiede un elemento chiave "errori" nella richiesta. Il controller crea questo elemento alla riga 20.

  • riga 28: si recupera il metodo [get] o [post] che il cliente ha utilizzato per effettuare la richiesta
  • riga 30: si recupera il valore del parametro [action] della richiesta. Ricordiamo che nella nostra applicazione solo la richiesta n. 2 [POST /personne1/main] presenta il parametro [action]. In questa richiesta, il suo valore è [validationFormulaire].
  • righe 31-34: se il parametro [action] non è presente, gli viene assegnato il valore "init". Questo accadrà nella richiesta iniziale n. 1 [GET /personne1/main].
  • righe 36-40: elaborazione della richiesta n. 1 [GET /personne1/main].
  • righe 41-45: elaborazione della richiesta n. 2 [POST /personne1/main].
  • riga 47: se non ci si trova in uno dei due casi precedenti, si procede come se ci si trovasse nel caso n. 1

5.7.4. Il metodo [doInit]

Questo metodo elabora la richiesta n. 1 [GET /personne1/main]. Per questa richiesta, deve inviare la vista [formulaire(nom,age)] vuota. Il suo codice è il seguente:

package istia.st.servlets.personne;
...

@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
     // parametri di istanza
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();

...    
     // visualizzazione della vista iniziale
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // si invia il modulo vuoto
        request.setAttribute("nom", "");
        request.setAttribute("age", "");
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }
...
}
  • righe 18-19: viene visualizzata la vista [formulaire]. Ricordiamo il modello previsto da questa vista:

<%
    // si recuperano i dati dal modello
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
  • righe 16-17: il modello [nom,age] della vista [formulaire] viene inizializzato con stringhe vuote.

5.7.5. Il metodo [doValidationFormulaire]

Questo metodo elabora la richiesta n. 2 [POST /personne1/main] in cui i parametri inviati sono [action, txtNom, txtAge]. Il suo codice è il seguente:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
     // parametri di istanza
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();
...
     // convalida del modulo
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
         // si recuperano i parametri
        String nom = request.getParameter("txtNom");
        String age = request.getParameter("txtAge");
         // verifica dei parametri
        ArrayList<String> erreursAppel = new ArrayList<String>();
         // il nome non deve essere vuoto
        nom = nom.trim();
        if (nom.equals(""))
            erreursAppel.add("Le champ [nom] n'a pas été rempli");
         // l'età deve essere un numero intero >=0
        if (!age.matches("^\\s*\\d+\\s*$"))
            erreursAppel.add("Le champ [age] est erroné");
         // Ci sono errori nei parametri?
        if (erreursAppel.size() != 0) {
             // viene inviata la pagina degli errori
            request.setAttribute("erreurs", erreursAppel);
            getServletContext().getRequestDispatcher(urlErreurs).forward(request, response);
            return;
        }
         // i parametri sono corretti - si invia la pagina di risposta
        request.setAttribute("nom", nom);
        request.setAttribute("age", age);
        getServletContext().getRequestDispatcher((String)params.get("urlReponse")).forward(request,
                response);
        return;
    }
...
}
  • righe 16-17: si recuperano dalla richiesta del cliente i valori dei parametri "txtNom" e "txtAge".
  • righe 19-26: viene verificata la validità di questi due parametri
  • righe 28-33: se uno dei parametri è errato, viene visualizzata la vista [erreurs(erreursAppel)]. Ricordiamo il modello di questa vista:

<%
// si recuperano i dati dal modello
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>
  • righe 35-38: se i due parametri "txtNom" e "txtAge" recuperati hanno valori validi, viene visualizzata la vista [reponse(nom,age)]. È necessario ricordare il modello della vista [reponse]:

<%
    // si recuperano i dati dal modello
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

5.8. Tests

Includiamo il progetto [mvc-personne-01] nelle applicazioni di Tomcat seguendo la procedura descritta nel paragrafo 3.3:

Image

Avviare Tomcat. Una volta fatto ciò, sarà possibile riprendere i test illustrati a titolo di esempio nel paragrafo 5.1. Sarà possibile aggiungerne altri. Ad esempio, è possibile rimuovere uno dei parametri di configurazione urlXXX da web.xml e osservare il risultato. Come illustrato di seguito, uno dei parametri è stato messo tra commenti in [web.xml]:


        <!-- 
            <init-param>
              <param-name>urlFormulaire</param-name>
              <param-value>
                /WEB-INF/vues/formulaire.jsp
              </param-value>
            </init-param>
        -->

Si avvia o si riavvia Tomcat e si richiede l'URL [http://localhost:8080/personne1/main]. Si ottiene la seguente risposta:

Image