| Obsługa sesji przez serwery webowe w J2EE | 8 months, 1 week ago |
Zaraz po odesłaniu do nas odpowiedzi serwery WWW zapominają, kim jesteśmy. W wielu przypadkach takie zachowanie jest prawidłowe, niekiedy jednak konieczne jest utrzymywanie pomiędzy klientem a serwerem stanu konwersacyjnego obejmującego wiele żądań. Interfejs API serwletów oferuje nam zadziwiająco proste rozwiązanie tego problemu.
Logika istniejącego obecnie modelu utrzymywania stanu konwersacji sprowadza się do sprawdzania prostego parametru przekazywanego wraz z żądaniem i odsyłanego z odpowiedzią. Tym przekazywanym parametrem jest obiekt identyfikujący klienta - identyfikator sesji. Idea jest prosta: po otrzymaniu pierwszego żądania od klienta, serwer tworzy unikalny, charakterystyczny tylko dla jednego klienta identyfikator sesji (podczas tworzenia nowego obiektu sesji) i zwraca go klientowi wraz z odpowiedzią. Wtedy klient z każdym kolejnym swoim żądaniem odsyła do serwera otrzymany identyfikator. Kontener widząc taki identyfikator, odnajduje odpowiednią sesję i wiąże ją z aktualnym żądaniem. W jaki sposób klient i kontener wymieniają między sobą informacje o identyfikatorze sesji? Najprostszym i najbardziej popularnym sposobem wymiany tego rodzaju identyfikacji są tzw. ciasteczka (nazywane też znacznikami kontekstu klienta). Cały proces identyfikacji przebiega wg następujących kroków:
- 1. klient wysyła pierwsze żądanie na serwer
- 2. kontener nie widząc w nagłówku HTTP żadnego ciasteczka identyfikującego sesję, tworzy nowy obiekt sesji (musimy jednak zasygnalizować kontenerowi, że chcemy stworzyć lub wykorzystać istniejącą sesję poleceniem request.getSession() w serwlecie obsługującym żądanie)
- 3. kontener zwraca klientowi odpowiedź wzbogaconą o nagłówek Set-Cookie: JSESSIONID=367A216783167
- 4. klient z każdym kolejnym żądaniem wysyła na serwer dodatkowy nagłówek Cookie: JSESSIONID=367A216783167
- 5. kontener w nagłówku HTTP widząc ciasteczko identyfikujące sesję, odnajduje odpowiednią dla klienta sesję i wiąże ją z żądaniem
Co zrobić, kiedy nasz klient (przeglądarka) nie akceptuje ciasteczek? W takiej sytuacji nasz unikalny identyfikator sesji możemy dodawać do każdego z adresów URL przekazywanego od klienta w postaci atrybutu jsessionid, np.:
<a href="http://localhost:8080/Test/DoSomething.do;jsessionid=6732167AS76788">link</a>
Oczywiście tak zmodyfikowany adres URL możemy otrzymać tylko po stronie serwera, a więc musimy go wysyłać w odpowiedniej postaci do klienta wraz z odpowiedzią. Przypisywanie adresów URL jest uzasadnione tylko wtedy, gdy stosowanie ciasteczek jest niemożliwe i tylko jeśli wymuszamy kodowanie adresów URL w odpowiedziach. Np. kodowanie adresów URL w kodzie serwletu możemy zrealizować w następujący sposób:
response.setContentType("text/html");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
out.println("...");
out.println("<a href="" + response.encodeURL("/Test.do") + "">kliknij mnie</a>");
Na stronach JSP możemy zaś skorzystać ze znacznika <c:URL> biblioteki JSTL.
W sytuacji, w której konieczne będzie przekazanie żądania na inny adres URL, zamiast korzystać z metody response.sendRedirect() powinniśmy użyć response.encodeRedirectURL("Test.do");
Musimy pamiętać, że kodowanie adresów URL odbywa się automatycznie, ale tylko wtedy, gdy nasz klient nie obsługuje ciasteczek i gdy zakodujemy nasze adresy metodą response.encodeURL(String) lub response.encodeRedirectURL(String).w
API serwletów, w interfejsie HttpServletRequest oprócz metody getSession(), udostępnia nam jeszcze jedną dosyć istotną metodę:
- public HttpSession getSession(boolean) - ta metoda z parametrem true jest równoważna bezargumentowej metodzie getSession(). Jeśli jednak przekażemy do niej parametr false, będzie to oznaczało, że metoda zwróci albo już istniejącą sesję, albo wartość null, jeśli jeszcze nie istnieje sesja powiązana z danym klientem.
Usuwanie sesji
Sesja może zginąć na cztery sposoby:
- po przekroczeniu globalnego dla całej aplikacji limitu czasowego określonego w deskryptorze wdrożenia (czas podajemy w minutach):
<session-config>
<session-timeout>15</session-timeout>
<session-config>
- po przekroczeniu limitu czasowego ustawionego przez metodę setMaxInactiveInterval(int) - czas podajemy w sekundach.
- po wykonaniu metody invalidate() na obiekcie sesji
- na skutek awarii
Kluczowe metody interfejsu HttpSession
| METODA | ZNACZENIE |
| String getId() | Zwraca aktualny identyfikator sesji |
| boolean isNew() | Zwraca wartość true, jeśli klient nie odesłał jeszcze żądania z danym identyfikatorem sesji |
| long getCreationTime() | Zwraca czas powstania sesji |
| long getLastAccessedTime() | Zwraca czas otrzymania przez kontener ostatniego żądania z danym identyfikatorem sesji |
| void setMaxInactivateInterval(int) | Ustawia maksymalny czas (wyrażony w sekundach) pomiędzy kolejnymi żądaniami klienta w ramach danej sesji |
| int getMaxInactiveInterval() | Zwraca maksymalny czas (wyrażony w sekundach) pomiędzy kolejnymi żądaniami klienta w ramach danej sesji |
| void invalidate() | Kończy sesję |
Śledzenie i migracja sesji
Istnieje dokładnie jeden obiekt ServletContext (reprezentujący kontekst aplikacji) w każdej wirtualnej maszynie Javy. Istnieje też dokładnie jeden obiekt ServletConfig dla każdego serwletu w każdej maszynie wirtualnej Javy. Ale w każdej aplikacji internetowej, niezależnie od liczby JVM, istnieje tylko jeden obiekt HttpSession dla określonego identyfikatora sesji. Obiekty HttpSession wraz z atrybutami są przenoszone pomiędzy JVM. W momencie migracji każda sesja ulega pasywacji i aktywacji. Ponieważ podczas migracji na inną maszynę wirtualną trzeba również przenosić wszystkie atrybuty sesji, a nie możemy mieć gwarancji, że atrybuty zawsze w całości będą serializowane, projektanci specyfikacji serwletów doszli do wniosku, że dobrym rozwiązaniem będzie umożliwienie sygnalizowania atrybutom należącym do sesji, że także one zostaną na moment przeniesione. Sygnalizacja ta może odbywać się w klasie implementującej interfejs HttpSessionActivationListener. Jeśli więc z jakiegoś powodu klasy naszych atrybutów sesji nie będą serializowane, powinniśmy skorzystać z interfejsu HttpSessionActivationListener i w jego metodach zwrotnych (sessionDidActivate(HttpSessionEvent) i sessionWillPassivate(HttpSessionEvent)) przygotować nasze atrybuty do wielkiej przeprowadzki. Ogólnie API serwletów w zakresie sesji udostępnia nam aż cztery interfejsy nasłuchujące:
| Interfejs | Metody | Zdarzenie | Opis |
| HttpSessionListener |
sessionCreated sessionDestroyed |
HttpSessionEvent | Zdarzenia utworzenia i zniszczenia obiektu sesji - typu HttpSession |
| HttpSessionAttributeListener |
attributeAdded attributeRemoved attributeReplaced |
HttpSessionAttributeEvent | Chcemy mieć informację, że w obiekcie sesji dodano, usunięto lub zastąpiono jakiś atrybut |
| HttpSessionBindingListener |
valueBound valueUnbound |
HttpSessionBindingEvent | Używamy klasy atrybutu i chcemy, aby obiekty jej typu były informowane o dodaniu lub usunięciu z sesji |
| HttpSessionActivationListener |
sessionDidActivate sessionWillPassivate |
HttpSessionBindingEvent | Używamy klasy atrybutu i chcemy, aby obiekty jej typu były informowane o przekazywaniu powiązanych z nimi sesji pomiędzy różnymi maszynami JVM w środowisku rozproszonym |
Interpretacja stron JSP do serwletu |
[LucidCRM] Start systemu ![]() |

Interpretacja stron JSP do serwletu
Comments
Lucid Office



Lucid CRM
Lucid Assistance
Lucid Sale
Lucid Mailer