1 Wprowadzenie

1.1 Servlet

Servlety to programy javowe po stronie serwera, umożliwiające generowanie dynamicznych stron WWW. Gdy powstały, szybko stały się bardzo chętnie stosowanym rozwiązaniem w aplikacjach internetowych.

Zalety:

- szybsze i potężniejsze od standardowych CGI

- przenośne

- rozszerzalne, łatwe do rozbudowy

Wady:

- konieczność używania wielu instrukcji println, co powoduje wymieszanie logiki z widokiem, bardzo źle wpływa na czytelność kodu.

1.2 JSP (Java Servlet Pages)

Rozwiązaniem na wielokrotne użycie instrukcji println stały się strony JSP.

Zalety:

- Pozwalają zamieszczać kod javy w stronie html

- Rozwiązują problem wielokrotnego użycia instrukcji println

- Wygodne użycie znaczników, dających możliwość dynamicznego generowania strony

- Ustalanie wyglądu strony za pomocą konfiguracji znaczników

Wady:
- Ograniczona kontrola przepływu

Powstał pomysł, by połączyć JSP i Servlety. Servlety zapewniałyby kontrolę przepływu, a JSP prostotę pisania kodu html.

1.3 Struts

Rozwiązanie polegające na połączeniu JSP z Servletami dostarczone zostało przez Jakarta Struts. Prace nad projektem Struts rozpoczęły się w maju 2000 roku pod przewodnictwem Craig R. McClanahan. Wersja 1.0 powstała w lipcu 2001 roku.

Zalety:

- łatwe generowanie interfejsów (html) oddzielone od przepływu sterowania

- oddzielenie warstw widoku, kontrolera i modelu

- łatwa, podmienialna konfiguracja przepływu i obsługi żądań

- podmienialne i rozszerzalne technologie oraz moduły używane w aplikacji, co pozwala na konfigurację przystosowaną odpowiednio do tej aplikacji.

Wady:

- trochę skomplikowana konfiguracja aplikacji

2 Struts jako realizacja Model-View-Controller

Strutsy bazują na realizacji wzorca Model-View-Controller.

Przepływ kontroli sterowany jest przez centralny Kontroler.

Logika biznesowa oraz stan aplikacji są reprezentowane przez Model.

Po obsłużeniu żądania, sterowanie przekazywane jest do widoku korzystając z mapowania zadanego w pliku konfiguracyjnym.

2.1 Model

Model realizowany przez Struts możemy podzielić na dwa podsystemy:

- podsystem opisujący wewnętrzny stan aplikacji

- podsystem zawierający zbiór możliwych do wykonania akcji, mogących zmienić stan systemu.

Stany systemu najczęściej realizowane są jako Java Beans. Właściwości Java Beanów reprezentują konfigurację systemu. W zależności od stopnia złożoności systemu, Beany te mogą same dbać o swój stan, albo być fasadami, które pobierają stan systemu z innego komponentu.

Komponenty, które zazwyczaj są wykorzystywane przez te Java Beany w celu pobrania stanu, to:

- bazy danych
- wyszukiwarki
- Entity EJB
- serwery LDAP

W aplikacjach dużego rozmiaru, model zazwyczaj jest dostępny jako zbiór metod, które można wywołać dla Java Beanów. Dzięki temu można na przykład wiązać beany z każdym użytkownikiem w celu przechowywania spersonalizowanej konfiguracji (np. zawartość koszyka w sklepie internetowym).

Możliwe jest też rozwiązanie, w którym za poszczególne rodzaje operacji odpowiadają konkretne obiekty. Takim rozwiązaniem na przykład są Session EJB.

W niewielkich aplikacjach możliwe jest zrezygnowanie z oddzielnych Java Beanów. Cała logika zastąpiona może być przez klasy Akcji Kontrolera. Rozwiązanie to występuje w aplikacjach, które mają bardzo prostą logikę biznesową bez potrzeby powielania kodu w różnych akcjach.

2.2 View

Warstwa widoku najczęściej oparta jest o JSP. JSP może zawierać zarówno statyczny HTML jak i dynamicznie tworzoną zawartość z użyciem specjalnych tagów.

Struts’y posiadają wiele zdefiniowanych tagów pozwalających zarządzać dynamicznie treścią strony. Ponadto istnieje możliwość tworzenia własnych bibliotek tagów.

Tagi Struts’owe ułatwiają tworzenie wielojęzycznych i uniwersalnych interfejsów użytkownika. Współpracują one z ActionForm beans, automatycznie przechwytując i walidując pola formularza.

