Skip to content

7. Webanwendung MVC [personne] – Version 3


Empfohlene Lektüre in [ref1]: Kapitel 9


7.1. Einleitung

Wir möchten JavaScript-Code in die an den Browser gesendeten Seiten HTML einfügen. Der Browser führt den in der angezeigten Seite eingebetteten JavaScript-Code aus. Diese Technologie ist unabhängig von derjenigen, die vom Webserver zur Erstellung des Dokuments HTML verwendet wird (Java/Servlets/JSP, ASP.NET, ASP, PHP, Perl, Python, ...) verwendet wird.

[formulaire.jsp]

Die aus dieser Seite resultierende Ansicht sieht wie folgt aus:

Image

Die Schaltflächen, deren Beschriftung eingerahmt ist, nutzen JavaScript-Code, der in die Seite HTML eingebettet ist:

Beschriftung
Typ HTML
Funktion
Submit
<submit>
Erfüllt die Funktion der Schaltfläche „[Envoyer]“ aus früheren Versionen: Übermittelt die eingegebenen Werte an den Controller
[Envoyer]
<button>
neue Schaltfläche – überprüft lokal die Gültigkeit der eingegebenen Daten, bevor diese an den Controller gesendet werden
Rétablir
<reset>
Setzt das Formular in den Zustand zurück, in dem es ursprünglich vom Browser empfangen wurde
[Effacer]
<button>
löscht den Inhalt beider Eingabefelder

Hier ein Beispiel für die Verwendung der Schaltflächen [Envoyer] und [Effacer]:

Wir werden außerdem JavaScript-Code verwenden, um den Link [Retour au formulaire] der Ansichten [erreurs] und [réponse] zu verwalten. Nehmen wir als Beispiel die Ansicht [réponse]:

1

Der Unterschied liegt in der in [1] angezeigten URL. In der vorherigen Version lautete diese:

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

