W dzisiejszej lekcji nauczymy się co nieco o aplikacjach webowych, które stanowią zdecydowaną większość tworzonych współcześnie aplikacji.
Wiedza jak pisać aplikacje webowe jest w dzisiejszych czasach kluczowa dla pracodawców. Jak się sama przekonasz, nie różnią się one tak bardzo od zwykłych aplikacji, a biblioteka Spring MVC tylko uprości nam zadanie.
Lekcja
Choć lekcja ta będzie poświęcona aplikacjom webowym, nie będziemy tutaj poznawać API Javy EE. Oczywiście polecam samodzielnie poczytać na ten temat, rozszerzyć sobie wiedzę o Servletach itp., ale prawda jest taka że z ‘czystego’ API korzysta się niezwykle rzadko. Precyzyjna wiedza na ten temat oczywiście przydaje się, ale nie jest konieczna do rozpoczęcia kariery w IT.
Ale na pewno musimy sobie wyjaśnić czym właściwie jest Java EE :) Mówiąc najogólniej, jest to zbiór kontraktów (w postaci najczęściej interfejsów), czyli ustaleń, że pewne rzeczy mają działać tak, a nie inaczej. Dzięki temu aplikacje webowe możemy rozdzielić na dwa zasadnicze elementy — serwer aplikacji oraz samą aplikację (w postaci pliku WAR). Jeśli nasza aplikacja korzysta tylko ze standardowych elementów (ze specyfikacji Java EE), to możemy ją uruchomić (zdeployować, zrobić deploy) na dowolnym serwerze aplikacji.
Z czego składają się aplikacje webowe
Działająca aplikacja webowa (tj. taka, która działa na serwerze i jest dostępna dla użytkowników) w technologii Java EE tak jak wspominałem wcześniej składa się z 2 podstawowych elementów: serwera aplikacji oraz pliku WAR (często ten plik nazywany jest aplikacją webową, bywa też określany mianem modułu, systemu itp. — nie ma tutaj bardzo ścisłych określeń).
Uwaga: to nie jest do końca prawda, ponieważ można dołączyć lekki kontener, np. Jetty, do samego pliku WAR przez co nie potrzebuje on serwera aplikacji. Ma to swoje zalety, w takiej sytuacji serwer aplikacji (najczęściej zubożony) jest niejako częścią samej aplikacji, więc fizycznie nie ma podziału na 2 części, ale logicznie można nadal wyróżnić oba elementy.
Serwer aplikacji
Serwer aplikacji to ‘część wspólna’ wszystkich aplikacji webowych, która zapewnia nam podstawowe mechanizmy (np. zarządzanie wątkami, możliwość dynamicznego ładowania aplikacji, autoryzację i uwierzytelnianie (JAAS), obsługę protokołu HTTP, szyfrowanie o obsługę SSL oraz inne elementy z których możemy korzystać za pomocą określonych API). Na rynku jest wiele serwerów aplikacji, natomiast my będziemy wykorzystywali Tomcat jako jeden z prostszych i dzięki temu działających sprawnie także na komputerze lokalnym. Z najbardziej popularnych możemy wyróżnić:
- Tomcat (bezpłatny) — technicznie nie jest to serwer aplikacji, ale na potrzeby kursu jest wystarczający
- Glassfish (bezpłatny, istnieje opcja płatna)
- WildFly (dawniej JBoss AS; bezpłatny, istnieje opcja płatna)
- WebSphere (płatny)
- Oracle Fusion Middleware (płatny)
Serwery aplikacji mogą mieć uruchomione wiele aplikacji jednocześnie, które są rozróżniane za pomocą tzw. kontekstów. Załóżmy, że nasz serwer jest uruchomiony na naszym komputerze (który ma zawsze adres localhost) i działa na domyślnym porcie aplikacji webowych w Javie (8080). Adres http://localhost:8080/kontekst1/cos spowoduje, że zostanie uruchomiona aplikacja przypisana do kontekstu o nazwie kontekst1, a w ramach tej aplikacji zostanie obsłużony adres /cos . Nazwa kontekstu nadawana jest najczęściej automatycznie na podstawie nazwy pliku WAR (np. plik aplikacja.war będzie miał kontekst o nazwie aplikacja, a plik cos.war będzie miał kontekst o nazwie cos ).
Aby uruchomić plik WAR na serwerze aplikacji, najczęściej wystarczy umieścić go w odpowiednim katalogu. W przypadku serwera Tomcat (na którym będziemy pracowali i pokazywali przykłady) jest to katalog /webapps , w przypadku np. JBossa (z którego bardzo często korzysta się w przypadku aplikacji produkcyjnych) jest to katalog /deployments . W przypadku innych serwerów, stosowna informacja powinna być w dokumentacji dostarczonej przez autorów.
Plik WAR
Pliki WAR to nic innego jak określona struktura katalogów spakowana jako zip. Bardziej szczegółowo strukturę omówimy sobie poniżej. To co powinniśmy wiedzieć to to, że plik WAR powinien być kompletną aplikacją/modułem, tzn powinien zawierać nasz kod oraz wszystkie zależności (biblioteki, zewnętrzne moduły itp), które są potrzebne w naszej aplikacji.
Struktura aplikacji webowej (pliku WAR)
Tak jak wspomniałem wcześniej, plik WAR to spakowana struktura katalogów i specyficzne pliki. Przyjrzyjmy się bliżej najważniejszym katalogom i plikom.
- / — katalog główny, pliki w tym katalogu są dostępne publicznie, należy więc uważać, żeby nie umieścić tam żadnych wrażliwych danych, np. danych dostępowych do bazy danych itp. Wyjątkiem są katalogi WEB-INF oraz META-INF. W tym katalogu umieszczamy treści takie jak pliki jsp (nie będziemy z nich korzystać w taki sposób), grafiki używane w interfejsie, skrypty JS, arkusze styli CSS itp. Zawartość tego katalogu jest reprezentowana w naszym projekcie Mavenowym poprzez katalog /src/main/webapp
- /WEB-INF — to katalog, w którym jest nasz skompilowany kod, a także zawartość katalogu /src/main/resources z naszego projektu Mavenowego. Poza tym wewnątrz znajdziemy:
- web.xml — główny (i tak naprawdę jedyny wymagany) plik aplikacji webowej, określony w standardzie JavaEE. Definiujemy w nim Servlety, Listenery, Filtry itp. My będziemy go używać tylko po to, żeby uruchomić Springa ‑w skrócie, powiemy, że wszystkie zapytania mają być obsługiwane przez Servlet dostarczany przez Springa, oraz wskażemy gdzie znajduje się nasza konfiguracja
- classes — skompilowane nasze klasy
- lib — biblioteki i zależności w postaci plików JAR (np. tutaj znajdziemy biblioteki Springa)
- /META-INF — w tym katalogu najczęściej znajdziemy pliki których sami tam nie umieszczaliśmy ;) Biblioteki czasem przechowują tutaj konfigurację, deskryptory, opisy itp. Na tą chwilę nie będziemy się nim zajmować.
MVC
Zanim przejdziemy do Springa powiemy sobie parę słów czym właściwie jest MVC. To akronim od Model — View — Controller, co symbolizuje ‘trójpodział’ aplikacji. Idea jest prostsza niż to brzmi ;) Chodzi o to że pisząc funkcjonalność (np. wypisywanie listy kotów w naszej aplikacji) wyróżniamy trzy jej rozdzielne elementy:
- model — czyli tzw. domenę, są to obiekty które reprezentują pewien fragment rzeczywistości (np. w naszej aplikacji takim obiektem jest Kot) oraz powiązane elementy (np. kod zapisujący/odczytujący dane naszych kotów z bazy danych)
- view — widoki to to, co widzi użytkownik. Są to najczęściej fragmenty kodu HTML wzbogacone o dodatkowe elementy języka (np. żeby wyświetlić dynamiczne informacje)
- controller — to tzw. kontrolery, czyli logika, która stoi za naszymi stronami — innymi słowy kod który łączy model (bazę danych) z widokami (użytkownikiem).
Tutaj uwaga! W aplikacjach często używa się tzw. serwisów (czyli klas, które oferują funkcjonalność czysto biznesową, np. wyślij emaila, wywołaj jakiś inny program). Serwisy są wywoływane przez kontrolery i w zależności od podejścia mogą być uwzględniane w pojęciu ‘kontrolery’ lub nie — to zależy tak naprawdę od przyjętej nomenklatury.
W naszym przypadku będziemy wykorzystywać SpringMVC który pomaga nam połączyć powyższe elementy w jedną całość i ograniczyć ilość pisanego kodu ‘boilerplate’ (to kod, który nie realizuje stricte funkcjonalności, a służy jedynie temu, żeby całość mogła działać ze sobą — przykładem są np. gettery i settery).
Poniższy diagram obrazuje zależności i sposób interakcji pomiędzy tymi komponentami:
Spring MVC
Od razu zastrzegam że to, jak używać SpringMVC omówimy w kolejnej lekcji, dzisiaj będzie tylko koncepcja oraz kilka informacji :)
Przede wszystkim, czym jest i co nam daje: Spring Framework to obecnie najpopularniejszy framework do tworzenia aplikacji w języku Java. Do jego sukcesu przyczyniła się przede wszystkim elastyczność — można go stosować niemalże w każdym rodzaju aplikacji, a jednocześnie precyzyjnie konfigurować jego działanie. Framework ten zbudowany jest wokół zasady convention-over-configuration, tzn. nie musimy nic konfigurować i wtedy zostaną przyjęte sensowne wartości domyślne. Najczęściej jest to super rozwiązanie, pozwalające znacznie ograniczyć ilość pracy przy projekcie. Od jakiegoś czasu głównym sposobem na ‘współprace’ ze Springiem są adnotacje, czyli np. @Component nad nazwą klasy (adnotacje omówimy w kolejnej lekcji).
To, co daje nam Spring to przede wszystkim kontener IoC (Inversion of Control) — oznacza to w uproszczeniu (i nie do końca w zgodzie z rzeczywistością — ale na potrzeby kursu możemy przyjąć że tak jest) że w przeciwieństwie do ‘standardowej’ sytuacji, w której to klasa sama musi zadbać o inicjowanie potrzebnych jej komponentów, to kontener dba o tworzenie odpowiednich obiektów i ich ‘wstrzykiwanie’ (tzw. DI — Dependency Injection, to jedna z cech kontenera IoC), czyli ustawianie odpowiednich pól klasy właściwymi wartościami.
Spring MVC to ‘rozszerzenie’ Frameworka Spring o wsparcie dla aplikacji webowych (m.in obsługa adresów URL, przesyłania danych poprzez formularze itp) dzięki czemu tworzenie aplikacji webowej jest prostsze niż kiedykolwiek.
W przypadku Spring MVC spotkamy się też z pojęciem tzw. view resolvera — to specjalna klasa, która otrzymuje nazwę widoku do wyświetlenia oraz dane które przekazujemy do tego widoku (obiekt typu ModelAndView) i na tej podstawie generuje widok, który widzi użytkownik. Omówimy to od strony praktycznej poznając kontrolery.
To co jeszcze należy wiedzieć o Springu to kilka pojęć:
- bean — to obiekt dowolnego typu, który jest zarządzany przez Spring’a a tym samym podlega wstrzykiwaniu (czyli można go wstrzyknąć w dowolny obiekt z użyciem adnotacji)
- komponent / stereotyp — to adnotacja, która mówi że obiekt danej klasy ma być zarządzany przez Springa (innymi słowy: mówimy Springowi żeby utworzył beana o takim typie)
- component-scan — procedura, którą Spring wykonuje na początku (podczas inicjowania aplikacji) i która polega na ‘przejrzeniu’ wszystkich dostępnych oraz znalezieniu tych, które są oznaczone jako komponenty (mają określony stereotyp)
- view resolver — patrz wyżej ;)
To tyle teorii, do praktyki przejdziemy w kolejnej lekcji :)
Materiały dodatkowe / dokumentacja
- Opis pliku web.xml i możliwości jego konfiguracji (EN)
- Opis pliku WAR (EN)
- Reference do SpringMVC (EN)
- Szybki tutorial Spring MVC (EN) — spoiler! to będziemy omawiać w kolejnej lekcji dokładniej
Zadanie
Dzisiejsze zadanie praktyczne będzie dość proste:
- dodaj do projektu Maven moduł koty-webapp (tak, aby był typu WAR)
- do projektu koty-webapp dodaj zależności koty-domain oraz koty-application (pamiętaj, że zależności są przechodnie — więc wystarczy dodać tylko jedną z nich (wiesz którą, prawda? :) ) a druga będzie ‘w komplecie’ — jako zależność zależności
- do projektu koty-webapp dodaj zależności do spring MVC oraz Spring context w tych samych wersjach, co spring-core
Dodatkowo polecam zapoznać się z tutorialami Spring MVC lub oficjalnym getting started — ułatwi to następną lekcję :)
UWAGA!! Rozwiązanie tego zadania nie jest jeszcze pełnoprawną aplikacją webową! Brakuje przede wszystkim pliku web.xml, który jest niezbędny do uruchomienia aplikacji na serwerze. Plik ten dodajemy dopiero w lekcji 9. Poniższego rozwiązania NIE DA SIĘ uruchomić bez modyfikacji.
Jeśli uważasz powyższą lekcję za przydatną, mamy małą prośbę: polub nasz fanpage. Dzięki temu będziesz zawsze na bieżąco z nowymi treściami na blogu ( i oczywiście, z nowymi częściami kursu Javy). Dzięki!