2.3 Controller

Zadanie kontrolera skupione jest na przechwytywaniu żądań użytkownika (zazwyczaj klienta przeglądarek internetowych), decyzji która część logiki biznesowej powinna obsłużyć dane żądanie, a następnie przekazaniu żądania do odpowiedniego widoku, odpowiedzialnego za stworzenie interfejsu użytkownika.

Bazowym komponentem Kontrolera jest servlet ActionServlet. Jego konfiguracja polega na podaniu zbioru mapowań akcji (AcionMapping). Mapowanie akcji polega na podaniu ścieżki (najczęściej klasy), która jest mapowana do nadchodzącego żądania URI.

Wszystkie Akcje są podklasami org.apache.struts.action.Action.

Akcje interpretują żądanie, decydują o wywołaniu odpowiednich metod logiki biznesowej, a następnie decydują o przekazaniu żądania do konkretnego widoku.

Struts pozwalają na rozszerzanie ActionMapping o dodatkowe parametry, pozwalające skonfigurować działanie aplikacji w specyficzny, wygodniejszy sposób. Ponadto dozwolone jest używanie nazw dla mapowanych klas nie mających nic wspólnego z faktyczną lokalizacją przekierowania. Pozwala to na lepsze oddzielenie kontrolera od widoku.

2.4 Przepływ sterowania w Struts.

Podczas inicjalizacji, kontroler parsuje plik konfiguracyjny (struts-config.xml) i używa go do stworzenia obiektów kontrolera (między innymi ActionMappings).

Następnie kontroler wyszukuje ActionMapping dla aktualnego żądania. Żądanie może być sforwardowane do JSP albo do Akcji. Żądanie najczęśniejściej najpierw kierowane jest do Akcji wykonującej jakąś logikę biznesową a następnie akcja decyduje o przekierowaniu do strony JSP.

3 Konfiguracja Struts

3.1 struts-config.xml

Jest to plik konfiguracji aplikacji Struts, który stanowi bazę dla Kontrolera. Plik ten podzielony jest na następujące sekcje:

3.2.1 form-beans

Sekcja ta zawiera definicje formularzy używanych w aplikacji. Są to deskryptory używane do stworzenia instancji ActionForm. Każdy formularz opisuje się używając elementu <form-bean>, który posiada następujące atrybuty:

- name – unikalny identyfikator, który zostanie użyty przy mapowaniach akcji używających tego formularza.

- type – pełna nazwa klasy, która definiuje dany formularz. Klasa musi być podklasą ActionForm.

Przykład:
        <form-beans>
               <form-bean
                    name="logonForm"
                    type="org.apache.struts.webapp.example.LogonForm" />
        </form-beans>

3.2.2 global-exceptions

Możliwe jest zdefiniowanie centralnej obsługi dla wyjątków rzucanych przez akcje kontrolera. W tym celu należy zrobić własną klasę przedefiniującą ExcpetionHandler (metodę execute). Metoda ta powinna zwracać obiekt ActionForward, który mówi Strutsom gdzie mają przekierować sterowanie. Następnie dla takiego wyjątku definiujemy element <exception> w sekcji wyjątków. Element ma następujące parametry:

- handler – pełna nazwa klasy handlera

- type – pełna nazwa klasy wyjątku

- key – klucz z message resources, który może być użyty jako treść wyjątku

Częstym zastosowaniem centralnego mechanizmu wyjątków jest jego zdefiniowanie dla głównego wyjątku Exception, w celu stworzenia interfejsu i przechwytywania wszystkich niespodziewanych wyjątków, które wystąpią w aplikacji.

Przykład:
        <global-exceptions>
            <exception 
              key="some.key" 
              type="java.io.IOException" 
              handler="com.yourcorp.ExceptionHandler"/>
        </global-exceptions>

3.2.3 global-forwards

sekcja ta zawiera definicję globalnych przekierowań aplikacji. Przekierowania są instancjami klasy ActionForward. Przekierowania mapują nazwy logiczne do konkretnych zasobów (zazwyczaj stron JSP), co pozwala na podmianę zasobów widoku bez zmian w kodzie aplikacji. Dla każdego globalnego przekierowania używamy elementu <forward>, który posiada następujące atrybuty:

- name – Nazwa logiczna dla danego przekierowania, która używana jest w metodzie execute klas Action

- path – właściwa lokalizacja zasobu

- redirect – (true lub false). Określa, czy ActionServlet powinien przekierować żądanie (nowy request) do danego zasobu, zamiast jego przekazania.

Przykład:
        <global-forwards
         type="org.apache.struts.action.ActionForward">
                <forward 
                    name="logon" 
                    path="/logon.jsp"
                    redirect="false" />
        </global-forwards>

3.2.4 action-mappings

W tej sekcji zawarte są definicje wszystkich akcji aplikacji dostępnych klientowi. Dla każdego mapowania akcji używamy elementu <action>. Większość mapowań akcji zawiera przynajmniej następujące atrybuty:

- path – nazwa kontekstowa akcji, pod którą dostępna jest ta akcja

- type – pełna nazwa klasy akcji

- name – nazwa elementu <form-bean>, który będzie zainicjowany w tym żądaniu

- validate – czy przeprowadzać walidację formularza

Ponadto jako podelement może występować zbiór przekierowań lokalnych. Są one dostępne tylko przy obsłudze żądania korzystającego z danego mapowania akcji.

Przykład:
        <action-mappings>
                <action
                    path="/logon"
                    type="org.apache.struts.webapp.example.LogonAction"
                    name="logonForm"
                    validate="true" >
                       <forward 
                               name="failure" 
                               path="/mainMenu.jsp"/>
                       <forward 
                               name="success" 
                               path="/subscription.jsp"/>
               </action>
        </action-mappings>

3.2.5 controller

W tej sekcji dokonywana jest konfiguracja ActionServlet. Wiele parametrów Action Servleta zostanie ustawionych w web.xml, ale tutaj mogą być przedefiniowane w celu umożliwienia różnych konfiguracji różnym modułom aplikacji (korzystającym z różnych struts-config.xml).

3.2.6 message-resources

Strutsy mają wbudowane wsparcie dla aplikacji wielojęzycznych. Można zdefiniować jeden lub kilka źródeł zasobów. Różne moduły mogą korzystać z różnych plików zasobów. Definiując plik zasobów należy używać elementu <message-resource> z następującymi atrybutami:

- className – Bean z konfiguracją

- parameter - identyfikator pliku zasobów w aplikacji

Przykład:

<message-resources parameter="Application"/>

3.2.7 plug-in

Pluginy Strutsów są konfigurowane przy użyciu elementu <plug-in>. Element ten ma tylko jeden wymagany atrybut className, który definiuje interfejs pluginu.

3.2 web.xml

Należy jeszcze skonfigurować deskryptor aplikacji.

3.2.1 Konfiguracja servleta

Znajduje się tutaj podstawowa konfiguracja ActionServleta. Każda konfiguracja składa się z elementu <servlet>, posiadającego atrybuty

- servlet-name – nazwa mapowania
- servlet-class – klasa servletu

- init-param – atrybut określający lokalizacje struts-config.xml

Przykład:
   <servlet>
       <servlet-name>action</servlet-name>
       <servlet-class>
           org.apache.struts.action.ActionServlet
       </servlet-class>
       <init-param>
           <param-name>config</param-name>
           <param-value>
            /WEB-INF/struts-config.xml
           </param-value>
       </init-param>
       <load-on-startup>1</load-on-startup>
   </servlet>

3.2.2 Mapowanie servletów

Ponadto dokonane jest mapowanie żądań URI, które obsługiwane są przez konkretne servlety. Wykorzystywany jest element <servlet-mapping> z atrybutami:

- servlet-name – nazwa servletu ustalona w konfiguracji

- url-pattern – wzorzec adresów URI, które wykorzystują dany servlet