Hier ist die Aktion nicht mehr Teil der URL, da sie über einen POST statt über einen GET gesendet wird. Diese Änderung hat zur Folge, dass die einzige vom Browser angezeigte URL unabhängig von der angeforderten Aktion immer „[http://localhost:8080/personne3/main]“ lautet.

7.2. Das Eclipse-Projekt

Um das Eclipse-Projekt [mvc-personne-03] für die Webanwendung [/personne3] zu erstellen, duplizieren wir das Projekt [mvc-personne-02] gemäß der in Abschnitt 6.2 auf Seite 78 beschriebenen Vorgehensweise.

7.3. Konfiguration der Webanwendung [personne3]

Die Datei web.xml der Anwendung /personne3 sieht wie folgt aus:


<?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>
    <!--  Zuordnung ServletPersonne-->
    <servlet-mapping>
        <servlet-name>personne</servlet-name>
        <url-pattern>/main</url-pattern>
    </servlet-mapping>
    <!--  Startdateien -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Diese Datei ist bis auf einige Details identisch mit der der vorherigen Version:

  • Zeile 6: Der Anzeigename der Webanwendung hat sich in [mvc-personne-03] geändert

Der Parameter [urlControleur] ist verschwunden. In der vorherigen Version diente er dazu, das Ziel von POST für die Ansicht [formulaire] festzulegen. In dieser neuen Version ist das Ziel die leere Zeichenfolge c.a.d. Die vom Browser angezeigte URL. Wir haben erläutert, dass diese immer [http://localhost:8080/personne3/main] lauten würde – genau die, die wir für das POST der Ansicht [formulaire] benötigen.

Die Startseite [index.jsp] ändert sich:


<%@ 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");
%>
  • Zeile 5: Die Seite [index.jsp] leitet den Client zur URL des Controllers [ServletPersonne] der Anwendung [/personne3] weiter.

7.4. Der Code der Ansichten

7.4.1. Die Ansicht [formulaire]

Diese Ansicht sieht nun wie folgt aus:

Image

Sie wird von der folgenden Seite JSP [formulaire.jsp] generiert:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<%// Die Daten aus der Vorlage werden abgerufen
            String nom = (String) session.getAttribute("nom");
            String age = (String) session.getAttribute("age");
%>


<html>
  <head>
    <title>Personne - formulaire</title>
    <script language="javascript">
        // -------------------------------
        function effacer(){
          // Die Eingabefelder werden gelöscht
          with(document.frmPersonne){
            txtNom.value="";
            txtAge.value="";
          }//mit
        }//Löschen
        // -------------------------------      
        function envoyer(){
          // Überprüfung der Parameter vor dem Absenden
          with(document.frmPersonne){
            // Der Name darf nicht leer sein
            champs=/^\s*$/.exec(txtNom.value);
            if(champs!=null){
              // Der Name ist leer
              alert("Vous devez indiquer un nom");
              txtNom.value="";
              txtNom.focus();
              // Zurück zur grafischen Benutzeroberfläche
              return;
            }//if
            // Das Alter muss eine positive ganze Zahl sein
            champs=/^\s*\d+\s*$/.exec(txtAge.value);
            if(champs==null){
              // Das Alter ist ungültig
              alert("Age incorrect");
              txtAge.focus();
              // Zurück zur grafischen Benutzeroberfläche
              return;
            }//if
            // Die Parameter sind korrekt – sie werden an den Server gesendet
            submit();
          }//mit
        }//senden
      </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>


Neuerungen:

  • Zeile 56: Das Formular hat den Namen [frmPersonne]. Dieser Name wird im JavaScript-Code verwendet. Zu beachten ist das Fehlen des Attributs [action], wodurch das Formular [frmPersonne] an die vom Browser angezeigte URL gesendet wird.
  • Zeile 70: Die Schaltfläche „[Submit]“ übernimmt die Funktion der Schaltfläche „[Envoyer]“ aus früheren Versionen
  • Zeile 71: Ein Klick auf die Schaltfläche [Envoyer] vom Typ [Button] führt die in Zeile 24 definierte JavaScript-Funktion [envoyer] aus
  • Zeile 72: Die Funktion der Schaltfläche [Rétablir] hat sich nicht geändert
  • Zeile 73: Ein Klick auf die Schaltfläche „[Effacer]“ vom Typ „[Button]“ führt die in Zeile 16 definierte JavaScript-Funktion „[effacer]“ aus

Bevor wir den JavaScript-Code kommentieren, möchten wir noch einmal auf einige Konventionen hinweisen:

JavaScript verwaltet die angezeigte Seite und ihren Inhalt als Objektbaum, dessen Wurzel das Objekt [document] ist. In diesem Dokument kann es ein oder mehrere Formulare geben. [document.frmPersonne] bezeichnet das Formular mit dem Namen [frmPersonne], das in Zeile 56 definiert ist. Auch dieses Formular enthält Objekte. Dazu gehören die Eingabefelder. So bezeichnet [document.frmPersonne.txtNom] das Bildobjekt des Eingabefelds HTML, das in Zeile 60 definiert ist. Das Objekt [txtNom] verfügt über verschiedene Eigenschaften, darunter die Eigenschaft [value], die den Inhalt des Eingabefelds bezeichnet. Somit bezeichnet [document.frmPersonne.txtNom.value] den Inhalt des Eingabefelds [txtNom].

  • Zeilen 16–22: Die JavaScript-Funktion [effacer] setzt eine leere Zeichenfolge in die Eingabefelder [txtNom, txtAge].
  • Zeilen 24–49: Die JavaScript-Funktion [envoyer] überprüft die Gültigkeit der Werte in den Eingabefeldern [txtNom, txtAge], bevor sie übermittelt werden. Dazu verwendet sie reguläre Ausdrücke.
  • Zeile 28: Prüft, ob der Wert des Eingabefelds [txtNom] dem Muster /s* entspricht, was 0 oder mehr Leerzeichen bedeutet. Ist dies der Fall, bedeutet dies, dass der Benutzer keinen Namen angegeben hat. Bei Übereinstimmung mit dem Muster erhält die Variable champs einen anderen Wert als der Zeiger null, andernfalls erhält sie den Wert null.
  • Zeile 29: Wenn eine Übereinstimmung mit dem Muster vorliegt
  • Zeile 30: Es wird eine Meldung für den Benutzer angezeigt
  • Zeile 32: In das Feld [txtNom] wird die leere Zeichenkette gesetzt (es könnte eine Folge von Leerzeichen vorhanden sein)
  • Zeile 33: Der blinkende Cursor wird auf das Feld [txtNom] gesetzt
  • Zeile 34: Die Funktion wird abgebrochen. Es gibt dann kein Feld „POST“ auf dem Server für die eingegebenen Werte.
  • Zeilen 38–45: Ein ähnlicher Vorgang findet mit dem Feld [txtAge] statt
  • Zeile 47: Wenn man hier angelangt ist, sind die eingegebenen Werte korrekt. Das Formular [frmPersonne] wird dann an den Webserver gesendet (submit). Es läuft nun alles so ab, als hätte man auf die Schaltfläche mit der Bezeichnung [Submit] geklickt.

7.4.2. Die Ansicht [reponse]

Diese Ansicht zeigt die im Formular eingegebenen Werte an, sofern diese gültig sind:

Im Vergleich zur vorherigen Version wird die Neuerung erst sichtbar, wenn man den Link [Retour au formulaire] aus der Ansicht [réponse] verwendet:

Der Unterschied liegt in der in [1] angezeigten URL. In der vorherigen Version lautete diese:

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

Hier ist die Aktion nicht mehr Teil der URL, da sie über einen POST statt über einen GET gesendet wird. Die neue Seite JSP [reponse.jsp] lautet lqqqaaaaaaaaaqqAAAaaa

folgende:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">


<%
    // die Daten aus der Vorlage werden abgerufen
  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>

Neuerungen:

  • Zeilen 35–37: Der Link „[Retour au formulaire]“ enthält JavaScript. Ein Klick auf diesen Link führt zur Ausführung des JavaScript-Codes des Attributs „[href]“. Wie wir bei der Untersuchung von [formulaire.jsp] gesehen haben, wissen wir, dass dieser Code die Werte der Felder vom Typ <input>, <select> usw. des Formulars [frmPersonne] übermittelt.
  • Zeilen 32–34: Definieren das Formular [frmPersonne]. Dieses enthält nur ein Feld vom Typ <input type="hidden" ...>, also ein verstecktes Feld. Dieses Feld [action] dient dazu, dem Controller den Namen der auszuführenden Aktion zu übermitteln, in diesem Fall [retourFormulaire].

7.4.3. Die Ansicht [erreurs]

Diese Ansicht meldet Eingabefehler im Formular. Die vorgenommene Änderung entspricht derjenigen in der Ansicht [réponse]:

Der Unterschied liegt in der in [1] angezeigten URL. In der vorherigen Version lautete diese:

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

Hier ist die Aktion nicht mehr Teil der URL, da sie über einen POST statt über einen GET gesendet wird. Die neue Seite JSP [reponse.jsp] lautet wie folgt:


<%@ 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" %>

<%
// Die Daten aus dem Modell werden abgerufen
  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");
        }//für
      %>
    </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>

Neuerungen:

  • Zeilen 30–32: Die neue Handhabung des Klicks auf den Link. Die diesbezüglichen Erläuterungen in der Studie zu [réponse.jsp] gelten auch hier.

7.5. Tests der Ansichten

Um die Tests der vorherigen Ansichten durchzuführen, duplizieren wir deren Seiten JSP im Ordner /WebContent/JSP des Eclipse-Projekts:

Image

Anschließend werden die Seiten im Ordner JSP wie folgt geändert:

[formulaire.jsp]:


...
<%
  // -- Test: Die Seitenvorlage wird erstellt
  session.setAttribute("nom","tintin");
  session.setAttribute("age","30");
%>

<%// Die Daten aus der Vorlage werden abgerufen
            String nom = (String) session.getAttribute("nom");
            String age = (String) session.getAttribute("age");
%>

Die Zeilen 4–5 wurden hinzugefügt, um die Vorlage zu erstellen, die die Seite in den Zeilen 9–10 benötigt.

[reponse.jsp]:


...
<%
  // -- Test: Die Seitenvorlage wird erstellt
  request.setAttribute("nom","milou");
  request.setAttribute("age","10");
  request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>

<%
    // Die Daten der Vorlage werden abgerufen
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
  String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
...

Die Zeilen 4–6 wurden hinzugefügt, um die Vorlage zu erstellen, die die Seite in den Zeilen 11–13 benötigt.

[erreurs.jsp]:



<%
  // -- Test: Die Seitenvorlage wird erstellt
  ArrayList<String> erreurs1=new ArrayList<String>();
  erreurs1.add("erreur1");
  erreurs1.add("erreur2");
  request.setAttribute("erreurs",erreurs1);
  request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>

<%
// Daten aus der Vorlage abrufen
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs"); 
  String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>

Die Zeilen 4–8 wurden hinzugefügt, um die Vorlage zu erstellen, die die Seite in den Zeilen 13–14 benötigt.

Starten Sie Tomcat, falls dies noch nicht geschehen ist, und rufen Sie dann die folgenden URLs auf:

 

Wir erhalten tatsächlich die erwarteten Ansichten.

7.6. Der Controller [ServletPersonne]

Der Controller [ServletPersonne] der Webanwendung [/personne3] wird die folgenden Aktionen verarbeiten:

Nr.
Anfrage
Quelle
Verarbeitung
1
[GET /personne3/main]
vom Benutzer eingegebene URL
- die leere Ansicht [formulaire] senden
2
[POST /personne3/main]
mit Parametern [txtNom,
txtAge, action=validationFormulaire]
gesendet
Klick auf die Schaltfläche
[Envoyer] in der Ansicht
[formulaire]
- die Werte der Parameter [txtNom, txtAge] überprüfen
- Falls sie falsch sind, die Ansicht [erreurs(erreurs)] senden
- wenn sie korrekt sind, die Ansicht [reponse(nom,age)] senden
3
[POST /personne3/main]
mit Parametern
[action=retourFormulaire]
klicken
Klick auf den Link [Zurück zum
Formular] in den Ansichten
[réponse] und [erreurs].
- Senden Sie die Ansicht [formulaire], die mit den zuletzt eingegebenen Werten vorausgefüllt ist

Wir haben also eine neue Aktion zu bearbeiten: [POST /personne3/main] mit dem übermittelten Parameter [action=retourFormulaire] anstelle der alten Aktion [GET /personne3/main?action=retourFormulaire].

7.6.1. Grundgerüst des Controllers

Das Grundgerüst des Controllers [ServletPersonne] ist identisch mit dem der vorherigen Version.

package istia.st.servlets.personne;

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

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

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

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

    // Anzeige des leeren Formulars
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        ...
    }

    // Anzeige des vorausgefüllten Formulars
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        ...
    }

    // Formularvalidierung
    void doValidationFormulaire(HttpServletRequest request,
    ...
    }

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

