Grudzień 29, 2019

Jak działa Spring Web MVC?

W tym wpisie przedstawię Ci, w jaki sposób można stworzyć prostą stronę internetową przy użyciu Spring  Web MVC. Znajdziesz w nim również informację, na czym polega wzorzec MVC i jak działa to w Spring Framework.

Wzorzec MVC

MVC jest skrótem od Model-View-Controller, czyli od trzech elementów, na które składa się cały wzorzec. Nie jest on jakoś bardzo skomplikowany, wystarczy, że zapamiętasz poniższy, popularny graf reprezentujący wzorzec oraz za co odpowiedzialny jest każdy z elementów.

Czyli jak już wspomniałem wyróżniamy trzy elementy:

  • model – jest odpowiedzialny za przechowywanie informacji, które będziemy przesyłać między serwerem, a klientem;
  • widok – definiuje sposób reprezentacji danych, ostatecznie jest to plik HTML wyświetlany użytkownikowi, jednak zanim do tego dojdzie zostaje zazwyczaj wypełniany odpowiednimi danymi z modelu;
  • kontroler – tutaj zawiera się cała logika naszej aplikacji, jest odpowiedzialny za uzupełnienie modelu oraz zwrócenie klientowi odpowiedniego widoku.

Tak w skrócie prezentuje się wzorzec MVC. Jeśli coś dla Ciebie jeszcze nie jest jasne, to niczym się nie martw – wszystko stanie się zrozumiałe dopiero w sytuacji, gdy stworzymy prostą stronę internetową. Przynajmniej ja tak kiedyś miałem, wszędzie klepane były podobne regułki jak ta wyżej, które w ogóle mi nie pomagały.

Spring Web MVC

Postaram Ci się teraz opowiedzieć w jaki sposób ten cały wzorzec działa w Spring Framework. Od razu zaznaczę, że nie będziemy tego wszystkie ręcznie konfigurować, ponieważ jest to zbędne, od czasu gdy w 2014 roku została opublikowana pierwsza wersja projektu Spring Boot.

W całym procesie, od otrzymania zapytania HTTP od klienta, aż do zwrócenia mu odpowiedniej informacji bierze udział kilka bytów, które teraz pokrótce opiszę.

1. DispatcherServlet

DispatcherServlet zwany centralnym serwletem, przyjmuje wszystkie zapytania HTTP trafiające do naszego serwera. Jest odpowiedzialny za delegowanie pracy do odpowiednich komponentów naszej aplikacji.

Mówiąc precyzyjniej, DispatcherServlet wykorzystuje inne obiekty m.in. do przetwarzania zapytania klienta, zwrócenia mu odpowiedniego widoku oraz wykonuje inne procesy przydatne w czasie działania tego mechanizmu.

Innymi procesami, które może wywoływać to np. parsowanie multi-part requestów (upload plików), rozpoznanie strefy czasowej użytkownika lub przetwarza filtry, które mogą np. modyfikować nagłówki odpowiedzi. Jednak w tym artykule skupimy się tylko na trzech najważniejszych obiektach, które omówię poniżej.

2. HandlerMapping

DispatcherServlet wykorzystuje HandlerMapping w celu odnalezienia odpowiedniego kontrolera, który powinien zostać wywołany na podstawie ustalonych kryteriów, czyli jaki kontroler i jaka jego metoda jest przypisana pod konkretny adres URL.

3. HandlerAdapter

W przypadku, gdy kontroler i metoda zostaną już odnalezione to następnie jest wykorzystywany HandlerAdapter. Wspomiany adapter ma za zadanie wywołać znalezioną wcześniej metodę. Niby nic skomplikowanego, gdyby nie fakt, że musi ogarnąć cały tzw. proces resolving annotations czyli wstawić jako argumenty metody obiekty oznaczone adnotacjami np. @PathVariable lub @RequestBody.

4. ViewResolver

Ze względu, że kontrolery zwracają nam nazwę widoku jako typ String to potrzebujemy pewnego obiektu odpowiedzialnego za odnajdywanie widoku, który powinien zostać zwrócony w odpowiedzi dla klienta.

