#14 — Spring Data

By 27 November 2014 August 20th, 2016 Kurs Javy

W dzisiejszej lekcji poz­namy narzędzie, które znacznie uproś­ci i skró­ci nam pracę, związaną z obsługą bazy danych. Czy pamię­tasz, jak w ostat­niej lekcji pisałaś kod pobier­a­ją­cy listę obiek­tów z bazy danych? Wyma­gało to utworzenia nowej metody, w niej utworzenia zapy­ta­nia za pomocą Enti­ty­Man­agera, pobra­nia wyników i obsłuże­nia sytu­acji, w której nie ma wyniku lub otrzy­mu­je­my wyjątek. A gdy­bym powiedzi­ał, że wystar­czy tylko pier­wszy krok, nazwa metody? Przed­staw­iam zatem Spring Data :)

Lekcja

Interfejsy

Na wstępie powiemy sobie o inter­fe­jsach — do tej pory nie uży­wal­iśmy ich bezpośred­nio, dzisi­aj będą nam one niezbędne. Inter­fe­jsy tworzymy podob­nie do klas, przykład­owy inter­fe­js wyglą­da następująco:

public interface Interfejs {
    public void zrobCos();
}

Jak zapewne sama widzisz, deklaru­je­my metody (nazwy, zwracany typ, argu­men­ty), ale nie tworzymy ich imple­men­tacji — tym zaj­mu­je się klasa która imple­men­tu­je interfejs:

public class ImplementacjaInterfejsu implements Interfejs {
    //...
}

Inter­fe­jsy służą do usta­la­nia kon­trak­tu pomiędzy mod­uła­mi (czyli sposobu ich inter­akcji, korzys­ta­nia z siebie nawza­jem) — pod­czas gdy imple­men­tac­ja może się zmieni­ać, sam inter­fe­js pozosta­je ten sam, dzię­ki czemu ukry­wamy nieis­totne szczegóły przed inny­mi mod­uła­mi. Więcej o zas­tosowa­niu inter­fe­jsów i dlaczego są tak ważne w pro­gramowa­niu obiek­towym powiemy sobie w dal­szych lekc­jach, kiedy będziemy pra­cow­ać nad warsztatem.

Dodawanie Spring Data do projektu

Maven

Do pom.xml doda­je­my zależnosć do org.springframework.data:spring-data-jpa

Konfiguracja Spring XML

Aby Spring­Da­ta poprawnie ‘widzi­ało’ nasze repozy­to­ria, musimy dodać następu­ją­cy fragment:

<jpa:repositories base-package="pl.kobietydokodu"/>

Podob­nie jak w przy­pad­ku JPA i mapowań, base-pack­age musi wskazy­wać na paki­et, pod którym są wszys­tkie nasze repozytoria.

Aby plik XML nadal był poprawny, musimy do tagu <beans> (na samej górze) dodać dwa ele­men­ty: atry­but xmlns:jpa=“http://www.springframework.org/schema/data/jpa” oraz lin­ijkę “http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa‑1.0.xsd” (bez cud­zysłowów) wewnątrz atry­bu­tu schemaLocation

Spring Data

Spring Data to narzędzie, które bazu­je na JPA — nadal potrze­bu­je­my więc Enti­ty­Man­ager­Fac­to­ry w naszej kon­fig­u­racji Springa. Różni­ca w sto­sunku do JPA jest taka, że bib­liote­ka ta na pod­staw­ie samej nazwy metody budu­je zapy­tanie i obsługu­je zwracanie danych, niek­tóre wyjąt­ki itp. Jed­nocześnie, jeśli potrze­bu­je­my specy­ficznych funkcjon­al­noś­ci, sami może­my zdefin­iować zapy­tanie które ma być użyte (domyśl­nie jest ono automaty­cznie gen­erowane na pod­staw­ie nazwy metody).

Jak się pewnie domyślasz, w takiej sytu­acji nazewnictwem metod rządzą pewne reguły — masz oczy­wiś­cie rację, są pewne zasady ale są one proste do opanowa­nia i log­iczne, ale wszys­tko po kolei :)

Przykład­owe DAO, które uży­wa Spring Data wyglą­da następująco:

@Repository
public interface Interfejs extends Repository<Kot, Long> {
    public Kot findById(Long id);
}

Zwróć uwagę na frag­ment extends Repository<Kot, Long> — ten frag­ment mówi Springowi, że mamy do czynienia z repozy­to­ri­um zarządzanym przez Spring Data.

