Skip to content

5. Aplikacja internetowa MVC [personne] – wersja 1

5.1. Widoki aplikacji

Aplikacja wykorzystuje formularz użyty w poprzednich przykładach. Pierwsza strona aplikacji wygląda następująco:

Image

Ten widok nazwiemy widokiem [formulaire]. Jeśli wprowadzimy prawidłowe dane, zostaną one wyświetlone w widoku o nazwie [réponse]:

Image

Jeśli dane są nieprawidłowe, błędy zostaną zgłoszone w widoku o nazwie [erreurs]:

Image

5.2. Architektura aplikacji

Aplikacja internetowa [personne1] będzie miała następującą architekturę:

Image

Jest to architektura jednowarstwowa: nie ma warstw [métier] ani [dao], a jedynie warstwa [web]. [ServletPersonne] to kontroler aplikacji, który przetwarza wszystkie żądania klientów. Aby na nie odpowiedzieć, wykorzystuje jeden z trzech widoków [formulaire, réponse, erreurs].

Musimy ustalić, w jaki sposób kontroler [ServletPersonne] określa, jaką akcję ma wykonać po otrzymaniu żądania od użytkownika. Żądanie klienta to strumień HTTP, który różni się w zależności od tego, czy zostało wysłane za pomocą polecenia GET, czy POST.

Żądanie GET

W tym przypadku strumień HTTP wygląda następująco:

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]

Wiersz 1 określa żądany adres URL, na przykład:

GET /personne1/ HTTP/1.1

Adres URL ten można wykorzystać do określenia akcji, która ma zostać wykonana. Można zastosować różne metody:

  1. parametr adresu URL określa akcję, na przykład [/appli?action=ajouter&id=4]. W tym przypadku parametr [action] wskazuje kontrolerowi, jaka akcja jest od niego wymagana.
  2. ostatni element adresu URL określa akcję, na przykład [/appli/ajouter?id=4]. W tym przypadku ostatni element adresu URL [/ajouter] jest wykorzystywany przez kontroler do określenia akcji, którą ma wykonać.

Możliwe są również inne rozwiązania. Dwa poprzednie są powszechnie stosowane.

Żądanie POST

W tym przypadku sekwencja HTTP wygląda następująco:

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/osoba1/main
Cookie: JSESSIONID=9F5E5BFA29643FC6B1601EEED907E1F9
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
[ligne vide]
txtNom=&txtAge=&action=validationFormulaire

Wiersz 1 określa żądany adres URL, na przykład:

POST /personne1/main HTTP/1.1

Adres URL ten można wykorzystać do określenia akcji, która ma zostać wykonana, tak jak w przypadku GET. W przypadku GET parametr [action] został włączony do URL. Może to mieć miejsce również tutaj, jak w:

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

Jednak parametr [action] może być również zawarty w wysłanych parametrach (wiersz 15 powyżej), tak jak w:

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

W dalszej części wykorzystamy te różne techniki, aby wskazać kontrolerowi, co ma zrobić:

  • włączyć parametr action do żądanego adresu URL:
POST /appli?action=ajouter&id=4 HTTP/1.1
  • wysłać parametr action:
POST /appli HTTP/1.1
...
[ligne vide]
action=ajouter&id=4
  • użyj ostatniego elementu adresu URL jako nazwy akcji:
POST /appli/ajouter?id=4 HTTP/1.1

5.3. Projekt Eclipse

Aby utworzyć projekt Eclipse [mvc-personne-01] dla aplikacji internetowej [personne1], należy postępować zgodnie z procedurą opisaną w punkcie 3.1.

Image

Nie zachowamy domyślnie proponowanego kontekstu [mvc-personne-01]. Wybierzemy [personne1], jak pokazano poniżej:

Image

Otrzymany wynik jest następujący:

Image

Jeśli jednak zechcemy zmienić kontekst aplikacji internetowej, użyjemy opcji [clic droit sur projet -> Properties -> J2EE]:

Image

W opcji [1] należy podać nowy kontekst.

