6. Aplikacja internetowa MVC [personne] – wersja 2
Teraz zaproponujemy warianty poprzedniej aplikacji [/personne1], które nazwiemy [/personne2, /personne3, ...]. Warianty te nie zmieniają pierwotnej architektury aplikacji, która pozostaje następująca:

W przypadku tych wariantów nasze wyjaśnienia będą krótsze. Przedstawimy jedynie zmiany wprowadzone w stosunku do poprzedniej wersji.
6.1. Introduction
Teraz zamierzamy dodać do naszej aplikacji obsługę sesji. Przypomnijmy sobie następujące kwestie:
- dialog klient-serwer HTTP to ciąg niepowiązanych ze sobą sekwencji żądanie-odpowiedź
- sesja służy jako pamięć między różnymi sekwencjami żądania-odpowiedzi tego samego użytkownika. Jeśli jest N użytkowników, to istnieje N sesji.
Poniższa sekwencja ekranów przedstawia, jak powinna teraz działać aplikacja:
Wymiana nr 1
![]() | ![]() |
Nowością jest link powrotny do formularza, który został dodany w widoku [erreurs].
Wymiana nr 2
![]() | ![]() |
W wymianie nr 1 użytkownik podał dla pary (nazwisko, wiek) wartości (xx, yy). Jeśli w trakcie wymiany serwer poznał te wartości, to pod koniec wymiany je „zapomina”. Można jednak zauważyć, że podczas wymiany nr 2 serwer jest w stanie ponownie wyświetlić te wartości w swojej odpowiedzi. To właśnie pojęcie sesji pozwala w tym przypadku serwerowi internetowemu zapamiętywać dane w trakcie kolejnych wymian danych między klientem a serwerem. Istnieją również inne możliwe rozwiązania tego problemu.
W trakcie wymiany nr 1 serwer zapamiętuje w sesji parę (imię, wiek), którą przesłał mu klient, aby móc ją wyświetlić podczas wymiany nr 2.
Oto kolejny przykład wykorzystania sesji między dwiema wymianami:
Wymiana nr 1
![]() | ![]() |
Nowością jest link powrotny do formularza, który został dodany na stronie z odpowiedzią.
Wymiana nr 2
![]() | ![]() |
6.2. Projekt Eclipse
Aby utworzyć projekt Eclipse [mvc-personne-02] dla aplikacji internetowej [/personne2], skopiujemy projekt Eclipse [mvc-personne-01], aby wykorzystać istniejące zasoby. W tym celu postępujemy w następujący sposób:
[clic droit sur projet mvc-personne-01 -> Copy]:

a następnie [clic droit dans Package Explorer -> Paste]:
![]() | ![]() – w polu [1] wpisz nazwę nowego projektu, a w polu [2] nazwę istniejącego, ale pustego folderu |
W ten sposób tworzony jest projekt o nazwie [mvc-personne-02]:

Na razie jest on identyczny z projektem [mvc-personne-01]. Zanim będziemy mogli z niego korzystać, konieczne będzie wprowadzenie kilku zmian ręcznie. Przejdźmy do widoku [Servers] i spróbujmy dodać tę nową aplikację do tych zarządzanych przez Tomcat:
![]() | ![]() |
Widać, że w przypadku projektu [1] nowy projekt [mvc-personne-02] nie jest wykrywany przez Tomcat. Aby Tomcat go wykrył, należy zmodyfikować plik konfiguracyjny projektu [mvc-personne-02]. Użyjmy opcji [File / Open File], aby otworzyć plik [<mvc-personne-02>/.settings/.component]:
<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId">
<wb-module deploy-name="mvc-personne-01">
<wb-resource deploy-path="/" source-path="/WebContent"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
<property name="java-output-path" value="/build/classes/"/>
<property name="context-root" value="personne1"/>
</wb-module>
</project-modules>
Wiersz 3 określa nazwę modułu internetowego, który ma zostać wdrożony w Tomcat. Nazwa ta jest tutaj taka sama jak nazwa projektu [mvc-personne-01]. Zmieniamy ją na [mvc-personne-02]:
<wb-module deploy-name="mvc-personne-02">
Ponadto możemy przy okazji zmienić w wierszu 7 nazwę kontekstu aplikacji [mvc-personne-02], która koliduje z nazwą projektu [mvc-personne-01]:
<property name="context-root" value="personne2"/>
Tę drugą zmianę można było wprowadzić bezpośrednio w Eclipse. Nie znalazłem jednak sposobu, aby dokonać pierwszej zmiany bez korzystania z pliku konfiguracyjnego.
Po wykonaniu tych czynności zapisujemy nowy plik [.content], a następnie zamykamy i ponownie uruchamiamy Eclipse, aby zmiany zostały uwzględnione.
Po ponownym uruchomieniu Eclipse spróbujmy wykonać operację, która wcześniej zakończyła się niepowodzeniem:
![]() | ![]() |
Tym razem projekt [mvc-personne-02] jest prawidłowo rozpoznawany. Dodajemy go do projektów skonfigurowanych do uruchamiania przez Tomcat:

