W dzisiejszej lekcji poznamy narzędzie, które znacznie uprości i skróci nam pracę, związaną z obsługą bazy danych. Czy pamiętasz, jak w ostatniej lekcji pisałaś kod pobierający listę obiektów z bazy danych? Wymagało to utworzenia nowej metody, w niej utworzenia zapytania za pomocą EntityManagera, pobrania wyników i obsłużenia sytuacji, w której nie ma wyniku lub otrzymujemy wyjątek. A gdybym powiedział, że wystarczy tylko pierwszy krok, nazwa metody? Przedstawiam zatem Spring Data :)
Lekcja
Interfejsy
Na wstępie powiemy sobie o interfejsach — do tej pory nie używaliśmy ich bezpośrednio, dzisiaj będą nam one niezbędne. Interfejsy tworzymy podobnie do klas, przykładowy interfejs wygląda następująco:
public interface Interfejs {
public void zrobCos();
}
Jak zapewne sama widzisz, deklarujemy metody (nazwy, zwracany typ, argumenty), ale nie tworzymy ich implementacji — tym zajmuje się klasa która implementuje interfejs:
public class ImplementacjaInterfejsu implements Interfejs {
//...
}
Interfejsy służą do ustalania kontraktu pomiędzy modułami (czyli sposobu ich interakcji, korzystania z siebie nawzajem) — podczas gdy implementacja może się zmieniać, sam interfejs pozostaje ten sam, dzięki czemu ukrywamy nieistotne szczegóły przed innymi modułami. Więcej o zastosowaniu interfejsów i dlaczego są tak ważne w programowaniu obiektowym powiemy sobie w dalszych lekcjach, kiedy będziemy pracować nad warsztatem.
Dodawanie Spring Data do projektu
Maven
Do pom.xml dodajemy zależnosć do org.springframework.data:spring-data-jpa
Konfiguracja Spring XML
Aby SpringData poprawnie ‘widziało’ nasze repozytoria, musimy dodać następujący fragment:
<jpa:repositories base-package="pl.kobietydokodu"/>
Podobnie jak w przypadku JPA i mapowań, base-package musi wskazywać na pakiet, pod którym są wszystkie nasze repozytoria.
Aby plik XML nadal był poprawny, musimy do tagu <beans> (na samej górze) dodać dwa elementy: atrybut xmlns:jpa=“http://www.springframework.org/schema/data/jpa” oraz linijkę “http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa‑1.0.xsd” (bez cudzysłowów) wewnątrz atrybutu schemaLocation
Spring Data
Spring Data to narzędzie, które bazuje na JPA — nadal potrzebujemy więc EntityManagerFactory w naszej konfiguracji Springa. Różnica w stosunku do JPA jest taka, że biblioteka ta na podstawie samej nazwy metody buduje zapytanie i obsługuje zwracanie danych, niektóre wyjątki itp. Jednocześnie, jeśli potrzebujemy specyficznych funkcjonalności, sami możemy zdefiniować zapytanie które ma być użyte (domyślnie jest ono automatycznie generowane na podstawie nazwy metody).
Jak się pewnie domyślasz, w takiej sytuacji nazewnictwem metod rządzą pewne reguły — masz oczywiście rację, są pewne zasady ale są one proste do opanowania i logiczne, ale wszystko po kolei :)
Przykładowe DAO, które używa Spring Data wygląda następująco:
@Repository
public interface Interfejs extends Repository<Kot, Long> {
public Kot findById(Long id);
}
Zwróć uwagę na fragment extends Repository<Kot, Long> — ten fragment mówi Springowi, że mamy do czynienia z repozytorium zarządzanym przez Spring Data.
Taki obiekt używamy jak każdy inny w Springu — dodajemy go jako pole naszej klasy (np. kontrolera) i oznaczamy adnotacją @Autowired :
public class Kontroler {
@Autowired
protected Interfejs dao;
//...
}
Spring Data samo stworzy implementację naszego interfejsu i wstrzyknie ją w tym miejscu.
Z pewnością zauwazyłaś też adnotację @Repository — to adnotacja, która mówi Spring Data, że ta klasa odpowiada za dostęp do danych.
Konstruowanie zapytań na podstawie nazw metod
Szczegóły znajdziesz w dokumentacji, ale tutaj omówimy kilka najważniejszych elementów i podstawowych przykładów.
findBy{Query}
Podstawowe metody do pobierania zaczynają się od frazy findBy, po czym tworzymy właściwe zapytanie. Załóżmy, że chcemy pobrać obiekt na podstawie pól (mówimy o JPA i obiektach, więc patrzymy wg pól klas a nie kolumn tabel!) imie oraz kolorFuterka. Oba te pola są typu String, chcemy pobrać listę rekordów, które spełniają oba te kryteria. Nasza deklaracja metody będzie wyglądała więc następująco:
List<Kot> findByImieAndKolorFuterka(String imie, String kolorFuterka);
Jak sama widzisz, zamiast pisać zapytanie w HQL, wystarczy:
- określić typ zwracany przez metodę (u nas lista obiektów typu Kot)
- rozpocząć nazwę od findBy
- Wypisać po kolei nazwy pól, po których chcemy filtrować, łącząc je spójnikiem Or lub And
- Można uzywać też dodatkowych modyfikatorów, np. AndWiekGreaterThan albo AndImieStartsWith, szczegóły znajdziesz w dokumentacji
- Zadeklarować argumenty metody w kolejności (i o typach) w jakiej pojawiają się w zapytaniu (nazwie metody)
Prawda, że banalne?
Tworzenie/aktualizacja obiektów
Aby udostępnić metody do tworzenia/aktualizacji obiektów, wystarczy aby nasz interfejs rozszerzał interfejs CrudRepository. Bazując na przykładzie powyżej:
@Repository
public interface Interfejs extends CrudRepository<Kot, Long> {
public Kot findById(Long id);
}
Rozszerzając CrudRepository musimy podać typ obiektu oraz typ klucza głównego obiektu (tego pola, które ma adnotację @Id) — w naszym przypadku będą to odpowiednio typy Kot oraz Long . Sama konstrukcja to tzw. generics, o których powiemy sobie w lekcjach służących szlifowaniu warsztatu :)
Po rozszerzeniu możemy użyć metody save(Kot kot), która zarówno aktualizuje obiekt (jeśli obiekt ten ma id, które znajduje się w bazie danych) lub tworzy nowy rekord.
Podsumowanie
Celem ostatnich 3 lekcji było nie tylko pokazanie, jak korzystać z technologii, które można znaleźć w projektach z którymi się spotkasz, ale także aby pokazać Ci, jak zmienia się programowanie i w jakim kierunku te zmiany idą. Rozwój bibliotek i narzędzi dąży do tego, aby programista musiał pisać jak najmniej tzw. boilerplate code (mówiliśmy o nim w lekcji o JDBC, w skrócie jest to kod, który nie realizuje żadnej szczególnej funkcjonalności, a musimy go napisać żeby inne elementy działały).
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!