Darmowy fragment publikacji:
Java Enterprise Edition to standard tworzenia aplikacji biznesowych wykorzystujących język Java. Opracowany
przez fi rmę Sun Microsystems, działa w oparciu o wielowarstwową architekturę komponentową, oferując pro-
gramistom bardzo rozbudowane możliwości tworzenia oprogramowania funkcjonującego na niemal dowolnym
sprzęcie, w każdym systemie operacyjnym, z wykorzystaniem licznych serwerów aplikacji. Duża popularność
rozwiązań Java EE i coraz powszechniejszy dostęp do technologii WWW sprawiają, że programiści sprawnie
posługujący się tego rodzaju narzędziami rzadko fi gurują na listach osób poszukujących pracy, a jeśli już jakimś
cudem się na nich znajdą, bardzo szybko otrzymują atrakcyjne propozycje zatrudnienia. Nauka swobodnego poru-
szania się w tym środowisku może też być wspaniałą, poszerzającą horyzonty przygodą, a gdy poznasz platformę
Java EE, będziesz dysponował potężnym narzędziem, ułatwiającym tworzenie nawet najbardziej skomplikowa-
nych aplikacji internetowych w bardzo efektywny i szybki sposób.
Studenci, programiści i hobbyści pragnący poznać środowisko Java Enterprise Edition często napotykają problem
ze znalezieniem solidnych źródeł wiedzy, które pozwoliłyby im szybko i łatwo wejść w świat tej coraz bardziej
popularnej technologii. Lukę tę z powodzeniem wypełnia książka „Java EE 6. Programowanie aplikacji WWW”.
Dzięki niej wszyscy zainteresowani tematem zyskają możliwość poznania Java EE od podstaw i zdobycia prak-
tycznej wiedzy, na podstawie której będą mogli rozwij ać swoje umiejętności programistyczne w przyszłości. Ten
podręcznik pozwala na szybkie rozpoczęcie przygody z tworzeniem aplikacji webowych, skutecznie wprowadzając
w zagadnienia wykorzystywanych przy tym platform i mechanizmów, lecz nie pomij ając też informacji o charak-
terze ogólnym. Jeśli niewiele mówią Ci skróty JSP, JPA, JSF czy JPQL, a chciałbyś zmienić ten stan rzeczy, bez
wątpienia powinieneś sięgnąć po tę książkę, podobnie jak wszystkie osoby zainteresowane bezproblemowym
używaniem całego spektrum nowoczesnych narzędzi oferowanych przez środowisko Java EE.
Tworzenie serwletów
Zastosowanie szablonów JSP
Integracja danych z aplikacjami za pomocą mechanizmu JPA
Używanie interfejsów i komponentów
Korzystanie z technologii JSF
Uniwersalny i wygodny dostęp do danych, czyli język JPQL
Praktyczne przykłady realizacji
SPRAW, ABY TWORZENIE APLIKACJI WWW Z WYKORZYSTANIEM
JAVA EE NIE MIAŁO PRZED TOBĄ TAJEMNIC.
37,00 zł
5 6 1 5
Krzysztof Rychlicki-Kicior
K
r
z
y
s
z
t
o
f
R
y
c
h
l
i
c
k
i
-
K
c
o
r
i
i
J
a
v
a
E
E
6
P
r
o
g
r
a
m
o
w
a
n
e
a
p
i
l
i
k
a
c
j
i
W
W
W
Java EE 6
Programowanie aplikacji WWW
Szybko i bez kłopotów poznaj Java Enterprise Edition
Naucz się praktycznie tworzyć ciekawe aplikacje WWW
Dołącz do elity programistów nowoczesnych rozwiązań webowych
Już dziś sięgnij po jedyne kompendium wiedzy na temat Java EE!
Java EE 6.
Programowanie
aplikacji WWW
Autor: Krzysztof Rychlicki-Kicior
ISBN: 978-83-246-2659-5
Format: 158×235, stron: 232
(cid:127) Szybko i bez k³opotów poznaj Java Enterprise Edition
(cid:129) Naucz siê praktycznie tworzyæ ciekawe aplikacje WWW
(cid:129) Do³¹cz do elity programistów nowoczesnych rozwi¹zañ webowych
Ju¿ dziœ siêgnij po jedyne kompendium wiedzy na temat Java EE!
Java Enterprise Edition to standard tworzenia aplikacji biznesowych wykorzystuj¹cych
jêzyk Java. Opracowany przez firmê Sun Microsystems, dzia³a w oparciu o wielowarstwow¹
architekturê komponentow¹, oferuj¹c programistom bardzo rozbudowane mo¿liwoœci
tworzenia oprogramowania funkcjonuj¹cego na niemal dowolnym sprzêcie, w ka¿dym
systemie operacyjnym, z wykorzystaniem licznych serwerów aplikacji. Du¿a popularnoœæ
rozwi¹zañ Java EE i coraz powszechniejszy dostêp do technologii WWW sprawiaj¹,
¿e programiœci sprawnie pos³uguj¹cy siê tego rodzaju narzêdziami rzadko figuruj¹ na
listach osób poszukuj¹cych pracy, a jeœli ju¿ jakimœ cudem siê na nich znajd¹, bardzo
szybko otrzymuj¹ atrakcyjne propozycje zatrudnienia. Nauka swobodnego poruszania
siê w tym œrodowisku mo¿e te¿ byæ wspania³¹, poszerzaj¹c¹ horyzonty przygod¹,
a gdy poznasz platformê Java EE, bêdziesz dysponowa³ potê¿nym narzêdziem,
u³atwiaj¹cym tworzenie nawet najbardziej skomplikowanych aplikacji internetowych
w bardzo efektywny i szybki sposób.
Studenci, programiœci i hobbyœci pragn¹cy poznaæ œrodowisko Java Enterprise Edition
czêsto napotykaj¹ problem ze znalezieniem solidnych Ÿróde³ wiedzy, które pozwoli³yby
im szybko i ³atwo wejœæ w œwiat tej coraz bardziej popularnej technologii. Lukê tê
z powodzeniem wype³nia ksi¹¿ka „Java EE 6. Programowanie aplikacji WWW”.
Dziêki niej wszyscy zainteresowani tematem zyskaj¹ mo¿liwoœæ poznania Java EE od
podstaw i zdobycia praktycznej wiedzy, na podstawie której bêd¹ mogli rozwijaæ swoje
umiejêtnoœci programistyczne w przysz³oœci. Ten podrêcznik pozwala na szybkie
rozpoczêcie przygody z tworzeniem aplikacji webowych, skutecznie wprowadzaj¹c
w zagadnienia wykorzystywanych przy tym platform i mechanizmów, lecz nie pomijaj¹c
te¿ informacji o charakterze ogólnym. Jeœli niewiele mówi¹ Ci skróty JSP, JPA, JSF
czy JPQL, a chcia³byœ zmieniæ ten stan rzeczy, bez w¹tpienia powinieneœ siêgn¹æ po tê
ksi¹¿kê, podobnie jak wszystkie osoby zainteresowane bezproblemowym u¿ywaniem
ca³ego spektrum nowoczesnych narzêdzi oferowanych przez œrodowisko Java EE.
(cid:129) Tworzenie serwletów
(cid:129) Zastosowanie szablonów JSP
(cid:129) Integracja danych z aplikacjami za pomoc¹ mechanizmu JPA
(cid:129) U¿ywanie interfejsów i komponentów
(cid:129) Korzystanie z technologii JSF
(cid:129) Uniwersalny i wygodny dostêp do danych, czyli jêzyk JPQL
(cid:129) Praktyczne przyk³ady realizacji
Spraw, aby tworzenie aplikacji WWW z wykorzystaniem Java EE nie mia³o przed Tob¹ tajemnic
Spis treści
Część I Podstawy ....................................................................... 7
Rozdział 1. Java EE — naprawdę krótkie wprowadzenie ...................................... 9
Web vs Enterprise ........................................................................................................... 10
Serwery aplikacji ............................................................................................................ 11
Streszczenie, czyli krótki przewodnik po niniejszej publikacji ...................................... 11
Serwlety — na dobry początek ................................................................................. 11
Deskryptor wdrożenia .............................................................................................. 12
JSP — HTML + Java ............................................................................................... 13
JPA — czas na dane! ................................................................................................ 13
JSF — wyższy poziom prezentacji ........................................................................... 13
Facelets ..................................................................................................................... 14
Rozdział 2. Pierwsza aplikacja webowa ............................................................ 15
Integrowanie Tomcata z Netbeansem ............................................................................. 16
Pierwsza aplikacja .......................................................................................................... 17
Dodawanie nowych elementów ...................................................................................... 18
Pierwszy serwlet? ........................................................................................................... 20
Rozdział 3. Serwlet — na dobry początek ......................................................... 25
Życie serwletu ................................................................................................................ 25
Serwlet pod lupą ............................................................................................................. 26
Żądanie — odpowiedź .................................................................................................... 27
Przesyłanie odpowiedzi ............................................................................................ 29
Om nom nom, czyli ciasteczka w pełnej krasie ........................................................ 31
Sesje — nie tylko dla studentów .............................................................................. 31
Konfiguracja w kodzie Javy — można tego uniknąć ...................................................... 33
Parametry serwletów ................................................................................................ 34
Kontekst serwletów .................................................................................................. 35
Trzech muszkieterów? .................................................................................................... 36
Atrybuty a mnogość żądań ....................................................................................... 36
Słuchowisko ................................................................................................................... 39
ServletContextListener ............................................................................................. 39
ServletContextAttributeListener ............................................................................... 39
ServletRequestAttributeListener i ServletRequestListener ....................................... 39
HttpSessionAtributteListener i HttpSessionListener ................................................ 40
4
Java EE 6. Programowanie aplikacji WWW
HttpSessionBindingListener ..................................................................................... 40
Sesja + wiele JVM = HttpSessionActivationListener ............................................... 40
Filtry ............................................................................................................................... 41
Techniczny aspekt filtrów ........................................................................................ 41
Konfiguracja filtrów w pliku web.xml ..................................................................... 42
Rozdział 4. JSP — gdy out.println() nie wystarcza ............................................. 45
Zacznijmy od początku, czyli JSP w świecie serwletów ................................................ 46
Pliki JSP dostępne bezpośrednio .............................................................................. 46
Pliki JSP wywoływane z poziomu serwletów .......................................................... 46
Pochodzenie JSP — dziedzictwo serwletów .................................................................. 47
Pierwsze kroki w JSP ..................................................................................................... 47
Docenić wygodę, czyli jak to lat temu kilka bywało… ............................................ 50
Expression Language — elegancja i wygoda ................................................................. 54
Remedium — warto było czekać! ............................................................................ 55
Dostęp do obiektów w języku EL ............................................................................. 56
Beany, czyli ziarna — kult kawy wiecznie żywy ..................................................... 57
Ziarna + EL = kolejne ułatwienie ............................................................................. 58
Ziarna, mapy i co dalej? ........................................................................................... 59
EL — nie tylko atrybuty ........................................................................................... 59
Akcje JSP ....................................................................................................................... 61
Include vs Forward — odsłona druga ....................................................................... 62
Akcje + ziarna = kolejne potężne narzędzie ............................................................. 63
Dynamiczne generowanie elementów ...................................................................... 66
Rozdział 5. JSTL — wisienka na torcie JSP ....................................................... 69
Skrzynka z narzędziami .................................................................................................. 69
Rdzeń .............................................................................................................................. 70
c:out .......................................................................................................................... 70
Ale to już było, czyli c:set ........................................................................................ 72
Czwarty muszkieter .................................................................................................. 73
Kontrola sterowania ................................................................................................. 73
Pętelka do kompletu ................................................................................................. 75
Wyjątki + JSP = … .................................................................................................. 76
Adresy URL — same kłopoty ........................................................................................ 77
Adresy URL bez tajemnic ........................................................................................ 77
Tajemnica sesji… ..................................................................................................... 78
Trzech tenorów ............................................................................................................... 79
Na deser — funkcje! ....................................................................................................... 80
Przez kolekcje do serca ............................................................................................ 80
Funkcje łańcuchowe ................................................................................................. 81
Podsumowanie ................................................................................................................ 82
Część II Frameworki webowe ..................................................... 83
Rozdział 6. JavaServer Faces ........................................................................... 85
Frameworki — kolejny dowód na lenistwo człowieka ................................................... 85
JSF — kanonu ciąg dalszy .............................................................................................. 86
JSF, czyli MVC w praktyce ...................................................................................... 87
Kontroler — uniwersalny spawacz ........................................................................... 88
Małe zanurzenie .............................................................................................................. 88
Pierwsze przykłady .................................................................................................. 89
Aplikacja Notowania giełdowe ....................................................................................... 90
Tajemniczy zapis — # vs $ ...................................................................................... 95
Notowania historyczne, czyli kolekcja w kolekcji ................................................... 97
Spis treści
5
Najpierw szablon, później treść ................................................................................ 98
Klient szablonu ......................................................................................................... 99
Przygotowania… .................................................................................................... 100
Czas na obliczenia! ................................................................................................. 103
Mały zastrzyk ......................................................................................................... 105
JSF — komponenty, komponenty, komponenty! ......................................................... 106
Output — (prawie) wszystko, czego do szczęścia potrzeba ................................... 107
UIInput — teraz do szczęścia nie brakuje już nic ................................................... 108
Powrót do szarej rzeczywistości… ......................................................................... 112
Zasady działania JSF .................................................................................................... 115
Przykładowa aplikacja — maszyna licząca ............................................................ 115
Przywrócenie widoku (1) ....................................................................................... 118
Pobranie danych z żądania (2) ................................................................................ 119
Walidacja (3) .......................................................................................................... 119
Aktualizacja wartości w modelu (ziarnach — 4) .................................................... 120
Wywołanie zadeklarowanych uprzednio metod (5) ............................................... 120
Renderowanie odpowiedzi (6) ................................................................................ 120
Cykl życia w praktyce .................................................................................................. 120
Podsumowanie .............................................................................................................. 121
Rozdział 7. Konwertowanie i walidacja ........................................................... 123
Uroki transformacji ...................................................................................................... 123
Konwertery standardowe ........................................................................................ 124
Piszemy konwerter! ................................................................................................ 126
Walidator — nieodłączny partner konwertera .............................................................. 130
Walidatory — prawie jak konwertery .................................................................... 131
Walidacja niestandardowa — jak zawsze więcej pracy .......................................... 132
Część III Obsługa danych .......................................................... 135
Rozdział 8. JPA, czyli ORM + Java .................................................................. 137
Dostęp do danych w Javie ............................................................................................ 137
Oświecenie ............................................................................................................. 138
Pierwszy przykład ........................................................................................................ 139
Założenia ................................................................................................................ 139
Realizacja ............................................................................................................... 139
Tworzenie projektu ................................................................................................ 140
Hibernate a JPA — co i jak w ORM-owym świecie .............................................. 141
Pierwsza klasa encji ............................................................................................... 141
Jednostka utrwalania .............................................................................................. 145
Graficzna strona aplikacji ....................................................................................... 146
Dodawanie przychodni ........................................................................................... 150
EntityManager i spółka… ...................................................................................... 152
Menedżer encji — elegancki dostęp != łatwa sprawa ............................................ 153
Nudni słuchacze — nareszcie przydatni! ............................................................... 156
C już jest, czas na RUD .......................................................................................... 158
Niewiele Ci mogę dać… (póki nie pozwolisz mi zaprezentować danych) ............. 158
Słuchacz akcji vs akcja — starcie numer 2 ............................................................. 160
Istotny drobiazg — nasza aplikacja to niemowa! ................................................... 162
Rozdział 9. Związki między encjami — jedna tabela to za mało! ...................... 165
Przychodnia… i co dalej? ............................................................................................. 165
Związki między tabelami — krótkie przypomnienie .............................................. 165
Związki SQL w praktyce ........................................................................................ 166
Jeden do wielu, wiele do jednego ........................................................................... 167
6
Java EE 6. Programowanie aplikacji WWW
Wiele do wielu — najwyższy stopień wtajemniczenia ........................................... 167
Dodajemy tabele do bazy ....................................................................................... 168
Encje klas Javy — czas na związki! ............................................................................. 170
Encja Przychodnia — zmiana na lepszy model ...................................................... 171
Czas na nowości! .................................................................................................... 172
Wizyta — encja JPA w pełnej krasie ..................................................................... 178
CRUD dla lekarza — to już było, ale nie do końca ...................................................... 183
Nowy lekarz — nowe pole, duża zmiana ............................................................... 184
Magikonwersja ....................................................................................................... 185
Ziarnko do ziarnka i zbierze się aplikacja .............................................................. 186
Kolejne metody ziarna LekarzBean… .................................................................... 188
Na zakończenie — edycja ...................................................................................... 189
Pacjenci — suplement ............................................................................................ 191
Danie główne: all in one, czyli wizyty! ........................................................................ 192
Od czegoś trzeba zacząć, czyli zmiany ................................................................... 193
Dodawanie wizyty .................................................................................................. 196
Ostatnie ziarno ....................................................................................................... 197
Edycja i usuwanie — powrót ................................................................................. 200
Koniec coraz bliżej, czyli edycja w pełnej krasie ................................................... 201
Podsumowanie .............................................................................................................. 202
Rozdział 10. JPQL i jego możliwości ................................................................. 203
Prawie jak SQL… „prawie” robi różnicę ..................................................................... 203
Podstawy ...................................................................................................................... 204
Pobieranie z wariantami ......................................................................................... 204
JPQL a atrybuty złożone i null ............................................................................... 206
Nieco więcej o SELECT ........................................................................................ 207
Funkcje obliczeniowe ............................................................................................. 208
Operacje niezwiązane z pobieraniem ..................................................................... 209
Mechanizmy zaawansowane ........................................................................................ 209
JOIN na lewo, JOIN na prawo… ............................................................................ 210
Grupowanie i sortowanie ........................................................................................ 211
Podzapytania — prawdziwa moc ........................................................................... 212
Podsumowanie .............................................................................................................. 213
Dodatki ..................................................................................... 215
Dodatek A Instalacja serwera Apache Tomcat ............................................... 217
Pobranie ........................................................................................................................ 217
Konfiguracja ................................................................................................................. 217
Dodatek B Bibliografia .................................................................................. 219
Skorowidz ....................................................................................................... 221
Rozdział 3.
Serwlet
— na dobry początek
Aplikacja z poprzedniego rozdziału wprowadziła kilka istotnych elementów, których
omawianiem zajmiemy się w przeciągu najbliższych trzech rozdziałów. Rozpocznie-
my od podstawy podstaw, czyli elementu, który jest wykorzystywany pośrednio lub
bezpośrednio we wszystkich aplikacjach webowych — mowa o serwlecie.
Serwlet, czyli klasa rozszerzająca możliwości serwera aplikacji, może być traktowany
jako pojęcie niesłychanie ogólne. Praktycznie jedynym istotnym wymaganiem sta-
wianym serwletom jest działanie w trybie żądanie — odpowiedź — serwlet powinien
generować treść odpowiedzi w oparciu o to, co otrzyma w żądaniu. W poprzednim
rozdziale spotkałeś się z jednym z typowych zastosowań serwletów — generowaniem
kodu HTML. Nie jest to jednak w żadnym razie kres ich możliwości — nic nie stoi
na przeszkodzie, aby za pomocą serwletów generować zarówno dane tekstowe (np.
w formacie XML), jak i dane binarne (np. pliki wykonywalne, obrazy, etc.). Zanim
jednak zabierzemy się za praktyczne przykłady (pierwszy z nich mogłeś przeanali-
zować w poprzednim rozdziale), konieczne jest krótkie wprowadzenie teoretyczne,
w którym dowiesz się, jak serwlet współpracuje z serwerem aplikacji, a także jakie
podstawowe opcje związane z serwletami można ustawić w pliku web.xml.
Życie serwletu
Gdy uruchamiasz zwykłą aplikację, graficzną lub konsolową, w swoim systemie ope-
racyjnym, możesz w większości przypadków określić precyzyjnie, kiedy rozpoczyna
się, a kiedy kończy jej działanie. W przypadku popularnych technologii dynamicznych
stron internetowych (np. PHP) pliki są interpretowane na bieżąco (aczkolwiek istnieje
możliwość ich pośredniej kompilacji). Jak można opisać cykl życia serwletu?
Zacznijmy od klasy w takiej postaci, jaką już znamy — nieskompilowanego kodu źró-
dłowego. Zanim serwer zostanie uruchomiony, wszystkie pliki klas muszą zostać pod-
dane kompilacji. Powstałe pliki (o rozszerzeniu .class) są kopiowane do odpowiednich
26
Część I ♦ Podstawy
katalogów. Dopiero wtedy serwer może być uruchomiony, na nowo lub ponownie. Na
szczęście w nowszych wersjach serwerów aplikacji (np. Apache Tomcat 6) istnieje
możliwość automatycznego wykrywania i aktualizacji klas w trakcie działania serwera.
Gdy uruchamiasz serwer aplikacji, z punktu widzenia naszego serwletu nie dzieje się
nic istotnego. Następuje wtedy, rzecz jasna, inicjalizacja samego serwera, a także nie-
których ustawień całej aplikacji webowej. Sam serwlet pozostaje jednak nienaruszo-
ny. Cała zabawa zaczyna się, gdy dowolny użytkownik Twojej aplikacji po raz pierw-
szy spróbuje z niego skorzystać. Serwer wykonuje wtedy następujące czynności:
(cid:141) załadowanie klasy serwletu,
(cid:141) utworzenie instancji serwletu,
(cid:141) wywołanie metody init(),
(cid:141) wywołanie metody service().
Gdy serwlet znajdzie się w trakcie wywołania metody service(), może on rozpocząć
normalną obsługę żądań. Od tego momentu w przypadku otrzymania przezeń dowol-
nego żądania HTTP, nastąpi próba wywołania odpowiedniej metody serwletu, według
schematu nazwa/doNazwa(), np. GET/doGet(), POST/doPost(), itd.
Sporo pracy, nieprawdaż? Na szczęście do obowiązków programisty należy obsługa
wybranych metod ze słowem do w nazwie. Jeśli więc chcesz, aby serwlet obsługiwał
tylko żądanie GET, zadeklaruj jedynie metodę doGet().
W przypadku klasy serwletu utworzonej przez Netbeans, proces tworzenia serwletu
został uproszczony jeszcze bardziej. Twórcy szablonu założyli (skądinąd słusznie), że
znamienita większość programistów korzysta jedynie z metod HTTP GET i POST. Z tego
względu w klasie serwletu są przesłaniane dwie metody — doGet() i doPost(), które
odwołują się do jednej i tej samej metody — o nazwie processRequest(). Z jednej
strony ułatwia to życie w większości sytuacji, z drugiej jednak mogą się zdarzyć sytu-
acje, w których inaczej chcemy zareagować w przypadku żądania GET, a inaczej w przy-
padku POST. W takiej sytuacji należy usunąć wygenerowany mechanizm i napisać wła-
sne metody obsługi doGet() i/lub doPost().
Serwlet pod lupą
Przed chwilą poznałeś przepływ sterowania w serwlecie; najwyższa pora, abyś zapo-
znał się pokrótce z kluczowymi klasami powiązanymi z obsługą serwletów. Omówię
jedynie najważniejsze elementy; warto je zapamiętać, ponieważ będą się one pojawiać
także w dalszych przykładach, ilustrujących kolejne omawiane technologie.
Jak już wspomniałem, serwlety, którymi zajmujemy się w niniejszej książce, dziedzi-
czą po klasie HttpServlet. Ze względu na fakt, że serwlet z założenia jest konstrukcją
niezwykle uniwersalną, w hierarchii dziedziczenia pojawiają się dodatkowe elementy,
które ową uniwersalność wprowadzają. Oto krótki opis elementów hierarchii dziedzi-
czenia, począwszy od tych najbardziej ogólnych:
Rozdział 3. ♦ Serwlet — na dobry początek
27
(cid:141) Interfejs Servlet — określa najważniejsze metody, które muszą
implementować wszystkie serwlety. Metody te są niezależne od stosowanych
protokołów przesyłania danych, a dotyczą one głównie zarządzania cyklem
życia serwletu (init(), service(), destroy()).
(cid:141) Abstrakcyjna klasa GenericServlet — podstawowa implementacja
interfejsów Servlet i ServletConfig, dająca dostęp do parametrów i ustawień
serwletu. Klasa ta zawiera proste implementacje metod obu interfejsów,
dzięki czemu stanowi podstawę dla klasy HttpServlet i wszystkich innych
klas serwletów.
(cid:141) Klasa HttpServlet — to właśnie po tej klasie będziesz dziedziczył, tworząc
własne serwlety. Poza własnymi implementacjami metod ze wspomnianych
wcześniej interfejsów, klasa HttpServlet udostępnia metody do*, czyli
doGet(), doPost() etc. Dzięki temu we własnych serwletach musisz
zdefiniować jedynie te metody, które Twój serwlet zamierza obsługiwać.
Protokół HTTP zawiera definicje ośmiu metod: GET, POST, PUT, HEAD, OPTIONS, TRACE,
DELETE, CONNECT. Serwlety mogą obsługiwać wszystkie metody, na wyżej omówionej
zasadzie. W praktyce zdecydowanie najczęściej stosuje się metody GET i POST i to na
nich skupimy się w dalszej części tego rozdziału.
Żądanie — odpowiedź
Mimo niewątpliwie istotnej roli klasy HttpServlet, w trakcie pracy z serwletami czę-
ściej przyjdzie Ci zapewne korzystać z interfejsów HttpServletRequest/HttpServlet
(cid:180)Response. Reprezentują one odpowiednio obiekty żądania i odpowiedzi, przekazy-
wane do metod doGet(), doPost() etc. Pełny nagłówek metody doGet() wygląda na-
stępująco:
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, java.io.IOException
Twoim zadaniem jest takie zdefiniowanie metod do*, aby generowały one odpowiedź,
zazwyczaj zależną od przesłanych parametrów. Wszystkie niezbędne metody znajdziesz
w dwóch wyżej wspomnianych klasach. Zacznijmy od interfejsu HttpServletRequest
— to na jego podstawie będziemy w kolejnych przykładach generować odpowiedzi
przesyłane za pomocą interfejsu HttpServletResponse.
Niemal wszystkie metody HttpServletRequest są faktycznie przydatne, niemniej w tym
miejscu omówimy metody najistotniejsze z punktu widzenia samych serwletów:
(cid:141) Object getParameter(String nazwa) — pobiera parametr o danej nazwie
przesłany w żądaniu.
(cid:141) Enumeration String getParameterNames() — pobiera nazwy wszystkich
parametrów znajdujących się w danym żądaniu.
(cid:141) String getRemoteUser() — zwraca login uwierzytelnionego użytkownika
lub null, w przypadku braku uwierzytelnienia.
28
Część I ♦ Podstawy
(cid:141) Cookie[] getCookies() — zwraca tablicę ciasteczek — specjalnych plików
przechowywanych na komputerze użytkownika.
(cid:141) String getQueryString() — zwraca łańcuch parametrów, przesłanych
w adresie URL (za znakiem zapytania).
(cid:141) String getHeader(String nazwa) — zwraca wartość nagłówka HTTP
o podanej nazwie.
(cid:141) int getIntHeader(String nazwa) — zwraca wartość nagłówka HTTP
o podanej nazwie jako liczbę całkowitą.
(cid:141) long getDateHeader(String nazwa) — zwraca wartość nagłówka HTTP
o podanej nazwie jako liczbę milisekund, począwszy od początku epoki
(1 stycznia 1970 roku). Wartość ta może być przekazana w konstruktorze
klasy Date.
(cid:141) String getContextPath() — zwraca ścieżkę kontekstu aplikacji.
(cid:141) String getServletPath() — zwraca ścieżkę dostępu do serwletu.
(cid:141) String getPathInfo() — zwraca dodatkowe informacje zawarte w ścieżce.
Trzy ostatnie metody są ze sobą związane, ponieważ zwracają one kolejne elementy
adresu URL, wykorzystanego do wykonania żądania. Przeanalizujmy poniższy przy-
kład, prezentujący wiadomość o określonym identyfikatorze:
http://localhost:8080/MojaAplikacja/serwlety/info/235/
Pomijamy oczywiście nazwę protokołu (http) i nazwę serwera z portem (localhost:8080).
Zostaje nam więc ciąg:
/MojaAplikacja/serwlety/info/235/
Metoda getContextPath() zwraca fragment adresu określający naszą aplikację:
/MojaAplikacja
Ścieżka do kontekstu zawsze zaczyna się od ukośnika (ale nigdy na nim się nie koń-
czy!), chyba że aplikacja zostanie umieszczona w katalogu głównym serwera — wte-
dy zwracana wartość to łańcuch pusty. Fragment ten jest wspólny dla wszystkich pli-
ków wchodzących w skład tej aplikacji. Kolejny fragment adresu określa ścieżkę do
serwletu. W naszym przypadku jest to fragment:
/serwlety/info
Powyższy łańcuch znaków musi pasować do odpowiednich wzorców, zdefiniowanych
w deskryptorze wdrożenia (pamiętasz znacznik url-pattern z poprzedniego roz-
działu?). Zasady określania odpowiednich ścieżek do serwletów omówimy w następ-
nym rozdziale; na razie wystarczy Ci informacja, że ten fragment adresu umożliwia
jednoznaczne zidentyfikowanie serwletu.
Ostatni fragment ścieżki (/235/) zostanie zwrócony przez metodę getPathInfo(). Do-
kładnie rzecz biorąc, metoda getPathInfo() zwraca fragment adresu URL od ścieżki
serwletu do początku łańcucha parametrów (czyli do znaku zapytania). Oznacza to,
że nawet dołączenie parametrów, tak jak w poniższym przykładzie, nie zmieni warto-
ści ścieżki.
http://localhost:8080/MojaAplikacja/serwlety/info/235?param=1
Rozdział 3. ♦ Serwlet — na dobry początek
29
Przesyłanie odpowiedzi
Po przeanalizowaniu wszystkich możliwych atrybutów żądania musisz odesłać klien-
towi odpowiedź. Do tego celu służy obiekt interfejsu HttpServletResponse. W jego
przypadku otrzymujemy nieco mniejszy zestaw metod, jednak nie oznacza to wcale
mniejszych możliwości. Przede wszystkim musimy określić, jakie operacje chcemy
wykonywać w związku z przesyłaniem odpowiedzi do klienta:
(cid:141) przesłanie odpowiedzi w postaci danych tekstowych lub binarnych,
(cid:141) utworzenie i przesłanie ciasteczek,
(cid:141) dodanie do odpowiedzi dowolnych nagłówków,
(cid:141) przekierowanie żądania lub przesłanie kodu błędu.
Transmisja danych
Chociaż technologie internetowe mają swoją specyfikę, nie zapominajmy, że żyjemy
w świecie Javy. Z tego względu operacje zarówno odczytu, jak i zapisu wiążą się
z wykorzystaniem strumieni i/lub obiektów klas Reader/Writer. Nie inaczej jest w tym
przypadku: zanim prześlemy jakiekolwiek dane, musimy uzyskać odpowiednie obiek-
ty zapisujące:
(cid:141) ServletOutputStream getOutputStream() — zwraca strumień zapisu
dla danych binarnych
(cid:141) PrintWriter getWriter() — zwraca obiekt zapisujący dla danych tekstowych.
W przypadku danych binarnych możemy skorzystać z obiektu klasy ServletOutput
(cid:180)Stream. Jest to zwykły strumień zapisu, rozszerzony o możliwość zapisywania do-
wolnych danych typów prymitywnych, a także łańcuchów znaków (za pomocą metod
print() i println()). Z tej klasy należy korzystać w przypadku przesyłania plików —
jeśli serwer musi w dynamiczny sposób wygenerować treść takiego pliku.
Znacznie częściej przyjdzie Ci jednak korzystać z danych tekstowych. W tym przypad-
ku zazwyczaj będziesz korzystać z obiektu klasy PrintWriter i jego metody println().
Nagłówki i ciasteczka
O ile w przypadku żądania mamy do czynienia z odczytem nagłówków i ciasteczek
przesłanych przez klienta, o tyle w przypadku odpowiedzi występuje proces odwrot-
ny. Aby dodać ciasteczko, wystarczy skorzystać z metody addCookie():
void addCookie(Cookie c)
Więcej na temat ciasteczek w osobnym podrozdziale. W przypadku nagłówków sytu-
acja jest nieco bardziej skomplikowana — do dyspozycji mamy dwie metody (wraz
z odpowiednikami dla liczb i dat):
void addHeader(String nazwa, String wartość)
void setHeader(String nazwa, String wartość)
30
Część I ♦ Podstawy
Na czym polega różnica? Otóż metoda addHeader() doda podaną wartość do już istnie-
jącej zawartości nagłówka, natomiast metoda setHeader() zastąpi wartość, jeśli tako-
wa już istnieje. Tak samo działają bliźniacze metody addIntHeader(), addDateHeader(),
setIntHeader() i setDateHeader().
Kody odpowiedzi, błędy i przekierowania
Do obowiązków odpowiedzi HTTP należy także przekazywanie kodów odpowiedzi,
jeśli chcemy zaznaczyć, że odpowiedź nie zostanie zakończona w zwykły sposób. Aby
przekazać kod odpowiedzi, korzystamy z metody setStatus():
void setStatus(int kod)
W ten sposób przekazujemy kody, które nie określają sytuacji problematycznych.
W przypadku błędów (np. 404 — brak zasobu) zaleca się zdecydowanie wykorzysty-
wanie metody sendError():
void sendError(int kod)
void sendError(int kod, String komunikat)
Jak widać, istnieje możliwość przesłania dodatkowej informacji na temat samego błę-
du. Ostatnią funkcjonalność związaną z kodami odpowiedzi stanowi przekierowanie.
Chociaż z technicznego punktu widzenia przekierowanie jest też rodzajem kodu od-
powiedzi, do przekierowania wykorzystuje się oddzielną metodę:
void sendRedirect(String adres)
Korzystając z metod sendError() i sendRedirect(), należy pamiętać o subtelnych
kwestiach związanych z fizycznym przesyłaniem danych do klienta. Przesyłanie ko-
munikatów o błędach lub przekierowań wiąże się z dość brutalną ingerencją w proces
przesyłania odpowiedzi. Proces ten jest natychmiast przerywany, a klient otrzymuje
odpowiedź z wybranym kodem odpowiedzi. Co jednak stanie się, gdy zdążymy wy-
słać do klienta jakieś dane?
Odpowiedź jest prosta — nastąpi błąd. Po wysłaniu danych nie możesz ingerować
w treść nagłówków, przez co nie możesz ustawić kodu odpowiedzi, a co za tym idzie
także przekierowania. Czy oznacza to, że musisz uważać, gdzie wywołujesz metodę
println() obiektu PrintWriter? Na szczęście nie do końca.
Domyślnym zachowaniem obiektu w przypadku odpowiedzi jest zapisywanie danych
do bufora. Oznacza to, że dane zostaną wysłane po zakończeniu metody lub w przy-
padku wywołania metody flush() tego obiektu. Co za tym idzie, poniższa konstruk-
cja (wewnątrz metody doGet()) nie spowoduje wygenerowania błędu:
PrintWriter out = response.getWriter();
out.println( test );
response.sendRedirect( url/do/innego/serwletu );
Jeśli przed wywołaniem metody sendRedirect() wywołasz metodę out.flush(), wte-
dy błąd nastąpi. Zazwyczaj jednak takie wywołanie jest pomijane, dzięki czemu pro-
blem występuje stosunkowo rzadko.
Rozdział 3. ♦ Serwlet — na dobry początek
31
Om nom nom, czyli ciasteczka w pełnej krasie
Twórcy aplikacji webowych, podobnie jak Ciasteczkowy Potwór, mają szczególny
sentyment do ciasteczek (ang. cookies). Są to niewielkie pliki przechowywane na kom-
puterach użytkowników aplikacji webowych, dzięki czemu jesteśmy w stanie zapamię-
tywać ich preferencje, loginy i hasła itd. Metody operujące na ciasteczkach poznaliśmy
w poprzednim podrozdziale, ale teraz zaprezentujemy ich działanie w praktycznym
przykładzie (listing 3.1):
Listing 3.1. Przykład obsługi ciasteczek
protected void processRequest(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
response.setContentType( text/html;charset=UTF-8 );
PrintWriter out = response.getWriter();
try {
Cookie lastVisit = null;
for (Cookie c : request.getCookies())
if (c.getName().equals( obecnosc )) {
lastVisit = c;
break;
}
if (lastVisit != null)
out.println( Twoja ostatnia wizyta na stronie miała miejsce w dniu +
lastVisit.getValue());
else
out.println( Do tej pory nie odwiedziłeś/aś naszej strony. Wstydź się! );
lastVisit = new Cookie( obecnosc , new Date().toString());
response.addCookie(lastVisit);
} finally {
out.close();
}
}
Zadaniem powyższego serwletu jest przechowywanie informacji o dacie ostatniej wi-
zyty na stronie i wyświetlanie jej. W przypadku braku ciasteczka z datą (co jest równo-
znaczne z pierwszymi odwiedzinami na tej stronie, przynajmniej od czasu wyczysz-
czenia ciasteczek w przeglądarce) wyświetlamy inną informację. Warto zwrócić uwagę
na dwie kwestie. Po pierwsze, jeśli chcemy odczytać już istniejące ciasteczka — ko-
rzystamy z metody getCookies() znajdującej się w obiekcie request. Jeśli chcemy
dodać ciasteczko — korzystamy z obiektu response. Nigdy odwrotnie! Sprawa druga,
znacznie bardziej przykra — powyższy sposób dostępu do ciasteczek użytkownika
(pętla for..in) stanowi jedyną metodę znajdywania ciasteczek o określonej nazwie.
W przypadku tworzenia prawdziwych aplikacji trzeba zdefiniować osobną metodę do
wyszukiwania ciasteczek.
Sesje — nie tylko dla studentów
Obsługa sesji jest kolejnym nieodłącznym elementem niemal wszystkich aplikacji we-
bowych. W przypadku JEE interakcje z sesją możemy prowadzić na różne sposoby,
32
Część I ♦ Podstawy
także za pomocą poznanych już klas. W tym rozdziale poznamy sposób na dostęp do
sesji za pomocą obiektu klasy HttpServletRequest. Kluczową rolę odgrywa metoda
getSession(), występująca w dwóch wariantach:
HttpSession getSession()
HttpSession getSession(boolean czyTworzyc)
Na wstępie zaznaczę, że pierwszy wariant tej metody jest równoważny drugiemu wy-
wołanemu z parametrem true. Drugi wariant postępuje różnie w zależności od prze-
kazanej wartości logicznej:
(cid:141) Jeśli parametr ma wartość true, metoda zwraca obiekt sesji lub tworzy nowy,
jeśli ten nie istnieje.
(cid:141) Jeśli parametr ma wartość false, metoda zwraca obiekt sesji lub null, jeśli ten
nie istnieje.
Jak widać, wartość true należy przekazać, jeśli chcesz po prostu uzyskać dostęp do
sesji. Wartość false stosuje się, gdy chcesz sprawdzić, czy sesja istnieje. Można sko-
rzystać z tego mechanizmu, aby sprawdzić, czy dane żądanie jest pierwszym żądaniem
użytkownika w danej sesji. Mechanizm ten jest realizowany w poniższym przykładzie
z listingu 3.2:
Listing 3.2. Przykład wykorzystania sesji
protected void processRequest(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
response.setContentType( text/html;charset=UTF-8 );
PrintWriter out = response.getWriter();
try {
if (request.getSession(false)==null)
{
out.println( Witaj na stronie po raz pierwszy! );
request.getSession();
}
else
out.println( Witaj na stronie po raz kolejny! );
} finally {
out.close();
}
}
Jeśli po utworzeniu sesji chcesz sprawdzić, czy sesja została dopiero co utworzona,
skorzystaj z metody isNew():
(cid:141) boolean isNew() — zwraca true, jeśli obiekt sesji został utworzony podczas
tego żądania.
Korzystanie z obiektu sesji
Podstawowa funkcjonalność obiektu sesji sprowadza się do dwóch metod:
(cid:141) Object getAttribute(String nazwa) — zwraca atrybut sesji o podanej nazwie.
Rozdział 3. ♦ Serwlet — na dobry początek
33
(cid:141) void setAttribute(String nazwa, Object wartość) — dodaje obiekt
do sesji, przypisując mu podany klucz (nazwę). Jeśli jakiś obiekt o takiej
samej nazwie już istniał, zostanie on zastąpiony.
Wiemy już, jak utworzyć sesję, wiemy też, jak z niej skorzystać. Pozostało nam omó-
wienie, jakie są warunki zakończenia sesji. Może ono nastąpić w wyniku kilku różnych
sytuacji:
(cid:141) ręczne zakończenie sesji przez programistę,
(cid:141) upłynięcie czasu życia sesji,
(cid:141) zamknięcie okna przeglądarki przez użytkownika.
Ostatni przypadek, jest rzecz jasna, najprostszy — nie wymaga on naszej ingerencji.
Ręczne zakończenie sesji wiąże się z wywołaniem następującej metody:
(cid:141) void invalidate() — kończy sesję.
Najciekawiej sytuacja wygląda w przypadku określania terminu ważności sesji. Istnie-
ją bowiem dwie możliwości określenia tej wartości — pierwsza z nich jest stosowana
w pliku konfiguracyjnym web.xml:
web-app
session-config
session-timeout 10 /session-timeout
/session-config
/web-app
Podana wartość określa czas ważności sesji w minutach. Obowiązuje on dla wszyst-
kich sesji, chyba że skorzystasz z możliwości określenia czasu życia sesji w kodzie:
(cid:141) void setMaxInactiveInterval(int czas) — określa czas życia sesji
w sekundach. Podanie wartości 0 i ujemnych powoduje, że sesja nigdy
nie wygasa (do jej zakończenia jest więc konieczne wywołanie metody
invalidate() lub zamknięcie okna przeglądarki przez użytkownika).
Konfiguracja w kodzie Javy
— można tego uniknąć
Podczas tworzenia większości aplikacji programiści muszą zmierzyć się z problemem
obsługi różnego rodzaju ustawień wpływających na działanie aplikacji. Problemem
staje się lokalizacja tych ustawień. Z jednej strony nikt nie chce utrudniać sobie życia
— w końcu nie ma nic prostszego, niż wczytać wartość umieszczoną w stałej/zmiennej.
Z drugiej jednak strony zmiana takich ustawień wymagałaby rekompilacji całego pro-
jektu, w najlepszym przypadku — jednej biblioteki.
Z tego względu powszechnym standardem stało się umieszczanie różnego rodzaju
ustawień w zewnętrznych źródłach danych — plikach binarnych, tekstowych, XML;
34
Część I ♦ Podstawy
rzadziej w bazach danych. W przypadku aplikacji webowych JEE miejscem takim
jest deskryptor wdrożenia — plik web.xml. Poza licznymi ustawieniami związanymi
z funkcjonowaniem aplikacji jako takiej (część z nich już poznałeś), w pliku web.xml
możesz także zdefiniować parametry dla poszczególnych serwletów, a także całej apli-
kacji webowej.
Parametry serwletów
Parametry serwletów możesz określać za pomocą znacznika init-param w następu-
jący sposób:
servlet
servlet-name ParameterServlet /servlet-name
servlet-class pl.helion.jeeweb.ParameterServlet /servlet-class
init-param
param-name autor /param-name
param-value Krzysztof Rychlicki-Kicior /param-value
/init-param
/servlet
Po dwóch znanych już znacznikach (servlet-name i servlet-class) następuje dowol-
na liczba znaczników init-param. Każdy taki znacznik zawiera dwa kolejne, określa-
jące nazwę i wartość parametru. Parametry serwletów można też dodawać w środowi-
sku Netbeans, podczas tworzenia serwletu (w ostatnim kroku kreatora).
Pierwszy parametr utworzony, najwyższa pora, aby odczytać go we wnętrzu serwletu.
Do zarządzania parametrami serwletów służy interfejs ServletConfig, który jest im-
plementowany przez znane nam klasy GenericServlet i HttpServlet. Dwie metody
tego interfejsu, które interesują nas w tej chwili najbardziej, to:
(cid:141) String getInitParameter(String nazwa) — zwraca wartość parametru
o podanej nazwie.
(cid:141) String[] getInitParameterNames() — zwraca wszystkie nazwy parametrów
danego serwletu.
protected void processRequest(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
response.setContentType( text/html;charset=UTF-8 );
PrintWriter out = response.getWriter();
try {
out.println( Autorem serwletu jest + this.getInitParameter( autor ));
} finally {
out.close();
}
}
Dzięki umieszczeniu konfiguracji w pliku XML odnieśliśmy wymierną korzyść. Zmia-
na wartości w pliku XML nie wymaga rekompilacji kodów źródłowych, a jedynie prze-
ładowania aplikacji (w przypadku Tomcata istnieje także opcja automatycznego wy-
krywania zmian i przeładowywania aplikacji).
Rozdział 3. ♦ Serwlet — na dobry początek
35
Interfejs ServletConfig poza dwoma poznanymi metodami udostępnia metodę get
(cid:180)ServletName(), zwracającą nazwę serwletu, a także metodę getServletContext().
Zwraca ona (a jakżeby inaczej) kontekst serwletów — jeden z najważniejszych obiek-
tów w całym świecie aplikacji webowych JEE.
Kontekst serwletów
Kontekst serwletów to obiekt, który służy do komunikacji serwletów z kontenerem.
Dzięki niemu możesz dynamicznie dodawać serwlety do aplikacji, uzyskiwać dostęp
do zasobów znajdujących się w jej obrębie, zapisywać logi do serwerowego dzienni-
ka, a co najważniejsze z obecnego punktu widzenia — możesz korzystać z parametrów
aplikacji webowej (kontekstu). Od parametrów serwletów różni je zasięg oddziaływa-
nia. Każdy parametr kontekstu jest widoczny we wszystkich serwletach i innych pli-
kach. Parametry serwletu są określane w podobny sposób jak w przypadku serwletów:
web-app
context-param
param-name tytul /param-name
param-value Java EE 6. Tworzenie aplikacji webowych /param-value
/context-param
…
/web-app
Również sposób wykorzystywania parametrów kontekstu przypomina ten znany
z serwletów:
try {
out.println( Wszystkie przykłady pochodzą z książki +
this.getServletContext().getInitParameter( tytul ));
} finally {
out.close();
}
Jedyną różnicę stanowi odwołanie się do obiektu kontekstu. Reszta pozostaje bez zmian
— nawet nazwa metody. Ciekawostkę stanowi metoda wprowadzona w specyfikacji
Java Servlets 3.0. Otóż aż do momentu wprowadzenia tej specyfikacji parametry, za-
równo serwletów, jak i kontekstu, były wartościami tylko do odczytu. Jedyną możli-
wością zmiany parametrów była edycja pliku web.xml. W wersji JavaServlet 3.0 API
pojawiła się jednak innowacja — możliwość dynamicznego ustawiania parametrów
kontekstu za pomocą metody setInitParameter(). Wynika to z wprowadzenia dużej
elastyczności — klasa ServletContext w wersji 3.0 uzyskała wiele metod, takich jak
addServlet(), czy addFilter(), które umożliwiają dynamiczne dodawanie różnych
składników aplikacji, do tej pory deklarowanych jedynie w pliku web.xml. Nie należy
jednak nadużywać tej metody.
Kontekst serwletów pojawi się ponownie już niebawem, tymczasem nadszedł czas,
aby zmierzyć się z przeciwnikiem o wiele ważniejszym od parametrów — mowa
o atrybutach.
36
Część I ♦ Podstawy
Trzech muszkieterów?
Parametry, czy to serwletów, czy to aplikacji, mają swoje zastosowania i bywają nie-
zwykle przydatne. Mimo to głównym środkiem komunikacji między serwletami, kon-
tenerem, sesją, użytkownikiem i obiektem żądania — czyli z grubsza między wszyst-
kimi elementami aplikacji — są atrybuty. Z technicznego punktu widzenia między
parametrami i atrybutami występują dwie zasadnicze różnice:
(cid:141) W przypadku parametrów zarówno klucz, jak i wartość są łańcuchami
znaków, zaś w przypadku atrybutów — klucz jest łańcuchem, wartość
może być obiektem.
(cid:141) Parametry z założenia są tylko do odczytu (choć w świetle ostatniej wersji
specyfikacji wygląda to inaczej…), natomiast atrybuty są przeznaczone
zarówno do odczytu, jak i do zapisu.
Niezwykłe znaczenie ma także wprowadzenie zasięgu atrybutów. Atrybut dodany w za-
sięgu żądania (request) nie będzie widoczny w innych zasięgach. Tabela 3.1 przedsta-
wia zestawienie parametrów i atrybutów w poszczególnych zakresach.
Tabela 3.1. Możliwości zapisywania i odczytywania parametrów i atrybutów w poszczególnych
zakresach
Zakres
Żądanie
Serwlet
Sesja
Kontekst aplikacji
Parametry
Atrybuty
Zapis
nie
nie
brak
tak (od wersji 3.0)
Odczyt
tak
tak
brak
tak
Zapis
tak
brak
tak
tak
Odczyt
tak
brak
tak
tak
Na podstawie powyższej tabeli wydać wyraźnie, że parametry pełnią jedynie funkcję
ustawień, opcji konfiguracyjnych, które ułatwiają zmianę w działaniu aplikacji bez
konieczności ponownej rekompilacji kodu. Atrybuty natomiast mają zastosowanie
o wiele szersze — służą do wymiany informacji pomiędzy poszczególnymi elementa-
mi aplikacji.
W dalszej części rozdziału skupimy się tylko na atrybutach. Ich ogromna przydatność
ma bowiem pewne ograniczenia. Jedno z nich jest związane z najważniejszą chyba ce-
chą odróżniającą aplikacje webowe od aplikacji typu standalone — konieczność jed-
noczesnej obsługi wielu użytkowników.
Atrybuty a mnogość żądań
Jedna aplikacja webowa może być używana nawet przez setki czy tysiące użytkowni-
ków jednocześnie. Każde żądanie (HTTP request) jest obsługiwane przez kontener
w osobnym wątku. Istotną kwestią jest więc zapewnienie integralności operacji wyko-
Rozdział 3. ♦ Serwlet — na dobry początek
37
nywanych przez każdego z nich — nie może być tak, że operacje jednego użytkowni-
ka wpłyną na efekt operacji innego.
W przypadku parametrów problem ten raczej nie występuje. Co prawda, w wersji 3.0
pojawiła się możliwość modyfikowania parametrów kontekstu aplikacji, jednak możli-
wość ta powinna być używana w bardzo sporadycznych sytuacjach, gdy obsługa wielu
użytkowników nie powinna sprawiać problemów (np. z powodu wywoływania takiego
kodu przez superadministratora witryny). Jeśli jednak zabezpieczenie jest konieczne,
można zrealizować je w sposób analogiczny do tego, który zaprezentuję za chwilę.
Zdecydowanie bardziej skomplikowana sytuacja występuje w przypadku atrybutów.
Wszystkie trzy przypadki omówię w kolejnych podrozdziałach.
Atrybuty żądania
W przypadku atrybutów żądania sytuacja jest stosunkowo prosta. Żądanie jest realizo-
wane przez jednego użytkownika; w dodatku pojedyncze żądanie nie wiąże się w ża-
den sposób z innymi żądaniami (nawet tego samego użytkownika), dlatego problem
jednoczesnego dostępu przez wielu użytkowników nie występuje. Pojawia się jednak
inne pytanie — skoro obiekt żądania nie wchodzi w interakcje z innymi żądaniami, po
co miałby korzystać z atrybutów?
Takie rozwiązanie wynika ze stosowanych w praktyce mechanizmów obsługi stron.
Serwlety same w sobie rzadko generują treść — na ogół wykonują one różnorodne
operacje (np. pobranie danych z bazy, realizacja logiki biznesowej — choć w więk-
szych aplikacjach i te zadania są delegowane), a następnie przekazują sterowanie do
pliku JSP. W takiej sytuacji konieczne jest przekazanie informacji między serwletem
a plikiem JSP. Voilà! — znaleźliśmy zastosowanie atrybutów żądania. Dokładne wy-
jaśnienie i przykłady poznasz w rozdziale poświęconym JSP.
Atrybuty sesji
W nieco gorszej sytuacji są atrybuty sesji. Wiemy już, że jedna sesja jest powiązana
z konkretnym użytkownikiem. Teoretycznie nie powinno więc być problemów. Ale
użytkownicy bywają okrutni — wyobraź sobie, co mogłoby się stać, gdyby użytkow-
nik uruchomił Twoją aplikację webową w dwóch zakładkach i próbował jednocześnie
ładować różne (lub te same) serwlety?
Odpowiedź jest prosta: mogłoby dojść do jednoczesnego dostępu do sesji. Odczyt da-
nych nie stanowiłby problemu, ale atrybuty sesyjne mogą być przecież również zapi-
sywane. Taka sytuacja to potencjalny problem. Jak więc mu zaradzić?
Powiem krótko: należy skorzystać ze standardowego mechanizmu Javy, chroniącego
dane przed zapisem przez wiele wątków jednocześnie — synchronizacji. Teraz musi-
my określić, dostęp do czego dokładnie chcemy synchronizować.
Na początek odrzućmy obiekt żądania (klasy HttpServletRequest). Jest to obiekt zwią-
zany tylko z jednym, konkretnym żądaniem, więc zablokowanie dostępu do niego nie
wpłynęłoby na inne obiekty żądań — nadal wszystkie one mogłyby korzystać bez
38
Część I ♦ Podstawy
skrępowania z sesji. Nie ma sensu również blokada obiektu serwletu — dostęp do se-
sji mają różne serwlety, więc zablokowanie jednego z nich nie powstrzyma innych od
zapisu do sesji. Jedynym sensownym rozwiązaniem pozostaje zablokowanie obiektu
sesji, do którego uzyskujemy dostęp za pomocą obiektu żądania. Poniższy kod, wsta-
wiony we wszystkich serwletach, pozwoli na zliczenie wszystkich wywołań serwle-
tów, które miały miejsce w aplikacji webowej dla danego użytkownika:
HttpSession sesja = request.getSession();
synchronized(sesja) {
if (sesja.isNew())
sesja.setAttribute( licznik , 1);
else
{
int licznik = Integer.parseInt(sesja.getAttribute( licznik ).toString());
sesja.setAttribute( licznik , licznik + 1);
}
}
W ten sposób, gdy jeden serwlet wejdzie w blok synchronizowany, uzyskujemy gwa-
rancję, że żaden inny serwlet w tym momencie dostępu do sesji nie uzyska. Wszystkie
inne serwlety będą musiały czekać, aż pierwszy serwlet zwolni blokadę.
Atrybuty kontekstu serwletów
Największe niebezpieczeństwo niesie za sobą korzystanie z atrybutów należących do
kontekstu aplikacji. Każdy taki atrybut może być odczytany i zmodyfikowany w do-
wolnym niemal miejscu aplikacji. Z tego względu każda próba korzystania z atrybu-
tów (zwłaszcza zapisu) powinna być synchronizowana.
Zasada działania jest taka sama, jak w przypadku sesji. W tym przypadku musimy jednak
synchronizować obiekt kontekstu. Kod synchronizujący przedstawia się następująco:
ServletContext sc = this.getServletContext();
synchronized(sc)
{
Object licznik = sc.getAttribute( licznik );
if (licznik == null)
sc.setAttribute( licznik , 1);
else
{
licznik = sc.getAttribute( licznik );
sc.setAttribute( licznik , Integer.parseInt(licznik.toString()) + 1);
}
}
Powyższy kod realizuje funkcjonalność podobną do przykładu z sesją — tym razem
zliczamy jednak wszystkie wywołania serwletów wykonane przez wszystkich użyt-
kowników.
Z obiektami żądań, sesji i kontekstu, jak również z ich atrybutami, wiążą się ważne
klasy — słuchaczy zdarzeń. Choć istnieje możliwość tworzenia całych aplikacji we-
bowych bez świadomości istnienia tych klas, zdarzają się sytuacje, w których znajo-
mość tego typu mechanizmów jest niezbędna.
Rozdział 3. ♦ Serwlet — na dobry początek
39
Słuchowisko
Słuchacze zdarzeń to obiekty spotykane w Javie niezwykle często. Początkujący pro-
gramiści Javy spotykają się z nimi np. podczas tworzenia prostych aplikacji graficz-
nych. Słuchacz zdarzeń powiązany z przyciskiem pozwalał na wykonanie dowolnego
kodu np. po jego kliknięciu. Pojęcie słuchacza zdarzeń nie ogranicza się oczywiście
do tworzenia aplikacji z graficznym interfejsem — również aplikacje webowe dają
słuchaczom zdarzeń spore pole do popisu.
W poniższych podrozdziałach przedstawię interfejsy słuchaczy zdarzeń przeznaczone
do użycia w aplikacjach webowych. Nie jest to może najciekawszy fragment niniej-
szej książki, ale prędzej czy później znajdziesz się w sytuacji, w której będziesz mu-
siał skorzystać z opisanych w następnych akapitach mechanizmów.
ServletContextListener
Jest to najrzadziej chyba wykorzystywany słuchacz zdarzeń. Zawiera dwie metody:
contextInitialized() i contextDestroyed(), które są wywoływane w momencie utwo-
rzenia/usunięcia kontekstu aplikacji, czyli — w momencie startu i zakończenia aplika-
cji. Obydwie metody przyjmują parametr typu ServletContextEvent — umożliwia on
pobranie kontekstu aplikacji za pomocą metody getServletContext().
ServletContextAttributeListener
Drugim słuchaczem zdarzeń związanym z kontekstem aplikacji jest słuchacz obser-
wujący kolekcję atrybutów kontekstu. Reaguje on na dodawanie (metoda attribute
(cid:180)Added()), usuwanie (attributeRemoved()) i zamianę (attributeReplaced()) atrybu-
tów. Wszystkie trzy metody przyjmują jeden parametr typu ServletContextAttribute
(cid:180)Event — umożliwia on pobranie nazwy modyfikowanego atrybutu (getName()), jego
wartości (getValue()).
ServletRequestAttributeListener
i ServletRequestListener
Obydwa interfejsy pełnią analogiczne funkcje, co ich „kontekstowi” koledzy — na-
wet nazwy metod są podobne (w przypadku pierwszego interfejsu — identyczne,
w przypadku drugiego — requestInitialized() i requestDestroyed()). Jedyną real-
ną zmianą jest wprowadzenie dodatkowej funkcjonalności do klas argumentów zdarzeń
— ServletRequestAttributeEvent i ServletRequestEvent. Udostępniają one metodę
getServletRequest(). Pozwala ona na skorzystanie z obiektu żądania, którego zda-
rzenia dotyczą.
40
Część I ♦ Podstawy
HttpSessionAtributteListener
i HttpSessionListener
Również słuchacze zdarzeń powiązani z sesjami zostały utworzone zgodnie z omówio-
nymi powyżej zasadami. Słuchacz HttpSessionListener jest wykorzystywany przy
tworzeniu (metoda sessionCreated()) i kończeniu sesji (sessionDestroyed()). Prze-
kazywany argument — obiekt klasy HttpSessionEvent — udostępnia metodę getSes-
sion(), która daje dostęp do utworzonej (zakończonej) sesji. W przypadku interfejsu
HttpSessionAttributeListener mamy do dyspozycji te same trzy metody, co w po-
przednich przypadkach. Typ zdarzenia to HttpSessionBindingEvent. Jego możliwości
sprowadzają się do pobrania obiektu sesji i nazwy/wartości dodawanego/usuwanego/
zmienianego atrybutu.
HttpSessionBindingListener
Nareszcie coś ciekawego! Tytułowy interfejs odbiega nieco od schematu, z jakim mie-
liśmy do czynienia przez ostatnie trzy podrozdziały. Wszystkie trzy interfejsy z czło-
nem AttributeListener w nazwie odpowiadały za informowanie o zmianach zacho-
dzących w kolekcji atrybutów. Dla odmiany interfejs HttpSessionBindingListener
powinien być implementowany przez klasy, których obiekty będą umieszczane w se-
sji! Jeśli więc tworzysz własne klasy do przechowywania danych
Pobierz darmowy fragment (pdf)