Przykład:
   <servlet-mapping>
       <servlet-name>action</servlet-name>
       <url-pattern>/do/*</url-pattern>
   </servlet-mapping>

3.2.3 Konfiguracja taglibów

Pozostaje jeszcze skonfigurować biblioteki Tagów Strutsów:

- struts-bean – Tagi do zarządzania beanami i ich konfiguracjami oraz definiowania nowych beanów

Przykład użycia:

<bean:write name=”user” property=”surname”/>

- struts-html – Tagi html między innymi dla pól formularza.

Przykład użycia:
<html:hidden name=”user” property=”id”/>

- struts-logic – tagi do zarządzania warunkowym generowaniem kodu.

Przykład:

<logic:iterate name=”user” property=”privileges” id=”privilege”>

<logic:equals name=”privilege” value=”3”>

</logic:equals>
</logic:iterate>

Dołączenie tagów Strutsowych do aplikacji odbywa się w pliku web.xml:

    <taglib>
         <taglib-uri>
         http://struts.apache.org/tags-bean
         </taglib-uri>
         <taglib-location>
         /WEB-INF/struts-bean.tld
         </taglib-location>
    </taglib>
    <taglib>
         <taglib-uri>
         http://struts.apache.org/tags-html
         </taglib-uri>
         <taglib-location>
         /WEB-INF/struts-html.tld
         </taglib-location>
    </taglib>
    <taglib>
         <taglib-uri>
         http://struts.apache.org/tags-logic
         </taglib-uri>
         <taglib-location>
         /WEB-INF/struts-logic.tld
         </taglib-location>
    </taglib>

Aby używać danej biblioteki Tagów w konkretnej stronie JSP należy zaimportować wybrane biblioteki w następujący sposób:

    <%@ taglib
            uri="http://struts.apache.org/tags-html"
            prefix="html" %>

4 Elementy Struts

Struty zawierają servlet, który implementuje główną funkcję mapowanie URI na klasę akcji. Dlatego do głównych zadań w części kontrolera należy :

- Napisać klasę ActionForm do pośredniczenia pomiędzy widokiem a modelem.

- Napisać akcję dla requestów, które mogą być otrzymane.
- Skonfigurować mapowanie w xmlu (struts-config.xml)

4.1 Action

Elementy kontrolera odpowiedzialne za „akcje” to klasy Javy które podklasowują klasę Action. Są w niej zdefiniowane dwie metody – jedna z nich zostanie wywołana w zależności od konfiguracji środowiska servletów.

public ActionForward execute(ActionMapping mapping,
                     ActionForm form,
                     ServletRequest request,
                     ServletResponse response)
throws Exception;
 
public ActionForward execute(ActionMapping mapping,
                     ActionForm form,
                     HttpServletRequest request,
                     HttpServletResponse response)
throws Exception;

W naszym przypadku interesuje nas metoda zawierająca requesty http – bo budujemy aplikacje webowe. Gdybyśmy tworzyli aplikację nie korzystającą z protokołu http, użylibyśmy tej drugiej metody.

Zadaniem obiektu klasy Action jest obsłużenie requestu (za pośrednictwem wyżej wymienionej metody). Metoda owa zwraca również obiekt klasy ActionForward, który informuje, dokąd ma zostać przekierowana kontrola (jsp, html, tiles, inna akcja, itp.) Biorąc pod uwagę standardowe zastosowania, można się domyślać, że akcja zapewni również następujące elementy logiki :

- Walidacja stanu sesji. Np. Sprawdzenie czy użytkownik jest zalogowany (czy ktos nie próbuje dostać się „do środka” aplikacji poprzez zakładkę, czy ręcznie wpisany link, czy sesja nie przeterminowała się, itp.

- Jeśli wykonywana akcje otrzymuje jakiś formularz, możliwa jest tutaj walidacja danych pól tegoż formularza.

- Niekiedy może się zdarzyć, że w akcji będzie również obrobienie żądania typu np. zapisanie / pobranie czegoś z bazy danych (choć ta część powinna się odbywać poprzez odpowiednie beany, które stąd wywołamy)

- Uaktualnienie stanu obiektów istniejących po stronie serwera (zazwyczaj w obszarze requestu lub sesji – w zależności od żywotności owych obiektów).

- Zwrócenie obiektu klasy ActionForward, który prowadzi do strony mającej się wyświetlić po przetworzeniu otrzymanego requestu. Zazwyczaj będzie to jakieś mapowanie globalne lub lokalne (ze struts-config.xml).

Metoda rzuca wyjątek, jeśli wystąpią jakieś błędy. To może być nieprzyjemny moment w aplikacji, jeśli nie mamy nigdzie zdefiniowanego wyłapywania wyjątków.

Tipsy wujka „dobra rada” o Akcjach :

1) Servlet kontrolujący tworzy tylko jedną instancję Akcji, i używa jej do obsłużenia wszystkich żądań. Dlatego warto :

a) używać tylko lokalnych zmiennych

b) zachowywanie zasobów – wszelki próby np. trzymania połączeń z bazą danych tylko dla jednego usera w czasie jego sesji może powodować poważne problemy ze skalowalnością.

2)NIE rzucać wyjątkami w akcjach… - bardzo brzydko wyglądają strony webowe, które wykraczają się z błedęm 500 – internal Server terror i zasypują user-a treścią dziwnego stack trace’a…

3) Unikaj długaśnego kodu w akcjach. „Logika biznesowa” zdecydowanie powinna być przeniesiona do innych warstw aplikacji. Przeładowana akcja może się okazać ciężka do zrozumienia, podklasowania, ponownego użycia…

4.2 FormAction

ActionForm reprezentuje formularze ze stron html-owych. Musi zawierać pola trzymające informacje i gettery i settery zapewniające dostęp do nich. Formularze mogą być przechowywane albo w requeście, albo w sesji. Warto pamiętać o implementacji metody reset – jeśli zamierzamy je trzymać w sesji.

Ważne rzeczy do zapamiętania :

- ActionFormy w zasadzie nie implementują żadnych dodatkowych metod. Mają tylko reprezentować formularz w ogólnej architekturze i zawierają tylko pola trzymające informację i akcesory do nich.

- Automatyczna walidacją. Ewentualnie można dostarczyć metodę walidującą formularz. Możemy w niej dokonać walidacji pól i zwrócić null, jeśli walidacja jest pomyślna, lub obiekt klasy ActionErrors zawierający błędy napotkane podczas walidacji. Można też nie tworzyć tej metody i walidacji dokonać w akcji, albo przy użyciu np. Validatora, o którym mowa będzie za chwilę.

- Akcesory MUSZĄ odpowiadać konwencji Javowej getXxx, setXxx – bazuje na tym mechanizm obsługujący formy.

- Przyciski i podobne kontrolki też mogą być reprezentowane w formie – w ten sposób np. można wiedzieć, której kontrolki użyto.

- Można Ew. utworzyć beana zawierającego formularz i udostępniać jego obiekty, ale trzeba to mądrze przemyśleć, jakie obiekty udostępniamy do ogólnego użytku…

4.2.1 DynaActionForm

Czasem tworzenie obiektu formularza dla każdego form-a w aplikacji może być uciążliwe i nieprzyjemne, zwłaszcza dla prostych i często używanych danych. Rozwiązaniem dla tego problemu są dynamiczne formularze.

Wystarczy w mapowaniu odpowiednio je zdefiniować. DynaActionForm sam stworzy odpowiednią klasę. Obsługuje wszystkie proste typy, integery, springi itp. A także tablice, hashmapy.

4.3 ExceptionHandler

Można zdefiniować obsługę wyjątków, która zadziała, gdy akcja rzuci wyjątkiem. W tym celu należy podklasować ExceptionHandler i override’ować metodę execute. Powinna ona obsłużyć wyjątek i zwrócić obiekt klasy ActionForward, który przekieruje do odpowiedniej strony. Można również w xmlu zdefiniować osobne handlery dla różnych klas wyjątków. W szczególności można nie podklasowywać ExceptionHandler-a, tylko skonfigurować go w xmlu.

5 Rozszerzenia

Strutsy posiadają również interfejs pozwalający na dodawanie rozszerzeń.

Aby podłączyć rozszerzenie należy dodać do pliku konfiguracyjnego (struts-config.xml) wpis zawierający informacje o rozszerzeniu i głównej klasie. Klasa ta musi implementować interfejs Plugin.

Np. :
<plug-in className="org.apache.struts.tiles.TilesPlugin">
    <set-property
        property="definitions-config"
           value="/WEB-INF/tiles-defs.xml"/>
</plug-in>

5.1 Validator

Validator jest przykładem miłego rozszerzenia, które pozwala na elegancką walidację danych w formularzach.

Aby umożliwić walidację z użyciem tego plugina musi być spełnione kilka warunków :

1) bean formularza (ActionForm) musi podklasowywać klasę ValidatorForm.

2) Jsp-ek zawierający formularz musi zawierać tag <html:javascript> - bo validator opiera walidację na javascripcie (bardzo fajny feature zmniejszający obciążenie serwera).

3) Mapowanie formularza musi być według szablonu :
<form-validation>
<formset>             
<form name="logonForm">
  <field property="username" depends="required">
    <msg name="required" key="error.username"/>
  </field>    
</form>        
</formset>   
</form-validation>

4) Validator musi być podłączony tak jak mowa w pkt. 5 :) czyli : w struts-config.xml musi być wpis …

 
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property 
property="pathnames" 
value="/WEB-INF/validator-rules.xml, 
    /WEB-INF/validation.xml"/>
</plug-in>

5.2 Tiles

Tilesy to cały potężny dodatek do strutsów. Nie będziemy go tutaj szczegółowo omawiać, ale chcemy zasygnalizować jego istnienie i duże, przydatne możliwości.

Opiszemy więc króciutko jak go podłączyć :
1) utworzyć plik jsp zawierający layout strony. Np. :
 
<html>
<body>
<tiles:insert attribute="body"/>
</body>
</html>
2) Tworzymy treść strony głównej, np. :
<h1>This is my homepage</h1>
3) Mapujemy wygląd strony w tiles-defs.xml
<tiles-definitions>
<definition 
    name="layout" 
    path="/layout/layout.jsp">
    <put name="body" value=""/>
</definition>
<definition name="homepage" extends="layout">
    <put 
        name="body" 
        value="/index.jsp"/>
</definition>
<tiles-definitions>

4) Podłączamy plugin do strutsów :

<plug-in 
    className="org.apache.struts.tiles.TilesPlugin">
    <set-property 
        property="definitions-config" 
        value="/WEB-INF/tiles-defs.xml"/>
</plug-in>

5) Teraz możemy już tilesowych definicji używać w mapowaniu, np. :

<action 
path="/index"
type="org.apache.struts.actions.ForwardAction"
parameter="homepage"/>

5.3 Tlds

Strutsy pozwalają również na tworzenie własnych bibliotek Tagów.

Możemy napisać w Javie treść taga i umożliwić używanie takiego taga w jsp-kach.

Np. w jspk-u piszemy :
<customTag:linkUser/>

A w wynikowym html-u będzie w tym miejscu np. link do strony z informacjami o użytkowniku. Javowa klasa obsługująca tego taga, sprawdzi kto jest obecnie zalogowany i spreparuje odpowiednią ścieżkę do linku.

Aby móc z takich Tagów korzystać musimy jeszcze udostępnić informacje o ich użyciu w pliku z rozszerzeniem tld.

Przykładowy wpis w takim pliku :
 
  <tag>
    <name>currentDate</name>
    <tag-class>net.sf.zpptw.tf.taglib.CurrentDateTag</tag-class>
    <body-content>JSP</body-content>
    <description>Wypisuje biezaca date.</description>
  </tag>

5.4 Application properties

Strutsy korzystają z propertiesów – mechanizmu Javowego, który w bardzo ułatwia lokalizację językową aplikacji.

Tworzymy plik Application_XX.properties, gdzie XX oznacza skrót nazwy języka.

W takim pliku umieszczamy zbiór kluczy i wartości.

Pod danym kluczem umieszczamy treść komunikatów – w ten sposób obsługujemy wszystkie napisy, które chcemy wyświetlić użytkownikowi.

Np. :
login.button.save=Zapisz

Pod tymi samymi nazwami kluczy umieszczamy w różnych plikach językowych odpowiednie zlokalizowane komunikaty.

Dodatkowo, jeśli chcemy żeby napisy zawierały jakieś dodatkowe parametry, możemy zasygnalizować ich obecność w nawiasach klamrowych, np. :

login.successful.message=Zalogowany {0}. Dzień dobry !

Następnie parametry przekazujemy w odpowiednich metodach, które dają dostęp do tych wartości.

6 Przykład

7 Zadania

Napisz aplikację HelloWorld, o następującej specyfikacji :

Ekran powitalny prosi użytkownika o podanie Imienia, wieku i adresu zamieszkania.

Sprawdzamy, czy formularz jest poprawnie wypełniony, tzn :

Czy kod jest prawidłowy, czy wiek jest z „sensownego” zakresu.

Wypełnienie wszystkich pól jest obowiązkowe.

Jeśli formularz nie przejdzie walidacji – wyświetlamy stosowne informacje.

Jeśli przejdzie, wyświetlamy stronę powitalną, gdzie poczęstujemy użytkownika powitaniem („Hello World” ;) ) zwracając się do niego po imieniu.

Po rozpoznaniu użytkownika umożliwiamy mu zmianę języka na angielski / niemiecki / polski (jeden z nich nie powinien się wyświetlać w zależności od wybranego).

Niestety nasza aplikacja nie zawsze działa. Raz na kilka prób zmiany języka akcja powinna rzucić wyjątkiem „Program wykonał nieprawidłową operację. Skontaktuj się ze swoim sprzedawcą.”

W takiej sytuacji chcemy przekierować użytkownika na stronę z informacją, że wybrana przez niego strona nie jest obecnie dostępna i zaproszeniem do późniejszego ponownego spróbowania.

8 Źródła