Utworzymy podfolder [vues] w folderze [WEB-INF]: [clic droit sur WEB-INF -> New -> Folder]:

Oto nowy projekt:

Image

Po ukończeniu projekt będzie wyglądał następująco:

Image

  • kontroler [ServletPersonne] znajduje się w folderze [src]
  • Strony JSP z widoków [formulaire, réponse, erreurs] znajdują się w folderze [WEB-INF/vues], co uniemożliwia użytkownikowi bezpośrednie wywołanie ich, jak pokazuje poniższy przykład:

Image

Poniżej opisujemy poszczególne komponenty aplikacji internetowej [/personne1]. Zachęcamy czytelnika do tworzenia ich w trakcie lektury.

5.4. Konfiguracja aplikacji internetowej [personne1]

Plik web.xml aplikacji /personne1 będzie wyglądał następująco:


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

Co zawiera ten plik konfiguracyjny?

  • wiersze 34–37: plik URL /main jest obsługiwany przez serwlet o nazwie „personne”
  • wiersze 10–13: serwlet o nazwie „personne” jest instancją klasy [ServletPersonne]
  • wiersze 14–19: definiują parametr konfiguracyjny o nazwie [urlReponse]. Jest to adres URL widoku [réponse].
  • wiersze 20–25: definiują parametr konfiguracyjny o nazwie [urlErreurs]. Jest to adres URL widoku [erreurs].
  • wiersze 26–31: definiują parametr konfiguracyjny o nazwie [urlFormulaire]. Jest to adres URL widoku [formulaire].
  • wiersz 40: [index.jsp] będzie stroną główną aplikacji.

Adresy URL stron JSP oraz widoków [formulaire, réponse, erreurs] są objęte oddzielnymi parametrami konfiguracyjnymi. Pozwala to na ich przenoszenie bez konieczności ponownej kompilacji aplikacji.

Gdy użytkownik wywoła adres URL [/personne1], odpowiedź wyśle plik [index.jsp] (plik strony głównej, wiersz 40). Plik ten znajduje się w katalogu głównym folderu [WebContent]:

Image

Jego zawartość jest następująca:


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

Strona [index.jsp] ogranicza się do przekierowania klienta na adres URL [/personne1/main]. W związku z tym, gdy przeglądarka wysyła żądanie dotyczące adresu URL [/personne1], strona [index.jsp] wysyła jej następującą odpowiedź:

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/osoba1/main
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 0
Date: Thu, 18 May 2006 15:45:23 GMT
  • wiersz 1: odpowiedź HTTP/1.1, aby poinformować serwer o przekierowaniu do innego adresu URL
  • wiersz 4: adres URL, na który ma przekierować się przeglądarka

Po otrzymaniu tej odpowiedzi przeglądarka zażąda adresu URL [/personne1/main], zgodnie z poleceniem (wiersz 4). Plik [web.xml] aplikacji [/personne1] wskazuje, że żądanie to zostanie obsłużone przez kontroler [ServletPersonne] (wiersze 35–36).

5.5. Kod widoków

Pisanie aplikacji internetowej rozpoczynamy od stworzenia jej widoków. Pozwalają one określić potrzeby użytkownika w zakresie interfejsu graficznego i można je testować bez udziału kontrolera.

5.5.1. Widok [formulaire]

Ten widok przedstawia formularz służący do wprowadzania imienia i wieku:

Image

typ HTML
imię
rola
1
<input type="text">
txtNom
wprowadź nazwę
2
<input type="text">
txtAge
wprowadź wiek
3
<input type="submit">
 
wysłanie wprowadzonych wartości na serwer pod adresem URL /osoba1/main
4
<input type= "reset ">
 
w celu przywrócenia strony do stanu, w jakim została pierwotnie pobrana przez przeglądarkę
5
<input type= "button ">
 
w celu wyczyszczenia zawartości pól wprowadzania danych [1] i [2]

Jest generowana przez stronę JSP [formulaire.jsp]. Jej szablon składa się z następujących elementów:

  • [nom]: nazwa (ciąg znaków) znaleziona w atrybutach sesji powiązanych z kluczem „nazwa”
  • [age]: wiek (ciąg znaków) znaleziony w atrybutach sesji powiązanych z kluczem „age”

