Wyobraźmy sobie, że robimy zakupy w sklepie internetowym. Aplikacja obsługująca sklep internetowy to nic innego jak aplikacja WWW. Wybieramy więc interesujący nas produkt i klikamy aby dodać go do koszyka. Takie kliknięcie to nic innego jak wysłanie do serwera żądania HTTP. Klikamy jeszcze trochę przeglądając katalog produktów (każde kliknięcie to najpewniej kolejne żądania HTTP) i być może dodajemy do koszyka kolejne produkty, aż w końcu decydujemy się finalizować transakcję. Klikamy więc odpowiedni guzik, co jest równoważne z wysłaniem żądania HTTP. Najpewniej wszystkie te czynności wykonuje jednocześnie wielu klientów sklepu, skąd zatem serwer aplikacji ma wiedzieć, że żądanie HTTP finalizacji zakupów, które właśnie otrzymał, pochodzi od tej samej osoby która wcześniej dodała do koszyka produkty A, B i C a nie od osoby która wybrała produkty D, E i F? No i w jaki sposób zapamiętać produkty wybrane przez daną osobę, a osobno te wybrane przez kogoś innego?
Powyższy scenariusz to typowy problem, w którego rozwiązaniu pomaga nam mechanizm sesji. Sesja to właśnie taki koszyk z aplikacji sklepu internetowego, do którego możemy dodawać obiekty. Co więcej, to serwer aplikacji dba o to, aby z każdym żądaniem HTTP skojarzyć odpowiednią sesję, dokładnie tę samą która była skojarzona z poprzednimi żądaniami HTTP przychodzącymi od tego klienta.
Sesja w Javie reprezentowana jest przez obiekt typu javax.servlet.http.HttpSession. Obiekt ten pobieramy z obiektu reprezentującego żądanie HTTP za pomocą metody:
HttpSession getSession()
Metoda ta zwraca istniejący obiekt sesji skojarzony z bieżącym żądaniem, jeśli sesja dla danego klienta była już uprzednio utworzona, bądź tworzy i zwraca nowy obiekt, jeśli żądanie pochodzi od klienta który nie miał jeszcze aktywnej sesji.
Obiekty które dodajemy do sesji aby następnie, przy kolejnym żądaniu HTTP, móc je z tej sesji odczytać nazywamy atrybutami sesji. Atrybuty sesji mają nazwę i wartość. Atrybuty dodajemy do sesji za pomocą metody:
void setAttribute(String name, Object value) a pobieramy z niej za pomocą metody:
Object getAttribute(String name)
Jeśli więc funkcjonalność dodawania produktu do koszyka w aplikacji sklepu internetowego zaimplementowalibyśmy w postaci servletu to jego metoda doGet(…) wyglądałaby mniej więcej tak:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // pobranie obiektu sesji powiązanej z tym żądaniem HttpSession session = request.getSession(); // pobranie przekazanej jako parametr nazwy produktu String prod = request.getParameter("prod"); // pobranie z sesji listy reprezentującej koszyk List<String> cart = session.getAttribute("cart"); // przy pierwszym żądaniu musimy utworzyć nowy koszyk if(cart == null) { cart = new ArrayList<String>(); session.setAttribute("cart", cart); } // dodanie produktu do listy reprezentującej koszyk cart.add(prod); }
Zauważmy, że do obiektu sesji w powyższym przykładzie dodajemy nie bezpośrednio produkty, tylko listę produktów. De facto to ta lista jest odpowiednikiem koszyka z aplikacji sklepu, zaś sesję wykorzystujemy do przechowywania listy pomiędzy kolejnymi żądaniami. Moglibyśmy dodawać do sesji bezpośrednio produkty, jednak mieli byśmy wówczas problem z nazwaniem atrybutów. W sesji może być zapisany w danej chwili tylko jedna wartość z danym kluczem, tzn. jeślibyśmy dodali do sesji obiekt pod nazwą „produkt”, to ponowne dodanie do sesji innego obiektu pod tą samą nazwą sprawiłoby, że nadal mielibyśmy w sesji jeden atrybut, tyle że teraz jego wartością byłby ten nowy obiekt. Otrzymalibyśmy zatem efekt sklepu w którym można kupić tylko jeden produkt na raz.
Zwróćmy też uwagę na występującą w kodzie instrukcję warunkową IF. Metoda getAttribute() zwraca atrybut sesji o podanej nazwie, albo null jeśli takiego atrybutu w danym obiekcie sesji nie ma. Sytuacja ta będzie miała miejsce przy każdym pierwszym żądaniu dodania produktu do koszyka. Musimy więc sprawdzić czy atrybut był w sesji obecny i jeśli nie, to musimy go do niej dodać.
Zaimplementujmy teraz w ramach ćwiczenia aplikację WWW składającą się ze strony HTML na której umieścimy listę produktów oraz dwu servletów: obsługującego dodawanie produktu do koszyka oraz wyświetlającego wszystkie dodane produkty. Kliknięcie na dany produkt powinno oznaczać dodanie go do koszyka, tzn. wysłanie żądania typu GET do servletu którego ramowy kod pokazałem powyżej.