6.3. Konfiguracja aplikacji internetowej [personne2]
Plik web.xml aplikacji /personne2 ma następującą treść:
<?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-02</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>urlControleur</param-name>
<param-value>
main
</param-value>
</init-param>
<init-param>
<param-name>lienRetourFormulaire</param-name>
<param-value>
Retour au formulaire
</param-value>
</init-param>
</servlet>
<!-- Mapowanie ServletPersonne-->
<servlet-mapping>
<servlet-name>personne</servlet-name>
<url-pattern>/main</url-pattern>
</servlet-mapping>
<!-- pliki powitalne -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Plik ten jest identyczny z plikiem z poprzedniej wersji, z wyjątkiem tego, że zawiera dwa nowe parametry inicjalizacyjne:
- wiersz 6: nazwa wyświetlana aplikacji internetowej została zmieniona na [mvc-personne-02]
- wiersze 31–36: definiują parametr konfiguracyjny o nazwie [urlControleur], który jest adresem URL [main] prowadzącym do serwletu [ServletPersonne]
- wiersze 37–42: definiują parametr konfiguracyjny o nazwie [lienRetourFormulaire], który jest tekstem linku powrotnego do formularza na stronach JSP, [erreurs.jsp] i [reponse.jsp].
Strona główna [index.jsp] ulega zmianie:
<%@ 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("/personne2/main");
%>
- wiersz 5: strona [index.jsp] przekierowuje klienta do adresu URL kontrolera [ServletPersonne] aplikacji [/personne2].
6.4. Kod widoków
6.4.1. Widok [formulaire]
Ten widok jest identyczny jak w poprzedniej wersji:

Jest on generowany przez następujące strony: JSP i [formulaire.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
// pobieranie danych z szablonu
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
<html>
<head>
<title>Personne - formulaire</title>
</head>
<body>
<center>
<h2>Personne - formulaire</h2>
<hr>
<form action="<%=urlAction%>" 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>
Nowości:
- w wierszu 19 formularz posiada teraz atrybut [action], którego wartością jest adres URL, pod który przeglądarka ma wysłać wartości formularza, gdy użytkownik kliknie przycisk [Envoyer] typu submit. Zmienna [urlAction] przyjmie wartość action="main". Widok [formulaire] jest wyświetlany po wykonaniu przez użytkownika następujących czynności:
- pierwsze żądanie: GET /osoba2/główna
- kliknięcie linku [Retour au formulaire]: GET /osoba2/main?action=retourFormulaire
Ponieważ atrybut [action] nie określa adresu URL bezwzględnego (zaczynającego się od /), lecz względnego (niezaczynającego się od /), przeglądarka wykorzysta pierwszą część adresu URL aktualnie wyświetlanej strony [/personne2] i doda do niej adres względny. Adres URL dla POST będzie zatem brzmiał [/personne2/main], czyli adres kontrolera. Do tego żądania POST dołączone zostaną parametry [txtNom, txtAge, action] z wierszy 23, 27 i 38.
- wiersz 8: pobierana jest wartość elementu [urlAction] z modelu. Jest ona wyszukiwana w atrybutach bieżącego żądania. Zostanie ona wykorzystana w wierszu 19.
- wiersze 6–7: pobierane są wartości elementów [nom, age] z modelu. Są one wyszukiwane w atrybutach sesji, a nie w atrybutach zapytania, jak miało to miejsce w poprzedniej wersji. Ma to na celu zaspokojenie potrzeb zapytania [GET /personne2/main?action=retourFormulaire] związanego z widokami [réponse] i [erreurs]. Przed wyświetleniem tych dwóch widoków kontroler umieszcza w sesji dane wprowadzone w formularzu, co pozwala mu je odzyskać, gdy użytkownik korzysta z linku [Retour au formulaire] widoków [réponse] i [erreurs].
6.4.2. Widok [reponse]
Ten widok wyświetla wartości wprowadzone w formularzu, o ile są one prawidłowe:
![]() | ![]() |
W porównaniu z poprzednią wersją nowością jest link [Retour au formulaire]. Widok jest generowany przez następującą stronę: JSP [reponse.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
// pobieranie danych z modelu
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>
<a href="?action=retourFormulaire"><%= lienRetourFormulaire %></a>
</body>
</html>
- wiersz 31: link powrotny do formularza. Link ten składa się z dwóch części:
- cel [href="?action=retourFormulaire"]. Widok [réponse] jest wyświetlany po widoku POST formularza [formulaire.jsp] pod adresem URL [/personne2/main]. To właśnie ten ostatni adres URL jest wyświetlany w przeglądarce, gdy wyświetlany jest widok [réponse]. Kliknięcie linku [Retour au formulaire] spowoduje wówczas wysłanie żądania GET przez przeglądarkę do adresu URL określonego przez atrybut [href] linku, w tym przypadku „?action=retourFormulaire”. W przypadku braku adresu URL w [href] przeglądarka użyje adresu aktualnie wyświetlanego widoku, c.a.d. [/personne2/main]. Ostatecznie kliknięcie linku [Retour au formulaire] spowoduje wysłanie żądania GET przez przeglądarkę do adresu URL [/personne2/main?action=retourFormulaire], c.a.d – adres URL kontrolera aplikacji wraz z parametrem [action], który wskazuje mu, co ma wykonać.
- Tekst linku. Będzie on częścią szablonu przekazanego stronie przez kontroler i pobranego w linii 10.
6.4.3. Widok [erreurs]
Ten widok sygnalizuje błędy wprowadzenia danych w formularzu:
![]() | ![]() |
W porównaniu z poprzednią wersją nowością jest link [Retour au formulaire]. Widok jest generowany przez następującą stronę: JSP [erreurs.jsp]:
<%@ 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");
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");
}//dla
%>
</ul>
<br>
<a href="?action=retourFormulaire"><%= lienRetourFormulaire %></a>
</body>
</html>
- wiersz 26: link powrotny do formularza. Link ten jest identyczny z linkiem w widoku [réponse]. Zachęcamy czytelnika do ponownego zapoznania się z objaśnieniami dotyczącymi tego widoku.
6.5. Testowanie widoków
Aby przeprowadzić testy powyższych widoków, duplikujemy ich strony JSP w folderze /WebContent/JSP projektu Eclipse:

Następnie w folderze JSP strony są modyfikowane w następujący sposób:
[formulaire.jsp]:
...
<%
// -- test: tworzy się szablon strony
session.setAttribute("nom","tintin");
session.setAttribute("age","30");
request.setAttribute("urlAction","main");
%>
<%
// pobieramy dane z szablonu
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
Dodano wiersze 4–5 w celu utworzenia szablonu wymaganego przez stronę w wierszach 11–13.
[reponse.jsp]:
<%
// -- test: tworzymy szablon strony
request.setAttribute("nom","milou");
request.setAttribute("age","10");
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// pobieramy dane z szablonu
String nom=(String)request.getAttribute("nom");
String age=(String)request.getAttribute("age");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
Wiersze 4–6 zostały dodane w celu utworzenia szablonu wymaganego przez stronę w wierszach 11–13.
[erreurs.jsp]:
<%
// -- test: tworzymy szablon strony
ArrayList<String> erreurs1=new ArrayList<String>();
erreurs1.add("erreur1");
erreurs1.add("erreur2");
request.setAttribute("erreurs",erreurs1);
request.setAttribute("lienRetourFormulaire","Retour au formulaire");
%>
<%
// pobieranie danych z szablonu
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
Wiersze 4–8 zostały dodane w celu utworzenia szablonu wymaganego przez stronę w wierszach 13–14.
Uruchommy Tomcat, jeśli jeszcze tego nie zrobiliśmy, a następnie wywołajmy następujące adresy URL:
![]() | ![]() |
![]() |
Otrzymujemy oczekiwane widoki.
6.6. Kontroler [ServletPersonne]
Kontroler [ServletPersonne] aplikacji internetowej [/personne2] będzie obsługiwał następujące akcje:
nr | żądanie | źródło | przetwarzanie |
1 | [GET /personne2/main] | adres URL wpisany przez użytkownika | - wyślij pusty widok [formulaire] |
2 | [POST /personne2/main] z parametrami [txtNom, txtAge, akcja] przesłane | kliknięcie 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ą prawidłowe, wyślij widok [reponse(nom,age)] |
3 | [GET /osoba2/main? action=powrótDoFormularza] | kliknij link [Powrót do formularz] w widokach odpowiedzi] i [erreurs]. | - wysłanie widoku [formulaire] wstępnie wypełnionego najnowszymi wprowadzonymi wartościami |
Mamy zatem nową akcję do przetworzenia: [GET /personne2/main?action=retourFormulaire].
6.6.1. Szkielet kontrolera
Szkielet kontrolera [ServletPersonne] jest niemal identyczny jak w poprzedniej wersji:
Nowości:
- wiersz 4: korzystanie z sesji wymaga zaimportowania pakietu [HttpSession]
- wiersze 28–30: nowa metoda [doRetourFormulaire] obsługuje nową akcję: [GET /personne2/main?action=retourFormulaire].
6.6.2. Inicjalizacja kontrolera [init]
Metoda [init] jest identyczna jak w poprzedniej wersji. Sprawdza ona obecność w pliku [web.xml] elementów zadeklarowanych w tablicy [paramètres]:
- wiersz 5: dodano parametry [urlControleur] (adres URL kontrolera) oraz [lienRetourFormulaire] (tekst linku w widokach [réponse] i [erreurs]).
6.6.3. Metoda [doGet]
Metoda [doGet] musi obsłużyć akcję [GET /personne2/main?action=retourFormulaire], która wcześniej nie istniała:
- wiersze 6–14: sprawdzamy, czy lista błędów inicjalizacji jest pusta. Jeśli tak nie jest, wyświetlamy widok [erreurs(erreursInitialisation)], który zgłosi błąd lub błędy.
Aby zrozumieć ten kod, należy przypomnieć sobie szablon widoku [erreurs]:
<%
// pobieranie danych z szablonu
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
Widok [erreurs] oczekuje w zapytaniu elementu klucza „erreurs”. Kontroler tworzy ten element w linii 8. Oczekuje on również elementu klucza „lienRetourFormulaire”. Kontroler tworzy ten element w linii 9. W tym przypadku tekst linku będzie pusty. W wysyłanym widoku [erreurs] nie będzie zatem żadnego linku. Jeśli bowiem wystąpiły błędy podczas inicjalizacji aplikacji, należy ją ponownie skonfigurować. Nie ma potrzeby proponowania użytkownikowi kontynuowania działania aplikacji za pomocą linku.
- wiersze 34–37: obsługa nowej akcji [GET /personne2/main?action=retourFormulaire]
6.6.4. Metoda [doInit]
Metoda ta przetwarza żądanie nr 1 [GET /personne2/main]. W odpowiedzi na to żądanie musi wysłać pusty widok [formulaire(nom,age)]. Jej kod wygląda następująco:
- wiersz 4: pobierana jest bieżąca sesja, jeśli istnieje, w przeciwnym razie jest tworzona (parametr true z getSession).
- wiersze 9–10: wyświetlany jest widok [formulaire]. Przypomnijmy model oczekiwany przez ten widok:
<%
// pobieranie danych z modelu
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
- wiersze 6–7: elementy [nom,age] z modelu widoku [formulaire] są inicjowane pustymi ciągami znaków i umieszczane w sesji, ponieważ właśnie tam oczekuje ich widok.
- wiersz 8: element [urlAction] modelu jest inicjowany wartością parametru [urlControleur] z pliku [web.xml] i umieszczany w zapytaniu.
6.6.5. Metoda [doValidationFormulaire]
Metoda ta przetwarza zapytanie nr 2 [POST /personne2/main], w którym przesłane parametry to [action, txtNom, txtAge]. Jej kod wygląda następująco:
- wiersze 5–6: z żądania klienta pobierane są wartości parametrów „txtNom” i „txtAge”.
- wiersze 8–10: wartości te są zapisywane w sesji, aby można je było odzyskać, gdy użytkownik kliknie link [Retour au formulaire] w widokach [réponse] i [erreurs].
- wiersze 12–19: sprawdzana jest poprawność wartości obu parametrów
- wiersze 21–28: jeśli któryś z parametrów jest nieprawidłowy, wyświetlany jest widok [erreurs(erreurs,lienRetourFormulaire)]. Przypomnijmy szablon tego widoku:
<%
// pobierane są dane z modelu
ArrayList erreurs=(ArrayList)request.getAttribute("erreurs");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
- wiersze 30–34: jeśli oba pobrane parametry „txtNom” i „txtAge” mają prawidłowe wartości, wyświetlany jest widok [reponse(nom,age,lienRetourFormulaire)]. 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");
String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
6.6.6. Metoda [doRetourFormulaire]
Metoda ta przetwarza zapytanie nr 3 [GET /personne2/main?action=retourFormulaire]. Jej kod jest następujący:
Po zakończeniu działania tej metody należy wyświetlić widok [formulaire], wstępnie wypełniony ostatnimi danymi wprowadzonymi przez użytkownika. Przypomnijmy szablon widoku [formulaire]:
<%
// pobieramy dane z szablonu
String nom=(String)session.getAttribute("nom");
String age=(String)session.getAttribute("age");
String urlAction=(String)request.getAttribute("urlAction");
%>
Metoda [doRetourFormulaire] musi zatem odtworzyć poprzedni szablon.
- wiersz 4: pobieramy sesję, w której kontroler zapisał wprowadzone wartości (imię, wiek).
- wiersz 7: pobieramy imię z sesji
- wiersze 8–9: jeśli nie ma go w sesji, umieszczamy go tam z pustą wartością. Taki przypadek nie powinien wystąpić podczas normalnego działania aplikacji, ponieważ akcja [retourFormulaire] zawsze następuje po akcji [validationFormulaire], a więc po zapisaniu wprowadzonych danych w sesji. Sesja może jednak wygasnąć, ponieważ ma ograniczony czas trwania, często wynoszący kilkadziesiąt minut. W takim przypadku w wierszu 4 utworzono nową sesję, w której nie ma jeszcze nazwy. W nowej sesji umieszcza się zatem pustą nazwę.
- wiersze 11–13: podobnie postępuje się w przypadku wieku
- jeśli pominąć problem wygasłej sesji, wówczas wiersze 3–13 są zbędne. Elementy [nom,age] z modelu znajdują się już w sesji. Nie ma więc potrzeby ponownego ich tam umieszczania.
- wiersz 15: ustalamy wartość elementu [urlAction] z szablonu
6.7. Tests
Uruchom lub ponownie uruchom serwer Tomcat. Wprowadź adres URL [http://localhost:8080/personne2], a następnie powtórz testy przedstawione w przykładzie w paragrafie 6.1.
