Taki obiekt uży­wamy jak każdy inny w Springu — doda­je­my go jako pole naszej klasy (np. kon­trol­era) i oznacza­my adno­tacją @Autowired :

public class Kontroler {

    @Autowired
    protected Interfejs dao;

    //...

}

Spring Data samo stworzy imple­men­tację naszego inter­fe­j­su i wstrzyknie ją w tym miejscu.

Z pewnoś­cią zauwazyłaś też adno­tację @Repository — to adno­tac­ja, która mówi Spring Data, że ta klasa odpowia­da za dostęp do danych.

Konstruowanie zapytań na podstawie nazw metod

Szczegóły zna­jdziesz w doku­men­tacji, ale tutaj omówimy kil­ka najważniejszych ele­men­tów i pod­sta­wowych przykładów.

findBy{Query}

Pod­sta­wowe metody do pobiera­nia zaczy­na­ją się od frazy find­By, po czym tworzymy właś­ci­we zapy­tanie. Załóżmy, że chce­my pobrać obiekt na pod­staw­ie pól (mówimy o JPA i obiek­tach, więc patrzymy wg pól klas a nie kol­umn tabel!) imie oraz kolor­Futer­ka. Oba te pola są typu String, chce­my pobrać listę reko­rdów, które speł­ni­a­ją oba te kry­te­ria. Nasza deklarac­ja metody będzie wyglą­dała więc następująco:

List<Kot> findByImieAndKolorFuterka(String imie, String kolorFuterka);

Jak sama widzisz, zami­ast pisać zapy­tanie w HQL, wystarczy:

  • określić typ zwracany przez metodę (u nas lista obiek­tów typu Kot)
  • rozpocząć nazwę od findBy
  • Wyp­isać po kolei nazwy pól, po których chce­my fil­trować, łącząc je spójnikiem Or lub And 
    • Moż­na uzy­wać też dodatkowych mody­fika­torów, np. And­Wiek­GreaterThan albo AndImi­eS­tartsWith, szczegóły zna­jdziesz w dokumentacji
  • Zadeklarować argu­men­ty metody w kole­jnoś­ci (i o typach) w jakiej pojaw­ia­ją się w zapy­ta­niu (nazwie metody)

Praw­da, że banalne?

Tworzenie/aktualizacja obiektów

Aby udostęp­nić metody do tworzenia/aktualizacji obiek­tów, wystar­czy aby nasz inter­fe­js rozsz­erzał inter­fe­js CrudRepos­i­to­ry. Bazu­jąc na przykładzie powyżej:

@Repository
public interface Interfejs extends CrudRepository<Kot, Long> {
    public Kot findById(Long id);
}

Rozsz­erza­jąc CrudRepos­i­to­ry musimy podać typ obiek­tu oraz typ klucza głównego obiek­tu (tego pola, które ma adno­tację @Id) — w naszym przy­pad­ku będą to odpowied­nio typy Kot oraz Long . Sama kon­strukc­ja to tzw. gener­ics, o których powiemy sobie w lekc­jach służą­cych szli­fowa­niu warsztatu :)

Po rozsz­erze­niu może­my użyć metody save(Kot kot), która zarówno aktu­al­izu­je obiekt (jeśli obiekt ten ma id, które zna­j­du­je się w bazie danych) lub tworzy nowy rekord.

Podsumowanie

Celem ostat­nich 3 lekcji było nie tylko pokazanie, jak korzys­tać z tech­nologii, które moż­na znaleźć w pro­jek­tach z który­mi się spotkasz, ale także aby pokazać Ci, jak zmienia się pro­gramowanie i w jakim kierunku te zmi­any idą. Rozwój bib­liotek i narzędzi dąży do tego, aby pro­gramista musi­ał pisać jak najm­niej tzw. boil­er­plate code (mówiliśmy o nim w lekcji o JDBC, w skró­cie jest to kod, który nie real­izu­je żad­nej szczegól­nej funkcjon­al­noś­ci, a musimy go napisać żeby inne ele­men­ty działały).

Zadanie

Zmody­fikuj pro­gram, który już napisałaś tak, aby zami­ast Enti­ty­Man­agera uży­wał Spring Data.

Licencja Creative Commons

Jeśli uważasz powyższą lekcję za przy­dat­ną, mamy małą prośbę: pol­ub nasz fan­page. Dzię­ki temu będziesz zawsze na bieżą­co z nowy­mi treś­ci­a­mi na blogu ( i oczy­wiś­cie, z nowy­mi częś­ci­a­mi kur­su Javy). Dzięki!