Neuerungen:

  • Zeile 11: Das Array [paramètres] enthält nicht mehr den Parameter [urlControleur], der aus der Datei [web.xml] entfernt wurde.

Die Methoden [init, doValidationFormulaire] bleiben unverändert. Die Methoden [doGet, doInit, doRetourFormulaire] ändern sich geringfügig.

7.6.2. Die Methode [doGet]

Die Methode [doGet] muss die Aktion [POST /personne3/main] mit dem übermittelten Parameter [action=retourFormulaire] verarbeiten:

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

...
        if(méthode.equals("post") && action.equals("retourFormulaire")){
            // Zurück zum Eingabeformular
            doRetourFormulaire(request,response);
            return;
        }
        // Sonstige Fälle
        doInit(request,response);
    }
  • Zeilen 6–9: Verarbeitung der Aktion [POST /personne3/main] mit dem übermittelten Parameter [action=retourFormulaire]

7.6.3. Die Methode [doInit]

Diese Methode verarbeitet die Anfrage Nr. 1 [GET /personne3/main]. Ihr Code lautet wie folgt:

            // Anzeige eines leeren Formulars
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        // Die Sitzung des Benutzers wird abgerufen
        HttpSession session = request.getSession(true);        
        // Das leere Formular wird gesendet
        session.setAttribute("nom", "");
        session.setAttribute("age", "");
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

