[OLD] Java 101: Enum + Servlets
[This is a post from my old website. Outdated packages and libraries. Viewer discretion is advised ;-)]
ENUM
Typ enum, dodany w wersji 1.5, służy do definiowania stałych. Kiedy mamy z nim do czynienia, to wiemy że mamy do wyboru ograniczony zbiór możliwych opcji. Przykładowo, definiując enum poraRoku
z góry wiemy, że będzie on przyjmować wartości jedynie spośród ZIMA
, WIOSNA
, LATO
i JESIEN
.
Każdy enum domyślnie rozszerza klasę java.lang.Enum
, dlatego nie może rozszerzać żadnej innej klasy. Może natomiast implementować interfejsy. Enumy możemy definiować również jako klasy wewnętrzne.
Konstruktor może być protected
(domyślnie) albo private
. Nie przywołujemy go bezpośrednio. Weźmy nasz enum poraRoku
:
|
|
Efekt: LATO to okres strasznej duchoty.
Ciało klasy (typu) enum może zawierać metody i inne pola. Domyślnie w trakcie kompilacji dodawana jest metoda values()
, zwracająca tablicę wszystkich wartości naszego enum w kolejności ich deklaracji w kodzie. Zobaczmy jak możemy zawrzeć więcej informacji w stałych enum:
|
|
Efekt:
|
|
Pełen zbiór domyślnych metod znaleźć można w dokumentacji.
Kiedy stosować?
Korzystając z enuma, mamy zagwarantowane istnienie tylko jednej instancji stałej (wygodny punkt wyjścia dla wzorca Singleton). Ponadto, możemy korzystać z operatora ==
. Zawarta w klasie Enum
metoda equals()
działa dokładnie tak samo jak ten operator, ale jest metodą, więc możemy otrzymać wyjątek NullPointerException
, zamiast wartości false
jak w przypadku porównania enum przy pomocy ==
z null
.
Nie trzeba implementować interfejsu Serializable
by móc serializować enumy. Ponadto, dokonując serializacji enuma, de facto serializowana jest jego nazwa, zwracana przez wbudowaną metodę name()
, a przy deserializacji przywoływana jest metoda valueOf()
naszego enuma, zwracająca stałą o tej nazwie. W ten sposób nie musimy serializować wartości wszytkich pól enuma.
Enumy pozwalają także na wygodniejsze stosowanie wyrażeń switch
:
|
|
Efekt: W sam raz!
Nie zawsze stosowanie typu enum jest korzystne. Zajmują one więcej miejsca w pamięci (powód dla którego ich stosowanie nie jest rekomendowane przez zespół Androida). Jeżeli nasze stałe nie mają żadnych dodatkowych pól, to prawdopodobnie mniej zasobów będzie zajmować zwyczajowe public static final
.
Z drugiej strony, enumy są łatwym sposobem obsługi stałych, które mają posiadać dodatkowe pola (a zatem więcej informacji) i własne metody.
Czyli, jak zawsze, stosować w sposób przemyślany ;).
Prosta aplikacja webowa: Servlets, Tomcat
Mówiąc w skrócie, servlety to klasy pomagające serwerowi w odpowiadaniu na żądania ze strony klienta. Jako że najczęściej żądania są w protokole HTTP, to pisząc servlet zwykle rozszerzamy klasę javax.servlet.http.HttpServlet
, i nie bawimy się w implementację samego interfejsu javax.servlet.Servlet
.
Zwróćcie uwagę na początek tych nazw: javax, nie zwykłe java. Standardowa edycja Javy nie zawiera servletów, Jeżeli używaliście wcześniej platformy Javy SE, to będziecie musieli ściągnąć brakujące biblioteki, albo po prostu przerzucić się na Javę EE, która je (i inne) zawiera. Przykładowo, jeśli korzystacie z Eclipse’a, macie do wyboru kilka wersji programu. Zainstalujcie wersję dla Javy EE i będziecie mieć spokój ;).
Potrzebny jest też serwer oraz (akurat dla potrzeb takich servletów, jakie napiszemy) baza danych. W poniższych przykładach wykorzystany jest Tomcat oraz MySQL. Nie będziemy krok po kroku przerabiać ich instalacji, w internecie bez problemu można znaleźć instrukcje do każdego systemu operacyjnego. Za pierwszym razem może to trochę czasu zająć, szczególnie jeśli się nie miało wcześniej do czynienia z linią komend, ale warto tę chwilę poświęcić. Założenie jest zatem takie, że Tomcat jest zainstalowany, a na dysku utworzona została baza danych MySQL.
javax.servlet.http.HttpServlet
zawiera szereg metod odpowiadającym żądaniom HTTP. Skorzystamy z metod doGet()
oraz doPost()
. Różnica pomiędzy GET a POST polega na widoczności przesyłanych danych. Żądanie GET zawiera przesyłane do serwera informacje w adresie URL (można więc podejrzeć je nawet w historii przeglądarki), stąd dane muszą być zapisane za pomocą znaków ASCII. Przeglądarki i serwery nakładają ograniczenia na maksymalną długość adresu URL (od 2048 w górę), więc i z tej perspektywy jesteśmy ograniczeni. Dla żądania POST format danych nie jest tak istotny.
Napiszemy bardzo prostą aplikację webową: pamiętnik operujący na lokalnym serwerze.
Przygotowania*
(*Eclipse, wszystko można zrobić bez pomocy IDE)
Potrzebny jest nam nowy projekt, skonfigurowany do działania na serwerze. W Eclipse klikamy **File **-> **New **-> Dynamic Web Project. Po podaniu nazwy projektu, obok pola Target runtime klikamy przycisk New Runtime…, wybieramy wersję Tomcata, klikamy Finish. Kreator projektu również zamykamy klikając Finish. Ok, mamy lokalny serwer, na którym będziemy odpalać nasze servlety.
Teraz baza danych. Upewnij się, że masz włączony domyślną perspektywę w Eclipse (_Window _-> Perspective -> Open perspective -> Java EE). U dołu okna IDE kliknij w Data Source Explorer i prawym przycikiem myszy na Database Connections. Kliknij New, z listy wybierz MySQL. Po naciśnięciu Next wpisz dane do swojej bazy danych (nazwa pod polem Database, pełen URL, login i hasło). Jeżeli po naciśnięciu Test Connection pokazuje się komunikat o niepowodzeniu, sprawdź wybrany sterownik. W naszym wypadku jest to JDBC Driver, ściągnąć go można tutaj. a zmienić naciskając na ikonę trójkąta po prawej strony od listy sterowników, wskazując na miejsce, gdzie tenże .jar znajduje się na dysku.
{: .align-center}
W naszym wypadku baza danych nazywa się diary
, a przygotowana wcześniej tabela ENTRIES
, z następującymi kolumnami:
|
|
Servlet pobierający informacje z bazy danych
Tak jak wyżej napisano, servlety służące do obsługi żądań HTTP powinny rozszerzać klasę javax.servlet.http.HttpServlet
. A więc:
|
|
Kilka słów o @WebServlet
. Pojawiła się ona w specyfikacji Servlet 3.0. Wcześniej dla każdej aplikacji sieciowej obsługiwanej przy pomocy servletów należało tworzyć deskryptor w pliku web.xml
, w którym m.in. umieszczaliśmy informacje na temat wszystkich servletów. Dzięki temu kontener servletów (w naszym przypadku Tomcat) wiedział, który servlet powinien odpalić na dany typ żądania ze strony klienta. Adnotacja @WebServlet
ułatwia nam pracę, takowego pliku przygotowywać nie trzeba (Tomcat ją obsługuje od wersji 7.0).
W dokumentacji wymieniony jest szereg atrybutów adnotacji, ale podawać trzeba jedynie urlPatterns
/value
, wskazując URL pod którym nasz servlet będzie aktywny.
Nasz pierwszy servlet będzie służyć do odczytywania z bazy danych wpisów z pamiętnika. Żadnych specjalnych danych do serwera nie przesyłamy, tylko żądanie wyświetlenia wpisów, więc skorzystamy z żądania GET, a więc przesłaniamy metodę doGet()
. Od razu ustalimy typ odpowiedzi (będzie to wyświetlany w przeglądarce html) oraz przygotujemy przypiszemy zmienną out do obiektu PrintWriter
wziętego z HttpServletResponse
. Ten posłuży nam do przesłania tekstu (kodu html) do klienta:
|
|
Czas na małe parsowanie. Najpierw część kodu html, do którego nie potrzebujemy informacji z bazy danych:
|
|
Od razu zawarliśmy w nim URL, pod którym będzie działać nasz drugi servlet. Na razie wejście pod ten adres wywołałoby jedynie błędy.
Pozostaje nam połączenie się z bazą danych, pobranie wpisów i sparsowanie ich do kodu HTML. Najpierw kilka stałych:
|
|
Pierwszy servlet gotowy. Gdy klikniemy Run -> Run as… -> Run on Server powinniśmy ujrzeć coś takiego:
{: .align-center}
Zwróćcie uwagę, że adres URL to połączony adres bazy danych oraz adresu podanego w adnotacji @WebServlet
.
Czas na drugi servlet, pozwalający na dodawanie nowych wpisów do bazy. Jak widać podany adres servleta nie musi pokrywać się z nazwą klasy:
|
|
Tym razem skorzystamy z żądania POST, bo inaczej cała treść wpisu w żądaniu GET musiałaby wejść w adres URL. Przesłaniamy metodę doPost()
:
|
|
Gdybyśmy spróbowali odpalić ten servlet na serwerze, wyskoczy nam błąd 405. Nie wysłaliśmy bowiem żądania POST, więc sprawdzane jest (po adresie URL) żądanie GET, a tego nasz servlet nie obsługuje. Musimy przygotować plik .html do obsługi naszego servleta. Umieścimy go w projekcie w folderze WebContent/WEB-INF:
{: .align-center}
Przesyłane są informacje zawarte pomiędzy znacznikami <form>
i </form>
, odzyskiwane w kodzie servleta poprzez atrybut name
:
|
|
Po odpaleniu zobaczymy coś takiego:
{: .align-center}
I to tyle! Mamy prosty (prostacki ;)) pamiętnik przetrzymywany w bazie danych, z którym łączymy się Javą poprzez serwer lokalny. Póki nie wyłączymy serwera ani bazy danych możemy łączyć się z pamiętnikiem przez dowolną przeglądarkę.
Pełen kod dostępny na GitHubie.