ViewResolver jest łatwo podmienialny, zależnie od tego, który chcemy wykorzystywać i zazwyczaj tyczy się to naszych preferencji. Mamy do wyboru kilka tzw. template engine:

  • Thymeleaf;
  • Groovy markup templates;
  • JSP.

Możesz się zastanowić do czego jeszcze może się przydać taki template engine? Odpowiedź jest prosta, zazwyczaj chcemy, aby nasze strony były spersonalizowane i dla każdego klienta wyświetlały inne dane – właśnie w tym pomagają nam te narzędzia. Przy pomocy użycia odpowiednich słów kluczowych (zależnie od silnika jaki wybierzemy) i modelu, template engine potrafi dynamicznie dla nas wygenerować widok HTML.

5. Inne

O innych „specjalnych” (jak to jest napisane w dokumentacji) beanych możesz poczytać tutaj, wszystkie te byty są wykorzystywane do specjalnych zadań przez wspomniany wcześniej DispatcherServlet.

Warsztat

Udało się przebrnąć przez sporą dawkę teorii, przejdźmy teraz do stworzenia prostej strony internetowej przy użyciu Spring Web MVC. Tak jak wspomniałem – zrobimy to dosyć szybko przy użyciu Spring Boota. W przypadku, gdybyśmy nie chcieli z niego skorzystać musielibyśmy sami skonfigurować DispatcherServlet oraz ViewResolver.

Projekt jak zwykle tworzymy w Spring Initialzr.Wystarczy, że do projektu dodamy następujące zależności:

  • Spring web;
  • Thymeleaf.

Jeśli nie wiesz jak wygenerować projekt Spring Boot, to koniecznie zajrzyj do tego artykułu.

Ze względu, że wykorzystujemy Spring Boota i Thymeleaf, DispatcherServlet oraz ViewResolver zostały już za nas skonfigurowane. Jeśli nie chcemy nic zmieniać, to tak naprawdę możemy już pisać kod naszej aplikacji.

Kontroler

Na początku musimy stworzyć kontroler i zmapować go na konkretny adres URL. Dzięki temu zostanie on wywołany przez DispatcherServlet, gdy tylko klient wyśle zapytanie pod wcześniej zdefiniowany adres.

package pl.blog.spring.startmvc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloController {

  @GetMapping("/hello")
  public String sayHello() {
    return "hello";
  }
}

Zanim przejdziemy dalej wytłumaczę Ci ten krótki kod.

Adnotacja @Controller oznacza klasę HelloController oczywiście jako kontroler, czyli DispatcherServlet może od tego momentu delegować do niego pracę.

Adnotacja @GetMapping definiuje pod jakim adresem ma być wywołana dana metoda. 

Na sam koniec mamy magiczne: return "hello";

Czyli zwracamy nazwę widoku „hello”, jest to widok, który zostanie finalnie wyświetlony klientowi.

Widok

Skoro wcześniej zwróciliśmy nazwę widoku, to czas go stworzyć. Widoki domyślnie umieszczamy w folderze resources/templates/, oczywiście można to skonfigurować według własnych upodobań.

Nasz widok musi się nazywać hello.html, a wyglądać może dowolnie – u mnie on prezentuje się tak:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello boy</title>
</head>
<body>
    <h1>Witam serdecznie</h1>
</body>
</html>

Skoro mamy już wszystko możemy uruchomić aplikację i sprawdzić co się kryje pod adresem localhost:8080/hello.

Podsumowanie

I to na tyle podstaw Spring Web MVC. W tym artykule dowiedziałeś się czym jest wzorzec oraz jak Spring Framework sobie to wszystko ogarnia „pod spodem”. Co prawda, kryje się tam trochę więcej magii, ale niczym się nie martw. Zapewniam Cię, że wystarczy nam tylko tyle wiedzieć o działaniu tego całego mechanizmu.

W tym wpisie nie poruszyłem kwestii użycia modelu – wyświetliliśmy tylko widok, bez żadnych dynamicznych danych. To wszystko zmieni się w kolejnym wpisie z tej serii. Pokażę wtedy jak można wykorzystać Thymeleaf do wyświetlania danych oraz ich zapisywania poprzez formularz.

Kod projektu znajdziesz w tym repozytorium.