Widok [formulaire] jest generowany, gdy użytkownik wywołuje adres URL [/personne1/main], c.a.d oraz adres URL kontrolera [ServletPersonne]. Kod strony JSP [formulaire.jsp], który generuje widok [formulaire], jest następujący:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    // pobieramy dane z modelu
  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>

  • wiersze 6–7: strona JSP rozpoczyna się od pobrania z żądania [request] elementów [nom, age] ze swojego modelu. W normalnym trybie działania aplikacji model ten zostanie utworzony przez kontroler [ServletPersonne].
  • wiersze 18–38: strona JSP wygeneruje formularz HTML (tag <form>)
  • wiersz 18: tag <form> nie posiada atrybutu action określającego adres URL, który ma przetwarzać wartości przesłane przez przycisk [Envoyer] typu submit (wiersz 32). Wartości z formularza zostaną wówczas przesłane na adres URL, z którego pochodzi formularz, czyli na adres kontrolera [ServletPersonne]. W ten sposób kontroler ten służy zarówno do wygenerowania pustego formularza, o który początkowo poproszono za pomocą GET, jak i do przetwarzania wprowadzonych danych, które zostaną do niego przesłane za pomocą przycisku [Envoyer].
  • Wartości przesyłane to wartości z pól HTML, [txtNom] (wiersz 22), [txtAge] (wiersz 26) oraz [action] (wiersz 37). Ten ostatni parametr pozwoli kontrolerowi określić, jakie działania należy podjąć.
  • Przy pierwszym wyświetleniu formularza pola wprowadzania danych [txtNom, txtAge] są inicjowane odpowiednio zmiennymi [nom] (wiersz 22) i [age] (wiersz 26). Zmienne te pobierają wartości atrybutów z zapytania (wiersze 6–7), przy czym atrybuty te są inicjowane przez serwlet. To właśnie serwlet określa więc początkową zawartość pól wprowadzania danych w formularzu.
  • wiersz 33: przycisk [Rétablir] typu [reset] pozwala przywrócić formularz do stanu, w jakim znajdował się w momencie jego otrzymania przez przeglądarkę.
  • wiersz 34: przycisk [Effacer] typu [reset] nie pełni na razie żadnej funkcji.

W dalszej części będziemy nazywać ten widok widokiem [formulaire(nom, age)], gdy będziemy chcieli określić zarówno nazwę widoku, jak i jego szablon. Ponadto należy pamiętać, że gdy użytkownik kliknie przycisk [Envoyer], parametry [txtNom, txtAge] są wysyłane pod adres URL [/personne1/main].

5.5.2. Widok [reponse]

Ten widok wyświetla wartości wprowadzone w formularzu, o ile są one prawidłowe:

Image

Jest generowany przez stronę JSP [reponse.jsp]. Jego szablon składa się z następujących elementów:

  • [nom]: nazwa (String), która zostanie znaleziona w atrybutach sesji, powiązana z kluczem „nazwa”
  • [age]: wiek (ciąg znaków), który zostanie znaleziony w atrybutach sesji, powiązany z kluczem „wiek”

Kod strony JSP [reponse.jsp] wygląda następująco:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    // pobieramy dane z modelu
  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>

  • wiersze 6–7: strona JSP rozpoczyna się od pobrania z żądania [request] elementów [nom, age] swojego modelu. W normalnym trybie działania aplikacji to kontroler [ServletPersonne] będzie odpowiedzialny za utworzenie tego szablonu.
  • Elementy [nom, age] z modelu są następnie wyświetlane w wierszach 20 i 24

Następnie nazywamy ten widok widokiem [réponse(nom, age)].

5.5.3. Widok [erreurs]

Ten widok sygnalizuje błędy wprowadzenia danych w formularzu:

Image

Jest on generowany przez stronę JSP [erreurs.jsp]. Jego szablon składa się z następujących elementów:

  • [erreurs]: lista (ArrayList) komunikatów o błędach, która znajduje się w atrybutach zapytania, powiązana z kluczem „błędy”

