Thymeleaf i mongoDB

Dzisiaj skupię się na dwóch narzędziach, z których będę korzystać podczas pracy nad projektem, a o których do tej pory nie napisałem wystarczająco dużo, mianowicie – Thymeleaf i mongoDB.

Thymeleaf

Thymeleaf to narzędzie służące do komunikacji między serwerem a widokiem aplikacji. Poprzez dodanie specjalnych atrybutów w wybranych znacznikach możemy w kodzie html wykorzystywać takie elementy języków programowania jak instrukcje warunkowe czy pętlę for-each. Dodatkowo Thymeleaf umożliwia nam pobranie elementów wysłanych z serwera (np. dane z bazy danych) oraz wyświetlenie ich na naszej stronie.

Jako pierwszy przykład wyświetlimy na stronie wartość pobraną z adresu URL i przesłaną do widoku przez kontroler. Aby to zrobić musimy dodać następującą metodę do klasy pl.mocode.controller.MainController:

@RequestMapping("/{name}")
public String getMainPageWithName(@PathVariable String name, Model model) {
    model.addAttribute("name", name);
    return "main";
}

Pojawiło się kilka nowych rzeczy, ale zaraz wszystko po kolei wytłumaczę 😉 Zacznijmy od parametru model typu Model – najprościej rzecz ujmując, służy on do przesyłania informacji do widoku aplikacji. Dzięki funkcji addAttribute możemy wysłać jakąś zmienną (drugi argument funkcji) do widoku, gdzie będziemy mogli się do niej odwołać pod nazwą podaną w pierwszym argumencie. Jak widać na powyższym przykładzie do widoku przesyłamy zmienną name typu String. Adnotacja @PathVariable przed tą zmienną w parametrze odwołuje ją do zmiennej ze ścieżki URL o tej samej nazwie w nawiasie klamrowym.

Przyjrzyjmy się jaka zmiana nastąpiła w pliku resources/templates/main.html. Przede wszystkim dołączony został Thymeleaf w znaczniku html

<html lang="en" xmlns:th="http://www.thymeleaf.org">

Dzięki temu możemy odwoływać się do jego funkcji przy pomocy tagu th. Od razu wykorzystamy jego możliwości w znaczniku h1

<h1 th:text="'Hello ' + ${name} + '!'"></h1>

Aby odwołać się do przesłanej z kontrolera zmiennej należy wpisać jej nazwę w nawiasie klamrowym poprzedzonym znakiem dolara. Zobaczmy, jak działa nasz przykład w praktyce:

Jeżeli chcesz zapoznać się z innymi możliwościami Thymeleafa to odsyłam Cię do dokumentacji, a w przykładzie z bazą mongoDB skorzystamy z pętli for-each 😉

mongoDB

Dosłownie kilka słów wstępu i przechodzimy do konkretów 🙂 MongoDB to nierelacyjna baza danych, przez co jest bardziej skalowalna niż SQLowe bazy. Dane są przechowywane w formacie JSON, natomiast generowany ID jest ciągiem znaków (zmienna typu String).

Idąc za przykładem z oficjalnej strony Springa stwórzmy następujące klasy: pl.mocode.model.Customer,  pl.mocode.controller.CustomerController oraz interfejs pl.mocode.dao.CustomerDao (odpowiednik CustomerRepository).

Klasa Customer składa się z prostych deklaracji pól, getterów i setterów oraz konstruktorów, jedyne na co warto zwrócić uwagę, to deklaracja pustego konstruktora, który jest wymagany do poprawnego działania na repozytorium. Interfejs CustomerDao rozszerza interfejs MongoRepository, który trzeba uzupełnić o typ klasy bazowej (w naszym przypadku klasa Customer) oraz typ ID (jak wspominałem wyżej, w przypadku mongoDB – String). Ciekawsze rzeczy zaczynają się dziać w klasie CustomerController:

@Autowired
private CustomerDao customerDao;

Adnotacja @Autowired pozawala nam wstrzyknąć zależność do interfejsu CustomerDao, przez co nie tworzymy za każdym razem nowej instancji customerDao, a cały czas operujemy na ogólnej dla całego projektu. Takie działanie nazywa się Dependency Injection (DJ).

@RequestMapping("/customers")
public String getCustomerListPage(Model model) {
    model.addAttribute("customerList", customerDao.findAll());
    return "customers";
}

Tutaj przesyłamy do widoku listę (List<Customer>) wszystkich zapisanych w bazie danych klientów, przy pomocy funkcji findAll(). Lista dostępna będzie w widoku pod nazwą customerList.

@RequestMapping("/customer/add/{firstName}/{lastName}")
public String createCustomer(@PathVariable String firstName, @PathVariable String lastName) {
    Customer customer = new Customer(firstName, lastName);
    customerDao.save(customer);
    return "redirect:/customers";
}

Następnie implementujemy możliwość dodawania nowych klientów do bazy przy użyciu metody GET. Utworzonego klienta zapisujemy w bazie przy pomocy funkcji save(customer). W wartości zwracanej korzystamy z metody redirect:, która przekierowuje użytkownika na wpisany po niej adres (w naszym przypadku do listy wszystkich klientów).

@RequestMapping("/customer/delete/{id}")
public String deleteCustomersById(@PathVariable String id) {
    customerDao.delete(id);
    return "redirect:/customers";
}

@RequestMapping("/customer/delete/all")
public String deleteAllCustomers() {
    customerDao.deleteAll();
    return "redirect:/customers";
}

Kolejne dwie metody umożliwiają usuwanie danych z bazy. W pierwszym przypadku możemy usunąć wybranego klienta wpisując w adresie strony jego ID, natomiast w drugim korzystając z funkcji deleteAll() usuwamy wszystkie zapisane w bazie dane dotyczące klientów.

Zwróćmy uwagę jeszcze na plik resources/templates/customers.html, a szczególnie na poniższy fragment:

<tr th:each="customer : ${customerList}">
    <td th:text="${customer.id}"></td>
    <td th:text="${customer.firstName}"></td>
    <td th:text="${customer.lastName}"></td>
    <td><a th:href="@{'/customer/delete/' + ${customer.id}}">Delete</a></td>
</tr>

Przy pomocy tagu th:each iterujemy po każdym obiekcie z listy customerList (przesłanego przed chwilą z CustomerController), a obecnie iterowany obiekt znajduje się pod nazwą customer. W ten sposób w kolejnych wierszach tabelki możemy wpisać wybrane wartości. Ostatnia kolumna tabelki zawiera odnośnik do adresu „/customer/delete/{id}”, dzięki czemu możemy usunąć konkretnego klienta z bazy.

Po wpisaniu poniższych adresów w przeglądarce:

http://localhost:8081/customer/add/Jakub/Kalinowski
http://localhost:8081/customer/add/Teofil/Sawicki
http://localhost:8081/customer/add/Aleksander/Kowalski

Efekt naszej pracy przedstawia się następująco:

Podsumowanie

Mam nadzieję, że dowiedzieliście się dzisiaj czegoś nowego, a może nawet ciekawego 🙂 W sobotę dalsza część rozwoju projektu, w którym zaimplementujemy funkcje rejestracji i logowania użytkowników. Do zobaczenia! 🙂

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *