Lekcja
Dzisiejsza lekcja zapewne będzie najciekawszą z dotychczasowych — nasza aplikacja będzie dostępna przez przeglądarkę i otrzyma pierwsze funkcjonalności!
Będzie ona zarazem jedną z najnudniejszych — poznamy w niej nieprzyjemną zasadę Napisz — Uruchom — Poczekaj, czyli w jaki sposób sprawdzamy czy aplikacja działa.
W każdej z poprzednich lekcji mogliśmy uruchomić naszą aplikację i po ułamku sekundy wiedzieliśmy, czy działa czy nie. W przypadku aplikacji webowych uruchomienie trwa dłużej a też ‘wyklikanie’ czy działa czy nie zajmuje więcej czasu. Dlatego od tego momentu należy się uzbroić w cierpliwość, ponieważ konieczność ponownego uruchamiania aplikacji po każdej drobnej zmianie może być, i będzie, frustrująca. Na pocieszenie mogę dodać jedynie, że wraz z nabieraniem wprawy takie sprawdzanie będzie coraz mniej częste, a w kolejnych lekcjach poznamy lepsze sposoby na testowanie poprawnego działania aplikacji.
Spring MVC — dodawanie do projektu
W zadaniu do poprzedniej lekcji dodaliśmy już zależności do biblioteki Spring, ale nie uaktywniliśmy jej jeszcze w naszym projekcie. Tym zajmiemy się na początek.
Maven — zależności
Jesli nie miałaś kiedy zając się ostatnim zadaniem, to poniżej rozwiązanie ;)
Dodajemy do pliku pom.xml w module koty-webapp poniższe zależności (w najnowszych wersjach):
- org.springframework:spring-core
- org.springframework:spring-webmvc
- org.springframework:spring-context
oraz do modułu koty-application ponownie:
Jeśli potrzebujesz przypomnienia jak zarządzać zależnościami w Mavenie, zapraszam Cię do ponownego przeczytania poprzedniej lekcji numer 7 :)
Konfiguracja
Na początku parę słów o tym jak Spring MVC działa w projekcie. Spring w projektach webowych najczęściej jest uruchamiany z użyciem wzorca Front Controller. Więcej o wzorcach z przykładami będziemy rozmawiali w końcowych lekcjach kursu, ale w uproszczeniu ten wzorzec zakłada posiadanie ‘nadzorcy’, który zarządza wszystkimi zapytaniami HTTP — tzn. każde zapytanie trafia do tego zarządcy, a następnie on decyduje, jak go obsłużyć (np. do jakiego kontrolera je przekierować). W Springu tą rolę pełni tzw. DispatcherServlet. (Servlet to podstawowy element budulcowy dla aplikacji webowych w specyfikacji Java EE, nie będziemy go poznawać dokładnie w ramach głównego wątku kursu). Servlet ten konfigurujemy standardowo w pliku web.xml (o tym za chwilę) wskazując konfigurację Springową — plik XML który określa, jak ma się zachowywać Spring (o nim też w dalszej części).
Te dwa pliki to właściwie cała konfiguracja której potrzebujemy. Spring wyznaje zasadę Convention over Configuration, czyli nie musimy konfigurować elementów i wtedy użyte zostaną sensowne wartości domyślne. Najczęściej to wystarcza. Jednocześnie możemy zmienić naprawdę najbardziej szczegółowe ustawienia, jeśli tylko chcemy. W tym kursie pójdziemy tą pierwszą drogą ;)
Plik web.xml
Ten plik jest częścią standardu JavaEE i pozwala nam określać m.in. Servlety, Filtry, Listenery itp. My wykorzystamy go jednie do tego, aby ‘oddać’ pełną kontrolę Springowi — dodamy omawiany wcześniej DispatcherServlet i nie będziemy więcej modyfikować tego pliku.
Zainteresowanych zapraszam do szerszego zapoznania się ze specyfikacją lub innymi materiałami w tym temacie (w sekcji linki).
Plik ten o poniższej treści, należy umieścić w katalogu /src/main/webapp/WEB-INF (jesli katalog WEB-INF nie istnieje, należy go utworzyć).
Pełny listing pliku web.xml poniżej:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Baza danych kotow</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/rootApplicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Plik applicationContext.xml
Plik ten może mieć właściwie dowolną nazwę, ale albo musi być ona podana w pliku web.xml (tak jak my to zrobiliśmy) albo musi mieć nazwę taką jak servlet. Ja z przyzwyczajenia używam takiej właśnie nazwy i tak będę się odnosił do tego pliku w dalszej części lekcji.
Plik ten jest pewnego rodzaju instrukcją, jak ma się zachowywać Spring, co ma udostępniać a czego nie i jak ma wiązać elementy ze sobą. My chcemy osiągnąć na tą chwilę jeden cel: pisząc jak najmniej chcemy żeby Spring robił jak najwięcej za nas ;) Póki co oznacza to, że włączymy konfigurację za pomocą adnotacji oraz tzw. package-scan.
Konfiguracja za pomocą adnotacji — dzięki włączeniu tego elementu klasy które zdefiniujemy w pliku XML (a nie za pomocą adnotacji) także będą sprawdzane pod kątem posiadanych adnotacji i w razie potrzeby podjęte zostaną odpowiednie kroki. Chwilowo nie będziemy wykorzystywać tej funkcjonalności, ale warto to mieć w konfiguracji, żeby nie zapomnieć w przyszłości.
Component scan — dzięki temu Spring sam ‘przejrzy’ wszystkie dostępne klasy (lub np. zawężone tylko do wybranego pakietu) i te, które są oznaczone za pomocą stereotypów, utworzy w postaci beanów. Dzięki temu nowe np. kontrolery wystarczy napisać i nie musimy się martwić o to, czy pamiętaliśmy o ich konfiguracji i podpięciu.
Poniżej nasz plik XML z komentarzami:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="pl.kobietydokodu" /> <!-- Chcemy automatycznie obsługiwać wszystkie klasy z adnotacjami w tym pakiecie -->
<context:annotation-config /> <!-- To na przyszłość, pozwoli nam korzystać z adnotacji także w klasach, które byśmy skonfigurowali ręcznie -->
</beans>
Plik rootApplicationContext.xml
Podobnie jak powyższy, plik ten może mieć właściwie dowolną nazwę, ale albo musi być ona podana w pliku web.xml (tak jak my to zrobiliśmy). Różnica pomiędzy tym plikiem, a applicationContext.xml jest taka, że teoretycznie możemy mieć kilka aplikacji Springa działających w ramach jednej aplikacji webowej (definiując kilka różnych Servletów w pliku web.xml) — ta konfiguracja (uruchamiana przez ContextLoaderListener, zdefiniowany zaraz poniżej w pliku web.xml) pozwala na współdzielenie pewnych elementów. Będzie to istotne np. w przypadku Spring Security, czyli zabezpieczeń projektu, ponieważ działają one ‘przed’ samą aplikacją, nie mogą być więc jej częścią. Póki co jednak pozostawmy tą konfigurację pustą:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
</beans>
Widoki
Niewątpliwie ważnym elementem aplikacji są widoki — czyli to, co widzi użytkownik, z czym prowadzi interakcje i na czym pracuje. W Springu widoki działają w taki sposób, że metoda która chce wyświetlić widok zwraca jego nazwę, która jest dowolnym ciągiem znaków. Następnie ta nazwa trafia do tzw. view resolvera, który na podstawie nazwy widoku zwraca widok, który następnie otrzymuje model i na tej podstawie generuje kompletny widok dla użytkownika.
Dzięki temu, że view resolver ma określone zachowanie i sposób działania (implementuje określony interfejs, dokładniej jest to org.springframework.web.servlet.ViewResolver, posiadający jedną metodę o sygnaturze View resolveViewName(String viewName, Locale locale) ), możemy używać różnych resolverów nie zmieniając pozostałej części aplikacji. Daje nam to oczywiście bardzo dużą elastyczność :) W naszych przykładach wykorzystamy najprostszy (org.springframework.web.servlet.view.InternalResourceViewResolver), ale polecam zapoznać się z poniższymi opcjami:
Osobiście korzystam najczęściej z Apache Tiles — ale jest to naprawdę kwestia osobistych preferencji, mnie spodobał się sposób organizacji (w uproszczeniu, stronę dzielimy na fragmenty/kafelki — rzeczone tiles — i widoki współdzielą część elementów, dzięki czemu piszemy mniej HTMLa).
Wspomniana implementacja po prostu dodaje prefix (który konfigurujemy sami) oraz sufix (który podobnie sami konfigurujemy) tworząc ścieżkę, którą następnie używa jako nazwę pliku. To najszybsza na początek opcja, choć nie do końca zalecana jeśli chodzi o komercyjne projekty.
Konfigurujemy viewResolver
Aby skonfigurować viewResolver w naszym projekcie, wracamy do naszego pliku applicationContext.xml i dodajemy poniższy fragment (oczywiście przed tagiem </beans> kończącym plik):
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
To co się dzieje w powyższym fragmencie, to po kolei:
- Tworzymy nowego beana który jest typu InternalResourceViewResolver
- Konfigurujemy prefix ustawiając go na katalog /WEB-INF/views (jeśli nie pamiętasz, dlaczego katalog ten był specjalny, było to opisane w poprzedniej lekcji)
- Konfigurujemy sufiks — w tym przypadku dodajemy kropkę oraz rozszerzenie pliku
Czyli jeśli nasz kontroler ‘poprosi’ o widok o nazwie ‘glowny’, to Spring spróbuje wyświetlić stronę z pliku /WEB-INF/views/glowny.jsp .
Tworzymy statyczny widok
Następny krok to stworzenie statycznej strony HTML i zapisanie jej jako pliku z rozszerzeniem JSP. Jeśli nie wiesz, jak zacząć, zerknij na nasz krótki wpis na ten temat. Będzie to stanowiło podstawę do wprowadzenia dynamicznych elementów i wyświetlenia właściwych informacji.
Utwórz plik HTML, w którym będzie póki co wiadomość o treści “Witaj, jesteś na stronie bazy danych kotów” i zapisz go we wspomnianym katalogu pod nazwą ‘glowny.jsp’.
Pierwszy kontroler
Kolejnym krokiem jest stworzenie pierwszego kontrolera — czyli elementu, który pozwoli nam wyświetlać treści (strony) pod konkretnym adresem URL. Będziemy potrzebowali 2 rzeczy — kontrolera i widoku. Połączymy je modelem, który już istnieje (odpowiednia klasa jest częścią frameworka Spring) i musimy jedynie wypełnić go danymi.
@Component / @Service / @Controller / @Repository — stereotypy
W Springu funkcjonuje coś, co nazywamy stereotypami. Stereotypy to adnotacje, które dodajemy przed klasę (adnotujemy nimi klasę). Są one swego rodzaju znacznikami, które mówią Springowi, że ta klasa ma pewną specjalną funkcję. Są cztery podstawowe stereotypy:
- @Component — bazowy stereotyp, oznacza, że na podstawie tej klasy będzie utworzony bean Springa (innymi słowy: klasa ta jest zarządzana przez Spring’a, lub też cykl życia tej klasy będzie zarządzany przez Springa). Tego stereotypu używamy najczęściej do klas, które są pomocnicze i nie oferują elementów logiki biznesowej, a jedynie pomocnicze funkcje (np. konwersja między typami, jakieś wspólne elementy)
- @Service — stereotyp który wskazuje, że ta klasa jest serwisem, tzn. oferuje pewną logikę biznesową którą będziemy wykorzystywać w innych miejscach (np. kontrolerach; ogólnie w wyższych warstwach — o warstwach opowiemy sobie szerzej w przyszłości)
- @Repository — wskazuje że klasa pozwala na dostęp do danych, np. wspiera obsługę bazy danych. Adnotacje tą stosujemy np. w obiektach typu DAO, za 3 lekcje zobaczymy w jaki sposób uprości nam ona obsługę bazy danych.
- @Controller — oznaczamy nią kontrolery, tj. klasy, które będą obsługiwały zapytania wysyłane poprzez przeglądarkę od użytkowników.
Utwórzmy nową klasę o nazwie KotyController i dodajmy do niej adnotację @Controller. Nasza klasa powinna wyglądać następująco:
package pl.kobietydokodu.koty;
import org.springframework.stereotype.Controller;
@Controller
public class KotyController {
}
@Autowired — łączenie komponentów
W przypadku obiektów zarządzanych przez Springa (tzw. beanów — , jeśli zapomniałaś czym są beany, możesz zawsze wrócić do poprzedniej lekcji :) ) możemy wykorzystać tzw. wstrzykiwanie zależności (ang. Dependency Injection, DI, czasem określane mianem IoC — Inversion of Control — lub kontenera IoC; IoC to szersze pojęcie, ale można się spotkać z takimi sformułowaniami — więcej o tym, czym jest IoC dowiesz się z lekcji o wzorcach projektowych).
Wstrzykiwanie zależności polega na tym, że ‘mówimy’ Springowi o tym, jakich zależności nasz bean (to ważne, ponieważ wstrzykiwania zależności możemy dokonywać tylko i wyłącznie w obiektach, którymi zarządza Spring) potrzebuje, a Spring sam zadba, aby te zależności rozwiązać (tzw. dependency resolution — po prostu wstawienie odpowiedniego innego beana (to także bardzo ważne — wstrzykiwane mogą być tylko zależności zarządzane przez Springa) w to pole klasy). Mechanizm ten jest bardzo elastyczny (możemy np. za każdym razem wstawiać nowy obiekt danego typu albo wszędzie używać jednej instancji tego samego obiektu — to jest domyślne zachowanie; my poznamy tylko podstawową funkcjonalność) i obecnie powszechnie stosowany.
Jeśli pamiętasz (lub zajrzysz do kodu ;) ) do tej pory w naszej aplikacji stosowaliśmy np taki zapis:
private KotDAO kotDao = new KotDAO();
Czyli nie tylko mówiliśmy że będziemy używać obiektu o typie KotDAO i odwoływać się do niego pod nazwą kotDao, ale też od razu tworzyliśmy ten obiekt. To raczej nie jest wskazane, i w normalnej aplikacji prawie na pewno niewskazane. Zamiast tego po prostu powiemy Springowi że chcemy mieć obiekt typu KotDAO i chcemy go pod nazwą kotDao. Powiemy też, że KotDAO jest zarządzany przez Spring’a.
Dodajemy najpierw nowe pole do naszego kontrolera:
package pl.kobietydokodu.koty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class KotyController {
@Autowired
private KotDAO kotDao;
}
A następnie ‘informujemy’ Springa, że ma zarządzać także klasą KotDAO:
package pl.kobietydokodu.koty;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
@Repository
public class KotDAO {
...
@RequestMapping — funkcjonalność widoczna dla użytkowników
Czas na pierwszą interakcję z użytkownikiem — wyświetlimy mu naszą stworzoną wcześniej stronę (glowny.jsp). Wcześniej kilka słów teorii Internetu :)
Każdy z nas korzysta z przeglądarki internetowej, o czym zapewne wiesz. To, czego możesz nie wiedzieć to to, że przeglądarki korzystają najczęściej z protokołu HTTP — pozwala on na pobranie zasobów (np. strony internetowej czy grafiki) na podstawie adresu URL. Przykładowo ten blog ma adres URL http://kobietydokodu.pl — pierwsza część określa właśnie protokół http który jest używany żeby pobrać te zasoby (nie będziemy tutaj omawiać innych protokołów, zainteresowanych odsyłam do samodzielnego zgłębiania Google pod hasłem “web protocols”).
Protokół ten poza adresem URL określa także tzw. metodę — wszystkich metod mamy 8, ale na tą chwilę interesują nas dwie: POST i GET .
Metoda GET to ta, której używa przeglądarka gdy wpiszesz adres w pasku przeglądania. Gdy wpiszesz np. adres www.example.com/cos/innego, Twoja przeglądarka wyśle do serwera coś podobnego do poniższej wiadomości:
GET /cos/innego HTTP/1.1 Host: www.example.com
Mamy tam metodę, adres serwera (www.example.com) oraz tzw. ścieżkę ( /cos/innego ). Podobnie wygląda zapytanie metody POST, która jest używana do przesyłania danych do serwera (np. wypełnionego formularza czy załączonego co formularza pliku). To, co nas będzie interesowało najbardziej to właśnie ścieżka. W tym przypadku /cos byłoby nazwą kontekstu (o tym, czym jest kontekst możesz przeczytać w poprzedniej lekcji), a więc do naszej aplikacji trafi tylko fragment ścieżki — /innego .
Adnotacja @RequestMapping jest o tyle unikalna w stosunku do poprzednich, że możemy ją stosować w 2 miejscach:
- nad klasą — wszystkie metody tej klasy, które mają także adnotacje @RequestMapping, są tak jakby prefiksowane — za chwilę zobaczymy to na przykładzie, będzie to jaśniejsze :)
- nad metodą — wskazujemy, że ta metoda będzie uruchomiona, jeśli użytkownik wpisze konkretny adres URL
Porównajmy dwa przykłady (importy, pakiety itp pominięto dla czytelności), zakładamy że kontekst to /aplikacja, serwer www.example.com:
|
|
W tym wypadku metoda ta będzie uruchomiona po wejściu na adres http://example.com:8080/aplikacja/kontroler/metoda | W tym wypadku metoda ta będzie uruchomiona po wejściu na adres http://example.com:8080/aplikacja/metoda |
Jak widzimy powyżej, adnotacje @RequestMapping(“sciezka”) pozwalają nam wywołać określoną metodę w zależności od adresu, jaki wpisze użytkownik (ale ‘dopasowanie’ dotyczy tylko tej części ścieżki, która jest specyficzna dla aplikacji). Jeśli adnotację dodamy też do całej klasy kontrolera, to wartość którą podamy dodaje się do każdego z mapowań zdefiniowanych nad metodami tej klasy.
Model — przekazywanie danych do widoku
Zanim nauczymy się odbierać dane od użytkownika naszej aplikacji, zobaczmy jak możemy przekazywać je do widoku z kontrolera. Jeśli wrócimy do diagramu ilustrującego wzorzec MVC możemy zauważyć że służy do tego Model. W Springu mamy dwie możliwości korzystania z modelu: zamiast stringa zwrócić ModelAndView (który w zasadzie łączy model i nazwę widoku w jeden obiekt) lub ‘pobrać’ Model jako argument metody. Poniżej skorzystamy z tej drugiej metody, wydaje mi się że jest to czytelniejsze , jest to także ‘nowsza’ praktyka (tutaj możesz zapoznać się z ciekawą dyskusją na ten temat i argumentami za obiema opcjami). klasa która nas interesuje to org.springframework.ui.Model, a najbardziej jej metoda addAttribute(String, Object), która pozwala nam przekazać dowolny obiekt do widoku. Zobaczmy poniższy kod:
@Controller
public class ExampleController {
@RequestMapping("/przyklad/model")
public String przykladModelu(Model model) {
model.addAttribute("message", "To jest jakaś super informacja");
return "glowny";
}
}
Przekazuje on do widoku nasz komunikat za pomoca klucza (nazwy atrybutu) ‘message’. W naszym widoku wystarczy użyć zapisu np. :
<strong>${message}</strong>
aby wyświetlić przekazaną przez model informację. Składnia ${…} jest zdefiniowana w standardzie ExpressionLanguage . Jest to bardzo ciekawe narzędzie, które z jednej strony ma bardzo duże możliwości, a z drugiej jest proste w użyciu. Polecam zapoznać się z dokumentacją , do której link znajdziesz na końcu strony :)
Odczytywanie informacji od użytkownika
To, co omówiliśmy do tej pory pozwala nam na stworzenie aplikacji webowej, która wyświetla mniej więcej statyczne strony (wiemy już, jak dodawać elementy dynamiczne, ale nie są one póki co zależne od tego, co zrobi użytkownik). Czas najwyższy to zmienić i zająć się interakcją z użytkownikiem oraz odczytywaniem przesyłanych informacji
Dane z adresu URL
Pierwszy sposób na przekazywanie informacji do aplikacji webowej to za pomocą adresu URL. Są tutaj dwie możliwości:
- http://localhost:8080/koty/pokaz?imie=mruczek
- http://localhost:8080/koty/pokaz/mruczek
W pierwszym przypadku dane przekazujemy za pomocą tzw. parametrów i ich odczytywanie nie różni się niczym od odczytywania danych z formularza drugą metodą (w istocie jest to formularz wysłany z użyciem metody GET) i dlatego chwilowo nie będziemy się tym zajmować.
Sposób pokazany w drugim punkcie jest preferowany jeśli mamy małą ilość informacji z kilku powodów:
- jest przyjazny dla wyszukiwarek internetowych
- jest estetyczny
- łatwiej go zrozumieć i zinterpretować po prostu patrząc na niego
Spring pozwala nam w mapowaniu wykorzystać tzw. path variables (zmienne ścieżki? Nie spotkałem się prawdę mówiąc z ogólnieprzyjętym tłumaczeniem). W uproszczeniu wygląda to w ten sposób, że wskazujemy że w pewnym miejscu adresu URL będzie informacja którą chcemy uzyskać (np w powyższym przypadku imię kotka). W pewnym sensie działa to podobnie do wyrażeń regularnych, które poznaliśmy kilka lekcji wcześniej (tak naprawdę możemy używać wyrażeń regularnych żeby doprecyzować jak ma wyglądać informacja którą chcemy, ale o tym możesz poczytać samodzielnie). Łatwiej będzie nam zobaczyć to na przykładach. Dodajmy do naszego kontrolera następującą metodę:
@Controller
public class ExampleController {
@RequestMapping("/kot/{imie}")
public String szczegolyKota(@PathVariable("imie") String imieKota) {
return "glowny";
}
}
Jak widzisz dodaliśmy do tej metody argument typu String i nazwie wiadomość oraz przy tym argumencie (przed typem argumentu!) dodaliśmy adnotacje @PathVariable(“nazwa”). W ścieżce którą zapisaliśmy w adnotacji @RequestMapping mamy z kolei zapis {nazwa} — tzw. placeholder. Taka budowa mówi nam mniej więcej: “To, co w adresie będzie w miejscu {xyz}, zapamiętaj do użytku pod kluczem xyz, i wstaw to do argumentu metody, który ma adnotację @PathVariable(“xyz”) “.
Dane z formularzy — metoda ‘szybka’
W podtytule specjalnie użyłem apostrofów, ponieważ opisana tutaj metoda jest ‘szybka’ do zaimplementowania tylko z pozoru — faktycznie nie wymaga ona tworzenia dodatkowych obiektów i oszczędza trochę czasu, ale znacznie utrudnia pracę z formularzami i prowadzi do dziwnych konstrukcji związanych z walidacją. Przedstawiamy ją tutaj tylko dlatego, że można ją często spotkać w istniejących projektach. Pisząc własny kod, o ile nie jesteś pewna, że to dokładnie tej metody potrzebujesz, korzystaj z metody opisanej w lekcji 10!
Użycie tej metody jest podobne do opisanej powyżej — wystarczy dodać adnotację do atrybutu metody, nie musimy jednak modyfikować naszej ścieżki.
Mając np. kod:
@Controller
public class ExampleController {
@RequestMapping("/metoda")
public String widok(@RequestParam("a") String danaA, @RequestParam("b") Integer danaB) {
return "glowny";
}
}
Pod adresem /aplikacja/metoda?a=1&b=2, wartością argumentu danaA będzie “1”, a wartością danaB będzie liczba 2 (to też świetny przykład jak Spring sam dba o konwersje typów ‘w tle’ — nie musimy mu mówić dokładnie co ma zrobić, a jedynie jakich danych oczekujemy, a on sam zajmie się resztą (o ile będzie ‘wiedział’ jak to robić).
Jeśli z kolei wpiszemy adres /aplikacja/metoda?a=1, otrzymamy błąd (400: BadRequest) ponieważ brakuje jednego z argumentów. Żeby uniknąć tego rodzaju błędów i oznaczyć któryś z parametrów jako opcjonalny, możemy dodać argument do adnotacji wskazujący, że nie jest to wymagane pole. Przykład poniżej:
@Controller
public class ExampleController {
@RequestMapping("/metoda")
public String widok(@RequestParam("a") String danaA, @RequestParam(value = "b", required = false, defaultValue = "0") Integer danaB) {
return "glowny";
}
}
Metoda ta działa zarówno dla zapytań i danych przekazywanych za pomocą metod GET jak i POST.
Problem pojawia się np. w sytuacji kiedy odbieramy dane z formularza, następnie sprawdzamy je, po czym w razie wystąpienia problemów chcemy wyświetlić użytkownikowi informacje o problemie i ponownie wyświetlić formularz. Tym sposobem sami musimy zadbać o zapisanie tych danych, ich uzupełnienie oraz wypisanie odpowiednich komunikatów. To sporo niepotrzebnego kodu, a co więcej, Spring może to zrobić za nas.
Szczegółowo opiszemy to w kolejnej lekcji, gdzie nauczymy się także dodawać walidację do poszczególnych pól i reagować na błędne dane
Zadanie
W tej lekcji zadaniem jest stworzenie podstaw do naszej aplikacji:
- Dodaj kontroler o nazwie KotyKontroler
- Podłacz do kontrolera naszą klasę KotDAO
- Utwórz metody do obsługi każdej z operacji na kocie którą mamy w systemie (dodaj, wypisz wszystkie, pokaż szczegóły)
- Utwórz i podepnij statyczne strony HTML do każdej z tych metod (na stronie z listą powinna być metoda, która pokaże listę kotów, po kliknięciu na każdego z nich powinniśmy przejść do ekranu szczegółów kota; na stronie z listą powinien być też przycisk z odnośnikiem do dodawania)
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!