Kod strony JSP [erreurs.jsp] jest następujący:


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

<%
// pobieranie danych z modelu
  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");
        }//for
      %>
    </ul>
  </body>
</html>

  • wiersz 8: strona JSP rozpoczyna się od pobrania z zapytania [request] elementu [erreurs] ze swojego szablonu. Element ten reprezentuje obiekt typu ArrayList, składający się z elementów typu String. Elementy te to komunikaty o błędach. Podczas normalnego działania aplikacji to kontroler [ServletPersonne] będzie odpowiedzialny za utworzenie tego modelu.
  • wiersze 18–22: wyświetlają listę komunikatów o błędach. W tym celu konieczne jest napisanie kodu Java w treści HTML strony. Należy zawsze dążyć do ograniczenia go do minimum, aby nie zaśmiecać kodu HTML. W dalszej części zobaczymy, że istnieją rozwiązania pozwalające na zmniejszenie ilości kodu Java na stronach JSP.
  • wiersz 4: należy zwrócić uwagę na tag importujący pakiety niezbędne dla strony JSP

Następnie wywołujemy ten widok, widok [erreurs(erreurs)].

5.6. Testowanie widoków

Możliwe jest przetestowanie poprawności stron JSP bez konieczności pisania kontrolera. Wymaga to spełnienia dwóch warunków:

  • trzeba mieć możliwość wywołania ich bezpośrednio z poziomu aplikacji, bez pośrednictwa kontrolera
  • strona JSP musi sama zainicjować model, który normalnie byłby tworzony przez kontroler

Aby przeprowadzić te testy, kopiujemy strony JSP z widoków do folderu [/WebContent/JSP] w projekcie Eclipse:

Image

Następnie w folderze JSP strony są modyfikowane w następujący sposób:

[formulaire.jsp]:


...

<%
  // -- test: tworzymy szablon strony
  request.setAttribute("nom","tintin");
  request.setAttribute("age","30");
%>

<%
    // pobieramy dane z szablonu
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
    
<html>
    <head>
...

Dodano wiersze 3–7 w celu utworzenia szablonu wymaganego przez stronę w wierszach 11–12.

[reponse.jsp]:


...

<%
  // -- test: tworzymy szablon strony
  request.setAttribute("nom","milou");
  request.setAttribute("age","10");
%>

<%
    // pobieramy dane z szablonu
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

    
<html>
    <head>
...

Wiersze 3–7 zostały dodane w celu utworzenia szablonu wymaganego przez stronę w wierszach 11–12.

[erreurs.jsp]:


...

<%
  // -- test: tworzymy szablon strony
  ArrayList<String> erreurs1=new ArrayList<String>();
  erreurs1.add("erreur1");
  erreurs1.add("erreur2");
  request.setAttribute("erreurs",erreurs1);
%>

<%
// pobieranie danych z szablonu
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

    
<html>
    <head>
...

Wiersze 3–9 zostały dodane w celu utworzenia szablonu wymaganego przez stronę w wierszu 13.

Uruchom Tomcat, jeśli jeszcze tego nie zrobiłeś, a następnie wywołaj następujące adresy URL:

 

Otrzymujemy oczekiwane widoki. Teraz, gdy mamy już wystarczające zaufanie do stron JSP w aplikacji, możemy przejść do pisania jej kontrolera [ServletPersonne].

5.7. Kontroler [ServletPersonne]

Pozostaje jeszcze napisać serce naszej aplikacji internetowej, czyli kontroler. Jego rolą jest:

  • odbioru żądania od klienta,
  • przetworzenie żądanej przez niego akcji,
  • wysłanie w odpowiedzi odpowiedniego widoku.

Kontroler [ServletPersonne] będzie obsługiwał następujące akcje:

nr
żądanie
źródło
przetwarzanie
1
[GET /personne1/main]
adres URL wpisany przez użytkownika
- wyślij pusty widok [formulaire]
2
[POST /personne1/main]
z parametrami [txtNom,
txtAge, akcja] opublikowane
po kliknięciu przycisku
[Envoyer] w widoku
[formulaire]
- sprawdzić wartości parametrów [txtNom, txtAge]
- jeśli są nieprawidłowe, wyślij widok [erreurs(erreurs)]
- jeśli są poprawne, wyślij widok [reponse(nom,age)]

Aplikacja uruchamia się, gdy użytkownik wywołuje adres URL [/personne1/main]. Zgodnie z plikiem [web.xml] aplikacji (patrz punkt 5.4) żądanie to jest przetwarzane przez instancję typu ServletPersonne, którą teraz opisujemy.

5.7.1. Szkielet kontrolera

Kod kontrolera [ServletPersonne] wygląda następująco:

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 {
...

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

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

     // wyświetlanie widoku początkowego
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
...
    }

     // walidacja formularza
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
...
    }

     // przesyłanie
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // przekazanie kontroli do GET
        doGet(request, response);
    }
}
  • wiersze 20–22: metoda [init] wykonywana podczas początkowego ładowania serwletu
  • wiersze 25–28: metoda [doGet] wywoływana przez serwer WWW po otrzymaniu żądania typu GET skierowanego do aplikacji
  • wiersze 42–46: metoda [doPost] wywoływana przez serwer WWW po wysłaniu do aplikacji żądania typu POST. Jak widać, zostanie ona również przetworzona przez metodę [doGet] (wiersz 45).
  • wiersze 31–33: metoda [doInit] obsługuje akcję nr 1 [GET /personne1/main]
  • wiersze 36–39: metoda [doValidationFormulaire] przetwarza akcję nr 2 [POST /personne1/main] z parametrami przesłanymi w metodzie [txtNom, txtAge, action].

Poniżej opisujemy poszczególne metody kontrolera

5.7.2. Inicjalizacja kontrolera

Gdy klasa kontrolera zostanie załadowana przez kontener serwletów, wykonywana jest jej metoda [init]. Odbywa się to tylko raz. Po załadowaniu do pamięci kontroler pozostaje w niej i przetwarza żądania od różnych klientów. Każdy klient jest obsługiwany przez osobny wątek wykonawczy, dzięki czemu metody kontrolera są wykonywane jednocześnie przez różne wątki. Należy pamiętać, że z tego powodu kontroler nie może posiadać pól, które mogłyby być modyfikowane przez jego metody. Jego pola muszą być tylko do odczytu. Są one inicjowane przez metodę [init], co stanowi jej główną rolę. Metoda ta ma bowiem tę cechę, że jest wykonywana tylko raz przez jeden wątek. Nie ma zatem problemów z równoczesnym dostępem do pól kontrolera w tej metodzie. Metoda [init] ma na celu zainicjowanie obiektów niezbędnych dla aplikacji internetowej, które będą współdzielone w trybie tylko do odczytu przez wszystkie wątki klienckie. Te współdzielone obiekty można umieścić w dwóch miejscach:

  • w polach prywatnych kontrolera
  • kontekście wykonania aplikacji (ServletContext)

Kod metody [init] kontrolera [ServletPersonne] wygląda następująco:

package istia.st.servlets.personne;

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

     // inicjalizacja
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
         // pobieramy parametry inicjalizacji serwletu
        ServletConfig config = getServletConfig();
         // przetwarzamy pozostałe parametry inicjalizacyjne
        String valeur=null;
        for(int i=0;i<paramètres.length;i++){
             // wartość parametru
            valeur=config.getInitParameter(paramètres[i]);
             // czy parametr istnieje?
            if(valeur==null){
                 // odnotowuje się błąd
                erreursInitialisation.add("Le paramètre ["+paramètres[i]+"] n'a pas été initialisé");
            }else{
                 // zapisywanie wartości parametru
                params.put(paramètres[i],valeur);
            }
             // adres URL widoku [erreurs] podlega specjalnej obróbce
            urlErreurs = config.getInitParameter("urlErreurs");
            if (urlErreurs == null)
                throw new ServletException(
                        "Le paramètre [urlErreurs] n'a pas été initialisé");
        }
    }
...
}
  • wiersz 16: pobierana jest konfiguracja aplikacji internetowej c.a.d. zawartość pliku [web.xml]
  • w wierszach 19–29 pobierane są parametry inicjalizacji serwletu, których nazwy są zdefiniowane w tabeli [paramètres] w wierszu 9
  • wiersz 21: pobierana jest wartość parametru
  • wiersz 25: jeśli parametr nie istnieje, błąd jest dodawany do listy błędów [erreursInitialisation], która początkowo jest pusta (wiersz 8).
  • wiersz 28: jeśli parametr występuje, jest zapisywany wraz ze swoją wartością w słowniku [params], który początkowo jest pusty (wiersz 10).
  • wiersze 31–35: parametr [urlErreurs] musi być obowiązkowo obecny, ponieważ określa adres URL widoku [erreurs], który może wyświetlać ewentualne błędy inicjalizacji. Jeśli nie istnieje, aplikacja zostaje przerwana poprzez uruchomienie widoku [ServletException] (wiersz 33).

5.7.3. Metoda [doGet]

Metoda [doGet] obsługuje zarówno żądania GET, jak i POST w serwlecie, ponieważ metoda [doPost] odwołuje się do metody [doGet]. Jej kod wygląda następująco:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
     // parametry instancji
    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 {

         // sprawdzamy, jak przebiegła inicjalizacja serwletu
        if (erreursInitialisation.size() != 0) {
             // przekazujemy kontrolę do strony błędów
            request.setAttribute("erreurs", erreursInitialisation);
            getServletContext().getRequestDispatcher(urlErreurs).forward(
                    request, response);
             // koniec
            return;
        }

         // pobieramy metodę wysyłania żądania
        String méthode=request.getMethod().toLowerCase();
         // pobieramy akcję do wykonania
        String action=request.getParameter("action");
         // akcja?
        if(action==null){
            action="init";
        }
         // wykonanie akcji
        if(méthode.equals("get") && action.equals("init")){
             // uruchomienie aplikacji
            doInit(request,response);
            return;
        }
        if(méthode.equals("post") && action.equals("validationFormulaire")){
             // walidacja formularza wprowadzania danych
            doValidationFormulaire(request,response);
            return;
        }
         // inne przypadki
        doInit(request,response);
    }

     // wysłanie
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
         // przekazanie kontroli do GET
        doGet(request, response);
    }
}
  • wiersze 18–25: sprawdzane jest, czy lista błędów inicjalizacji jest pusta. Jeśli tak nie jest, wyświetlany jest widok [erreurs(erreursInitialisation)], który zgłasza błąd lub błędy.

Aby zrozumieć ten kod, należy przypomnieć sobie szablon widoku [erreurs]:

<%
// pobieranie danych z modelu
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>

Widok [erreurs] oczekuje w zapytaniu elementu klucza „erreurs”. Kontroler tworzy ten element w wierszu 20.

  • w wierszu 28: pobierana jest metoda [get] lub [post], której klient użył do wysłania zapytania
  • wiersz 30: pobierana jest wartość parametru [action] z zapytania. Przypomnijmy, że w naszej aplikacji tylko zapytanie nr 2 [POST /personne1/main] posiada parametr [action]. W tym zapytaniu ma on wartość [validationFormulaire].
  • wiersze 31–34: jeśli parametr [action] nie występuje, przypisuje się mu wartość „init”. Tak będzie w przypadku początkowego żądania nr 1 o numerze [GET /personne1/main].
  • wiersze 36–40: przetwarzanie zapytania nr 1 o numerze [GET /personne1/main].
  • wiersze 41–45: przetwarzanie zapytania nr 2 [POST /personne1/main].
  • wiersz 47: jeśli nie mamy do czynienia z żadnym z dwóch poprzednich przypadków, postępujemy tak, jakbyśmy mieli do czynienia z przypadkiem nr 1

5.7.4. Metoda [doInit]

Metoda ta przetwarza zapytanie nr 1 [GET /personne1/main]. W przypadku tego zapytania musi wysłać pusty widok [formulaire(nom,age)]. Jej kod jest następujący:

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

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

...    
     // wyświetlanie widoku początkowego
    void doInit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
         // wysyłamy pusty formularz
        request.setAttribute("nom", "");
        request.setAttribute("age", "");
        getServletContext().getRequestDispatcher((String)params.get("urlFormulaire")).forward(
                request, response);
        return;
    }
...
}
  • wiersze 18–19: wyświetlany jest widok [formulaire]. Przypomnijmy model oczekiwany przez ten widok:

<%
    // pobieranie danych z modelu
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>
  • wiersze 16–17: szablon [nom,age] widoku [formulaire] jest inicjowany pustymi ciągami znaków.

5.7.5. Metoda [doValidationFormulaire]

Metoda ta przetwarza żądanie nr 2 [POST /personne1/main], w którym przesłane parametry to [action, txtNom, txtAge]. Jej kod wygląda następująco:

package istia.st.servlets.personne;

...
@SuppressWarnings("serial")
public class ServletPersonne extends HttpServlet {
     // parametry instancji
    private String urlErreurs = null;
    private ArrayList erreursInitialisation = new ArrayList<String>();
    private String[] paramètres={"urlFormulaire","urlReponse"};
    private Map params=new HashMap<String,String>();
...
     // walidacja formularza
    void doValidationFormulaire(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException{
         // pobieranie parametrów
        String nom = request.getParameter("txtNom");
        String age = request.getParameter("txtAge");
         // weryfikacja parametrów
        ArrayList<String> erreursAppel = new ArrayList<String>();
         // nazwa nie może być pusta
        nom = nom.trim();
        if (nom.equals(""))
            erreursAppel.add("Le champ [nom] n'a pas été rempli");
         // wiek musi być liczbą całkowitą >=0
        if (!age.matches("^\\s*\\d+\\s*$"))
            erreursAppel.add("Le champ [age] est erroné");
         // czy występują błędy w parametrach?
        if (erreursAppel.size() != 0) {
             // wysyłamy stronę z komunikatami o błędach
            request.setAttribute("erreurs", erreursAppel);
            getServletContext().getRequestDispatcher(urlErreurs).forward(request, response);
            return;
        }
         // parametry są poprawne – wysyłamy stronę odpowiedzi
        request.setAttribute("nom", nom);
        request.setAttribute("age", age);
        getServletContext().getRequestDispatcher((String)params.get("urlReponse")).forward(request,
                response);
        return;
    }
...
}
  • wiersze 16–17: z żądania klienta pobierane są wartości parametrów „txtNom” i „txtAge”.
  • wiersze 19–26: sprawdzana jest poprawność tych dwóch parametrów
  • wiersze 28–33: jeśli któryś z parametrów jest nieprawidłowy, wyświetlany jest widok [erreurs(erreursAppel)]. Przypomnijmy model tego widoku:

<%
// pobierane są dane z modelu
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");  
%>
  • wiersze 35–38: jeśli oba pobrane parametry „txtNom” i „txtAge” mają prawidłowe wartości, wyświetlany jest widok [reponse(nom,age)]. Należy pamiętać o szablonie widoku [reponse]:

<%
    // pobierane są dane z modelu
  String nom=(String)request.getAttribute("nom");
  String age=(String)request.getAttribute("age");
%>

5.8. Tests

Dodajmy projekt [mvc-personne-01] do aplikacji Tomcat, postępując zgodnie z procedurą opisaną w punkcie 3.3:

Image

Uruchom Tomcat. Po wykonaniu tej czynności można wznowić testy przedstawione jako przykład w punkcie 5.1. Można również dodać nowe. Można na przykład usunąć jeden z parametrów konfiguracyjnych urlXXX z pliku web.xml i sprawdzić wynik. Tak jak poniżej, jeden z parametrów został skomentowany w pliku [web.xml]:


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

Uruchamiamy lub ponownie uruchamiamy Tomcat i wpisujemy adres URL [http://localhost:8080/personne1/main]. Otrzymujemy następującą odpowiedź:

Image