Neu ist, dass die in Zeile 8 angezeigte Ansicht [formulaire] das Element [action] nicht mehr in ihrem Modell enthält.

7.6.4. Die Methode [doRetourFormulaire]

Diese Methode verarbeitet die Anfrage Nr. 1 [POST /personne3/main] mit [action=retourFormulaire] in den übermittelten Elementen. Der Code lautet wie folgt:

    // Anzeige des vorausgefüllten Formulars
    void doRetourFormulaire(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        // Abruf der Benutzersitzung
        HttpSession session = request.getSession(true);        
        // Ist der Name in der Sitzung vorhanden?
        String nom = (String) session.getAttribute("nom");
        if (nom == null)
            session.setAttribute("nom", "");
        // Ist das Alter in der Sitzung vorhanden?
        String age = (String) session.getAttribute("age");
        if (age == null)
            session.setAttribute("age", "");
        // Formular anzeigen
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }

Neu ist, dass die in Zeile 14 angezeigte Ansicht [formulaire] das Element [action] nicht mehr in ihrer Vorlage enthält.

7.7. Tests

Starten oder starten Sie Tomcat neu, nachdem Sie das Eclipse-Projekt [personne-mvc-03] darin integriert haben. Rufen Sie die URL [http://localhost:8080/personne3] auf und führen Sie dann die in Abschnitt 7.1 als Beispiel gezeigten Tests erneut durch.