Skip to content

7. Applicazione web MVC [personne] – versione 3


Letture consigliate in [ref1]: capitolo 9


7.1. Introduction

Ci proponiamo di aggiungere codice JavaScript nelle pagine HTML inviate al browser. È quest’ultimo che esegue il codice JavaScript incorporato nella pagina che visualizza. Questa tecnologia è indipendente da quella utilizzata dal server web per generare il documento HTML (Java/servlet/JSP, ASP.NET, ASP, PHP, Perl, Python, ...).

[formulaire.jsp]

La visualizzazione risultante da questa pagina avrà il seguente aspetto:

Image

I pulsanti il cui testo è incorniciato utilizzano codice JavaScript incorporato nella pagina HTML:

Etichetta
Tipo HTML
Funzione
Submit
<submit>
svolge la funzione del pulsante [Envoyer] delle versioni precedenti: invia al controller i valori inseriti
[Envoyer]
<button>
nuovo pulsante – verifica localmente la validità dei dati inseriti prima di inviarli al controller
Rétablir
<reset>
ripristina il modulo allo stato in cui è stato inizialmente ricevuto dal browser
[Effacer]
<button>
cancella il contenuto dei due campi di immissione

Ecco un esempio di utilizzo dei pulsanti [Envoyer] e [Effacer]:

Utilizzeremo inoltre del codice JavaScript per gestire il collegamento [Retour au formulaire] delle viste [erreurs] e [réponse]. Prendiamo ad esempio la vista [réponse]:

1

La differenza sta nell’URL visualizzato in [1]. Nella versione precedente, era:

[http://localhost:8080/persona2/main?action=retourFormulaire]

In questo caso, l'azione non fa più parte dell'URL poiché verrà inviata tramite un POST anziché un GET. Questa modifica farà sì che l'unico URL visualizzato dal browser sarà [http://localhost:8080/personne3/main], indipendentemente dall'azione richiesta.

7.2. Il progetto Eclipse

Per creare il progetto Eclipse [mvc-personne-03] dell’applicazione web [/personne3], si duplicherà il progetto [mvc-personne-02] seguendo la procedura descritta al paragrafo 6.2, pagina 78.

7.3. Configurazione dell'applicazione web [personne3]

Il file web.xml dell’applicazione /personne3 è 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-03</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>
        <init-param>
            <param-name>lienRetourFormulaire</param-name>
            <param-value>
                Retour au formulaire
            </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>

Questo file è identico a quello della versione precedente, tranne che per alcuni dettagli:

  • riga 6: il nome visualizzato dell'applicazione web è cambiato in [mvc-personne-03]

Il parametro [urlControleur] è scomparso. Nella versione precedente serviva a impostare la destinazione del POST della vista [formulaire]. In questa nuova versione, la destinazione sarà la stringa vuota, c.a.d. L'URL visualizzato dal browser. Abbiamo spiegato che questo sarà sempre [http://localhost:8080/personne3/main], ovvero quello che ci serve per il POST della vista [formulaire].

La pagina iniziale [index.jsp] cambia:


<%@ 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("/personne3/main");
%>
  • riga 5: la pagina [index.jsp] reindirizza il client all'URL del controller [ServletPersonne] dell'applicazione [/personne3].

7.4. Il codice delle viste

7.4.1. La vista [formulaire]

Questa vista è diventata la seguente:

Image

Viene generata dalla pagina JSP [formulaire.jsp] 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) session.getAttribute("nom");
            String age = (String) session.getAttribute("age");
%>


<html>
  <head>
    <title>Personne - formulaire</title>
    <script language="javascript">
        // -------------------------------
        function effacer(){
          // si cancellano i campi di immissione
          with(document.frmPersonne){
            txtNom.value="";
            txtAge.value="";
          }//con
        }//cancellare
        // -------------------------------      
        function envoyer(){
          // verifica dei parametri prima dell'invio
          with(document.frmPersonne){
            // il nome non deve essere vuoto
            champs=/^\s*$/.exec(txtNom.value);
            if(champs!=null){
              // il nome è vuoto
              alert("Vous devez indiquer un nom");
              txtNom.value="";
              txtNom.focus();
              // ritorno all'interfaccia visiva
              return;
            }//if
             // l'età deve essere un numero intero positivo
            champs=/^\s*\d+\s*$/.exec(txtAge.value);
            if(champs==null){
              // l'età non è corretta
              alert("Age incorrect");
              txtAge.focus();
              // torna all'interfaccia visiva
              return;
            }//if
             // i parametri sono corretti - vengono inviati al server
            submit();
          }//con
        }//invia
      </script>
  </head>
  <body>
    <center>
      <h2>Personne - formulaire</h2>
      <hr>
      <form name="frmPersonne" 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="Submit"></td>
            <td><input type="button" value="[Envoyer]" onclick="envoyer()"></td>
            <td><input type="reset" value="Rétablir"></td>
            <td><input type="button" value="[Effacer]" onclick="effacer()"></td>
          </tr>
        </table>
        <input type="hidden" name="action" value="validationFormulaire">
      </form>
    </center>
  </body>
</html>


Novità:

  • riga 56: il modulo ha il nome [frmPersonne]. Questo nome verrà utilizzato nel codice JavaScript. Si noti l’assenza dell’attributo [action], il che fa sì che il modulo [frmPersonne] venga inviato all’URL visualizzato dal browser.
  • riga 70: il pulsante [Submit] svolge la funzione del pulsante [Envoyer] delle versioni precedenti
  • riga 71: cliccando sul pulsante [Envoyer] di tipo [Button] viene eseguita la funzione JavaScript [envoyer] definita alla riga 24
  • riga 72: il pulsante [Rétablir] non ha cambiato funzione
  • riga 73: cliccando sul pulsante [Effacer], di tipo [Button], viene eseguita la funzione JavaScript [effacer] definita alla riga 16

Prima di commentare il codice JavaScript, ricordiamo alcune nozioni:

JavaScript gestisce la pagina visualizzata e il suo contenuto come un albero di oggetti la cui radice è l’oggetto [document]. In questo documento possono essere presenti uno o più moduli. [document.frmPersonne] indica il modulo denominato [frmPersonne] definito alla riga 56. Anche questo modulo contiene oggetti. I campi di immissione ne fanno parte. Pertanto, [document.frmPersonne.txtNom] indica l’oggetto immagine del campo di immissione HTML definito alla riga 60. L'oggetto [txtNom] presenta diverse proprietà, tra cui la proprietà [value] che indica il contenuto del campo di immissione. Pertanto, [document.frmPersonne.txtNom.value] indica il contenuto del campo di immissione [txtNom].

  • righe 16-22: la funzione JavaScript [effacer] inserisce una stringa vuota nei campi di immissione [txtNom, txtAge].
  • righe 24-49: la funzione JavaScript [envoyer] verifica la validità dei valori dei campi di immissione [txtNom, txtAge] prima di inviarli. A tal fine utilizza espressioni regolari.
  • riga 28: verifica se il valore del campo di immissione [txtNom] corrisponde al modello /s*, che indica 0 o più spazi. Se la risposta è sì, significa che l’utente non ha specificato alcun nome. In caso di corrispondenza con il modello, la variabile champs avrà un valore diverso dal puntatore null; in caso contrario, avrà il valore null.
  • riga 29: se c'è corrispondenza con il modello
  • riga 30: viene visualizzato un messaggio all'utente
  • riga 32: si inserisce la stringa vuota nel campo [txtNom] (potrebbe esserci una sequenza di spazi)
  • riga 33: si posiziona il cursore lampeggiante sul campo [txtNom]
  • riga 34: si interrompe la funzione. In questo modo, i valori inseriti non vengono inviati al server tramite POST.
  • righe 38-45: si segue una procedura analoga con il campo [txtAge]
  • riga 47: se si arriva a questo punto, significa che i valori inseriti sono corretti. Si invia (submit) quindi il modulo [frmPersonne] al server web. A questo punto, tutto avviene come se si fosse premuto il pulsante denominato [Submit].

7.4.2. La vista [reponse]

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

Rispetto alla versione precedente, la novità appare solo quando si utilizza il link [Retour au formulaire] della vista [réponse]:

La differenza sta nell'URL visualizzato in [1]. Nella versione precedente, era:

[http://localhost:8080/persona2/main?action=retourFormulaire]

In questo caso, l'azione non fa più parte dell'URL poiché verrà inviata tramite un POST anziché un GET. La nuova pagina JSP [reponse.jsp] è lqqqaaaaaaaaaqqAAAaaa

è la 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");
  String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>


<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>      
    <br>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      <%= lienRetourFormulaire %>
    </a>
  </body>
</html>

Novità:

  • righe 35-37: il link [Retour au formulaire] contiene del codice JavaScript. Cliccando su questo link, viene eseguito il codice JavaScript dell’attributo [href]. Come abbiamo visto nell’analisi di [formulaire.jsp], sappiamo che questo codice invia i valori dei campi di tipo <input>, <select>, ... del modulo [frmPersonne].
  • righe 32-34: definiscono il modulo [frmPersonne]. Questo modulo ha un solo campo di tipo <input type="hidden" ...>, ovvero un campo nascosto. Questo campo [action] serve a trasmettere al controller il nome dell’azione da eseguire, in questo caso [retourFormulaire].

7.4.3. La vista [erreurs]

Questa vista segnala gli errori di inserimento dati nel modulo. La modifica apportata è la stessa di quella per la vista [réponse]:

La differenza sta nell'URL visualizzato in [1]. Nella versione precedente, era:

[http://localhost:8080/persona2/main?action=retourFormulaire]

In questo caso, l’azione non fa più parte dell’URL poiché verrà inviata tramite un POST anziché un GET. La nuova pagina JSP [reponse.jsp] è la 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"); 
  String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>


<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>
    <br>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      <%= lienRetourFormulaire %>
    </a>
  </body>
</html>

Novità:

  • righe 30-32: la nuova gestione del clic sul link. Le spiegazioni fornite a questo proposito nello studio su [réponse.jsp] valgono anche in questo caso.

7.5. Test delle viste

Per eseguire i test delle viste precedenti, duplichiamo le relative pagine JSP 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
  session.setAttribute("nom","tintin");
  session.setAttribute("age","30");
%>

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

Le righe 4-5 sono state aggiunte per creare il modello necessario alla pagina delle righe 9-10.

[reponse.jsp]:


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

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

Le righe 4-6 sono state aggiunte per creare il modello richiesto dalla pagina alle righe 11-13.

[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);
  request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>

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

Le righe 4-8 sono state aggiunte per creare il modello richiesto dalla pagina alle righe 13-14.

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

 

Otteniamo effettivamente le visualizzazioni previste.

7.6. Il controller [ServletPersonne]

Il controller [ServletPersonne] dell'applicazione web [/personne3] gestirà le seguenti azioni:

n.
richiesta
origine
elaborazione
1
[GET /personne3/main]
URL digitato dall'utente
- inviare la vista [formulaire] vuota
2
[POST /personne3/main]
con parametri [txtNom,
txtAge, action=validationFormulaire]
pubblicati
cliccando sul pulsante
[Envoyer] nella 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)]
3
[POST /personne3/main]
con parametri
[action=retourFormulaire]
clic
clic sul link [Torna al
modulo] delle visualizzazioni
[réponse] e [erreurs].
- inviare la vista [formulaire] precompilata con gli ultimi valori inseriti

Abbiamo quindi una nuova azione da gestire: [POST /personne3/main] con il parametro inviato [action=retourFormulaire], al posto della precedente azione [GET /personne3/main?action=retourFormulaire].

7.6.1. Struttura del controller

Lo scheletro del controller [ServletPersonne] è identico a quello della versione precedente.

package istia.st.servlets.personne;

...
import javax.servlet.http.HttpSession;

@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","lienRetourFormulaire"};
    private Map params=new HashMap<String,String>();
    ...

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

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

     // visualizzazione del modulo vuoto
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        ...
    }

     // visualizzazione del modulo precompilato
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        ...
    }

     // convalida del modulo
    void doValidationFormulaire(HttpServletRequest request,
    ...
    }

     // invio
    public void doPost(HttpServletRequest request, HttpServletResponse response)
    ...
    }
}

Novità:

  • alla riga 11, la tabella [paramètres] non contiene più il parametro [urlControleur], che è stato rimosso dal file [web.xml].

I metodi [init, doValidationFormulaire] rimangono invariati. I metodi [doGet, doInit, doRetourFormulaire] subiscono lievi modifiche.

7.6.2. Il metodo [doGet]

Il metodo [doGet] deve elaborare l'azione [POST /personne3/main] con il parametro inviato [action=retourFormulaire]:

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

...
        if(méthode.equals("post") && action.equals("retourFormulaire")){
             // ritorno al modulo di inserimento
            doRetourFormulaire(request,response);
            return;
        }
         // altri casi
        doInit(request,response);
    }
  • righe 6-9: elaborazione dell’azione [POST /personne3/main] con il parametro inviato [action=retourFormulaire]

7.6.3. Il metodo [doInit]

Questo metodo elabora la richiesta n. 1 [GET /personne3/main]. Il suo codice è il seguente:

             // visualizzazione del modulo vuoto
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // recupera la sessione dell'utente
        HttpSession session = request.getSession(true);        
         // invio del modulo vuoto
        session.setAttribute("nom", "");
        session.setAttribute("age", "");
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

La novità è che la vista [formulaire] visualizzata alla riga 8 non contiene più l'elemento [action] nel proprio modello.

7.6.4. Il metodo [doRetourFormulaire]

Questo metodo elabora la richiesta n. 1 [POST /personne3/main] con [action=retourFormulaire] tra gli elementi inviati. Il codice è il seguente:

     // visualizzazione del modulo precompilato
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // recupera la sessione dell'utente
        HttpSession session = request.getSession(true);        
         // Il nome è presente nella sessione?
        String nom = (String) session.getAttribute("nom");
        if (nom == null)
            session.setAttribute("nom", "");
         // L'età è presente nella sessione?
        String age = (String) session.getAttribute("age");
        if (age == null)
            session.setAttribute("age", "");
         // visualizzazione del modulo
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

La novità è che la vista [formulaire] visualizzata alla riga 14 non contiene più l’elemento [action] nel proprio modello.

7.7. Tests

Avviare o riavviare Tomcat dopo avervi integrato il progetto Eclipse [personne-mvc-03]. Richiedere l’URL [http://localhost:8080/personne3], quindi riprendere i test illustrati nell’esempio al paragrafo 7.1.