W poprzednich wpisach pokazałem jak stworzyć prostą aplikację z pomocą Spring Boota. Dzisiaj chciałbym rozszeżyć tamten wpis o temat przekazywania zmiennych do aplikacji używając URL. Zakładam, że wiesz już jak stworzyć podstawowy szkielet działającej aplikacji, jeśli nie to zapraszam do przeczytania wpisu na ten temat pod adresem: http://blog.mloza.pl/spring-boot-szybkie-tworzenie-aplikacji-web-w-javie/.
W pierwszym poście na temat tworzenia aplikacji w Spring Boot pokazywałem jak możemy zmapować adres url na metodę w kontrolerze. Nie wspomniałem wtedy o tym, że możemy również w adresie zawrzeć parametry które mogą być przekazywane do naszej funkcji. Jest to bardzo użyteczne i szeroko wykorzystywane w aplikacjach. Przykładowo, możemy napisać metodę która ma za zadanie wyciągnać zawartość wpisu na blogu z bazy danych. Zamiast tworzyć oddzielne metody dla każdego wpisu i ręcznie je mapować, możemy stworzyć jedną metodę której będziemy przekazywać identyfikator wpisu. Na podstawie tego identyfikatora, metoda znajdzie odpowiedni wpis i zwróci go do przeglądarki.
W poście skupie sią na dwóch metodach przekazywanie danych. Pierwsza to użycie QueryString – jest to część adresu występująca po znaku zapytania, na przykład: http://blog.mloza.pl/przykladowy/url?klucz=wartosc&nazwa=123. Zmienne podajemy w formacie klucz=wartosc, a kolejne elementy oddzielamy znakiem &.
Drugą możliwość przesyłania danych jest umieszczenie ich bezpośrednio w adresie url. Przykładowo: http://blog.mloza.pl/przykladowy/url/wartosc/123. W takim wypadku nie przekazujemy już kluczy, a jedynie wartości.
Kod źródłowy przykładów znajduje się w GitHubie pod adresem: https://github.com/mloza/spring-boot-params
Implementacja w Spring Boot: query string
Zacznijmy od przekazywania parametrów przez query string. Musimy stworzyć metodę na którą będzie mapowany url. Następnie podajemy jako listę parametrów metody wszystkie zmienne których się spodziewamy. Każdy parametr adnotujemy @RequestParam i nadajemy mu nazwę taką jak klucz który będziemy przekazywać podczas uruchomienia aplikacji:
Zacznijmy od przekazywania parametrów przez query string. Musimy stworzyć metodę na którą będzie mapowany url. Następnie podajemy jako listę parametrów metody wszystkie zmienne których się spodziewamy. Każdy parametr adnotujemy @RequestParam i nadajemy mu nazwę taką jak klucz który będziemy przekazywać podczas uruchomienia aplikacji:
@RequestMapping("/querystring") | |
@ResponseBody | |
public String queryStringMapping( | |
@RequestParam String param1, | |
@RequestParam String param2) { | |
return String.format("Otrzymane wartoÅci: param1=%s, param2=%s", param1, param2); | |
} |
I to w zasadzie wystarczy. Po uruchomieniu aplikacji i przejściu pod adres http://localhost:8080/querystring?param1=asd¶m2=asd zostanie nam wyświetlony tekst:
Otrzymane wartości: param1=asd, param2=asd
Parametry opcjonalne
Spróbujmy wejść teraz na tą samą stronę nie podając jednego z parametrów, korzystając z takiego url: http://localhost:8080/querystring?param1=asd. Otrzymamy błąd 400 z informacją, że brakuje zdefiniowanego argumentu param2.
Czasem chcemy aby część parametrów była opcjonalna. Aby tak się stało należy dodać do adnotacji @RequestParam argument required=false.
@RequestMapping("/querystring") | |
@ResponseBody | |
public String queryStringMapping( | |
@RequestParam String param1, | |
@RequestParam(required = false) String param2) { | |
return String.format("Otrzymane wartoÅci: param1=%s, param2=%s", param1, param2); | |
} |
Po odświeżeniu strony zwrócony zostanie tekst:
Otrzymane wartości: param1=asd, param2=null
Czyli zamiast param2 otrzymaliśmy null.
Inne nazwy parametrów metody i kluczy w URL
Czasem potrzebujemy nazwać parametr w metodzie inaczej niż klucz przekazany w URL. Przykładowo klucz zawiera pauzy (-) które nie mogą być częścią nazwy parametru. Możemy wtedy przekazać nazwę parametru który ma zostać zmapowany przez atrybut value lub name adnotacji. Załóżmy, że chcemy aby w kodzie nasze parametry nazywały się p1 i p2, możemy to zrobić w następujący sposób:
@RequestMapping("/querystring") | |
@ResponseBody | |
public String queryStringMapping( | |
@RequestParam("param1") String p1, | |
@RequestParam(required = false, name = "param2") String p2) { | |
return String.format("Otrzymane wartoÅci: param1=%s, param2=%s", p1, p2); | |
} |
Automatyczne typowanie zmiennych
Gdy chcemy przkazać w parametrze liczbę, nie musimy jej ręcznie parsować. Wystarczy jako parametr ustawić typ liczbowy i Spring dokona konwersji za nas. W przypadku gdy spodziewamy się wartości liczbowej, a otrzymamy tekst, zostanwe wyrzucony wyjątek.
@RequestMapping("/querystring") | |
@ResponseBody | |
public String queryStringMapping( | |
@RequestParam("param1") String p1, | |
@RequestParam(required = false, name = "param2") String p2, | |
@RequestParam int p3) { | |
return String.format("Otrzymane wartoÅci: param1=%s, param2=%s, p3=%d", p1, p2, p3); | |
} |
Po wpisaniu w przeglądarkę adresu: http://localhost:8080/querystring?param1=asd&p3=123 zostanie nam wyświetlone:
Otrzymane wartości: param1=asd, param2=null, p3=123
Spróbujmy teraz zminieć p3 na jakąś wartość tekstową, np. http://localhost:8080/querystring?param1=asd&p3=txt, wtedy otrzymamy taki wyjątek:
Przekazywanie parametrów przez URL
Jeśli chcemy przekazać parametry w URL musimy zawrzeć tą informację w adnotacji @RequestMapping wstawiając odpowiednie placeholdery w miejsca gdzie będą zmienne. Wartości parametrów trafią jak poprzednio do metody poprzez argumenty, z tą różnicą, że tym razem należy wykorzystać adnotację @PathVariable.
@RequestMapping("/path/{id}") | |
@ResponseBody | |
public String pathVariable(@PathVariable String id) { | |
return String.format("WartoÅÄ zmiennej id = %s", id); | |
} |
Przejście na stronę http://localhost:8080/path/identyfikator zwróci nam tekst: Wartość zmiennej id = identyfikator.
Automatyczne typowanie zmiennych
W tym przypadku również możemy zmienić typ parametrów jak to miało miejsce w przypadku query string.
@RequestMapping("/path/{id}") | |
@ResponseBody | |
public String pathVariable(@PathVariable int id) { | |
return String.format("WartoÅÄ zmiennej id = %s", id); | |
} |
Również w tym przypadku otrzymamy błąd jeśli spodziewamy się liczby a przekażemy np. tekst.
Parametry opcjonalne
Adnotacja PathVariable również posiada argument required. Jednak w tym przypadku jest to trochę bardziej skomplikowane. Tutaj zmienna jest częścią adresu url, więc jeśli ją po prostu pominiemy to adres nie zostanie rozpoznany i storna nie zostanie wyświetlona. Zamiast niej otrzymamy błąd 404. Jednakże, RequestMapping może przyjąć wiele mapowań URL, więc możemy przkeazać takie w którym nasza zmienna nie występuje i wtedy ją oznaczyć jako required = false.
@RequestMapping({"/path/{id}", "/path"}) | |
@ResponseBody | |
public String pathVariable( | |
@PathVariable(required = false) Integer id) { | |
return String.format("WartoÅÄ zmiennej id = %s", id); | |
} |
Warto również zwrócić uwagę, że zmieniłem typ argumentu id z int na Integer. Zabieg ten jest konieczny ponieważ int nie może przyjąć wartości null, jeśli zostawimy malego inta i nie podamy wartości parametru dostaniemy wtedy błąd.
Walidacja otrzymanych danych
Używając zmiennych w URL możemy również przekazać wyrażenie regularne które będzie sprawdzać poprawność danych.
@RequestMapping({"/path/{id:[0-9]{2,5}}", "/path"}) | |
@ResponseBody | |
public String pathVariable( | |
@PathVariable(required = false) Integer id) { | |
return String.format("WartoÅÄ zmiennej id = %s", id); | |
} |
Trzeba jednak pamietać, że wyrażenie to jest używane do dopasowania ścieżki, więc jeśli przekażemy parametr który nie pasuje do wyrażenia to otrzymamy błąd 404. W tym przypadku oznacza to, że nie znaleziono mapowania dla danego adresu URL.
Podsumowanie
Spring zapewnia nam bardzo łatwe przekazywanie parametrów do metody. Dzięki temu możemy łatwo i szybko tworzyć dynamiczne strony, oszczędza to czas który byśmy musieli w innym przypadku spędzić na kodowaniu. Dodatkowo otrzymujemy podstawowe narzędzia do sprawdzenia poprawności przekazywanych parametrów.
Trzeba również pamiętać, że długość URL jest ograniczona. Wielkość tego ograniczenia jest definiowana w konfiguracji serwera. Specyfikacja HTTP mówi, że nie powinno być to mniej niż 8000 oktetów (oktet to 8 bitów).