REST jezik upita s proljetnim i JPA kriterijima

OSTALO Vrh

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ Ovaj je članak dio serije: • REST jezik upita s proljetnim i JPA kriterijima (trenutni članak) • REST jezik upita s proljetnim podacima JPA specifikacije

• REST jezik upita s Spring Data JPA i Querydsl

• REST jezik upita - Napredno pretraživanje

• REST upitni jezik - implementacija ILI operacija

• REST jezik upita s RSQL-om

• OSTALI jezik upita s web podrškom Querydsl

1. Pregled

U ovom prvom članku ove nove serije istražit ćemo jednostavan jezik upita za REST API. Dobro ćemo iskoristiti Spring za REST API i JPA 2 kriterije za aspekte postojanosti.

Zašto jezik upita? Jer - za bilo koji dovoljno složen API - pretraživanje / filtriranje vaših resursa po vrlo jednostavnim poljima jednostavno nije dovoljno. Jezik upita fleksibilniji je i omogućuje filtriranje do točno potrebnih resursa.

2. Korisnik Entitet

Prvo - iznesite jednostavni entitet koji ćemo koristiti za naš API za filtriranje / pretraživanje - osnovni Korisnik:

@Entity javna klasa Korisnik {@Id @GeneratedValue (strategy = GenerationType.AUTO) private Long id; private String firstName; private String lastName; privatni String e-mail; privatno int doba; }

3. Filtriranje pomoću CriteriaBuilder

Sada - krenimo u stvar problema - upit u sloju postojanosti.

Izgradnja apstrakcije upita stvar je ravnoteže. Potrebna nam je dobra količina fleksibilnosti, s jedne strane, a s druge strane moramo održavati složenost. Visoka razina, funkcionalnost je jednostavna - uđete u neka ograničenja i vratite neke rezultate.

Pogledajmo kako to funkcionira:

@Repository javna klasa UserDAO implementira IUserDAO {@PersistenceContext private EntityManager entityManager; @Override public List searchUser (Parametri popisa) {CriteriaBuilder builder = entityManager.getCriteriaBuilder (); CriteriaQuery query = builder.createQuery (User.class); Korijen r = query.from (User.class); Predikatni predikat = builder.conjunction (); UserSearchQueryCriteriaConsumer searchConsumer = novi UserSearchQueryCriteriaConsumer (predikat, graditelj, r); params.stream (). forEach (searchConsumer); predikat = searchConsumer.getPredicate (); query.where (predikat); Rezultat popisa = entityManager.createQuery (upit) .getResultList (); povratni rezultat; } @Override public void save (User entity) {entityManager.persist (entity); }}

Pogledajmo UserSearchQueryCriteriaConsumer razred:

javna klasa UserSearchQueryCriteriaConsumer implementira Consumer {private predikatni predikat; privatni graditelj CriteriaBuilder; privatni Root r; @Override public void accept (SearchCriteria param) {if (param.getOperation (). EqualsIgnoreCase (">")) {predikat = builder.and (predikat, builder .greaterThanOrEqualTo (r.get (param.getKey ()), param .getValue (). toString ())); } else if (param.getOperation (). equalsIgnoreCase ("<")) {predikat = builder.and (predikat, builder.lessThanOrEqualTo (r.get (param.getKey ()), param.getValue (). toString () )); } else if (param.getOperation (). equalsIgnoreCase (":")) {if (r.get (param.getKey ()). getJavaType () == String.class) {predikat = builder.and (predikat, graditelj .like (r.get (param.getKey ()), "%" + param.getValue () + "%")); } else {predikat = builder.and (predikat, builder.equal (r.get (param.getKey ()), param.getValue ())); }}} // standardni konstruktor, getter, setter}

Kao što vidite, searchUser API uzima popis vrlo jednostavnih ograničenja, sastavlja upit na temelju tih ograničenja, vrši pretragu i vraća rezultate.

Klasa ograničenja je također vrlo jednostavna:

public class SearchCriteria {private String key; operacija privatnog niza; vrijednost privatnog objekta; }

The Kriterij pretrage provedba drži naše Upit parametri:

  • ključ: koristi se za držanje imena polja - na primjer: ime, dob, ... itd.
  • operacija: koristi se za zadržavanje operacije - na primjer: Jednakost, manja od, ... itd.
  • vrijednost: koristi se za zadržavanje vrijednosti polja - na primjer: john, 25, ... itd.

4. Testirajte upite za pretraživanje

Sada - testirajmo naš mehanizam pretraživanja kako bismo bili sigurni da zadržava vodu.

Prvo - inicijalizirajmo našu bazu podataka za testiranje dodavanjem dva korisnika - kao u sljedećem primjeru:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfig.class}) @Transactional @TransactionConfiguration javna klasa JPACriteriaQueryTest {@Autowired private IUserDAO userApi; privatni korisnik userJohn; privatni korisnik userTom; @Prije javne void init () {userJohn = novi korisnik (); userJohn.setFirstName ("Ivan"); userJohn.setLastName ("Doe"); userJohn.setEmail ("[e-pošta zaštićena]"); userJohn.setAge (22); userApi.save (userJohn); userTom = novi korisnik (); userTom.setFirstName ("Tom"); userTom.setLastName ("Doe"); userTom.setEmail ("[e-pošta zaštićena]"); userTom.setAge (26); userApi.save (userTom); }}

Ajmo sada Korisnik s određenim ime i prezime - kao u sljedećem primjeru:

@Test javna praznina givenFirstAndLastName_whenGettingListOfUsers_thenCorrect () {Params liste = novi ArrayList (); params.add (novi kriteriji pretraživanja ("firstName", ":", "John")); params.add (novi kriteriji pretraživanja ("lastName", ":", "Doe")); Rezultati popisa = userApi.searchUser (params); assertThat (userJohn, isIn (rezultati)); assertThat (userTom, ne (isIn (rezultati))); }

Dalje, uzmimo a Popis od Korisnik s istim prezime:

@Test public void givenLast_whenGettingListOfUsers_thenCorrect () {Params liste = novi ArrayList (); params.add (novi kriteriji pretraživanja ("lastName", ":", "Doe")); Rezultati popisa = userApi.searchUser (params); assertThat (userJohn, isIn (rezultati)); assertThat (userTom, isIn (rezultati)); }

Dalje, idemo na korisnike dobveći ili jednaki 25:

@Test javna praznina givenLastAndAge_whenGettingListOfUsers_thenCorrect () {Params liste = novi ArrayList (); params.add (novi kriteriji pretraživanja ("lastName", ":", "Doe")); params.add (novi kriteriji pretraživanja ("dob", ">", "25")); Rezultati popisa = userApi.searchUser (params); assertThat (userTom, isIn (rezultati)); assertThat (userJohn, ne (isIn (rezultati))); }

Dalje, potražimo korisnike koji to zapravo ne postoje:

@Test javna praznina givenWrongFirstAndLast_whenGettingListOfUsers_thenCorrect () {Params liste = novi ArrayList (); params.add (novi kriteriji pretraživanja ("firstName", ":", "Adam")); params.add (novi kriteriji pretraživanja ("lastName", ":", "Fox")); Rezultati popisa = userApi.searchUser (params); assertThat (userJohn, ne (isIn (rezultati))); assertThat (userTom, ne (isIn (rezultati))); }

Napokon, potražimo samo dane korisnike djelomičnoime:

@Test javna praznina givenPartialFirst_whenGettingListOfUsers_thenCorrect () {Params liste = novi ArrayList (); params.add (novi kriteriji pretraživanja ("firstName", ":", "jo")); Rezultati popisa = userApi.searchUser (params); assertThat (userJohn, isIn (rezultati)); assertThat (userTom, ne (isIn (rezultati))); }

6. The UserController

Napokon, hajde da sada povežemo podršku za upornost za ovo fleksibilno pretraživanje s našim REST API-jem.

Postavit ćemo jednostavno UserController - s findAll ()koristiti "traži”Da prođe u cijelom izrazu pretraživanja / filtra:

@Controller javna klasa UserController {@Autowired private IUserDao api; @RequestMapping (method = RequestMethod.GET, value = "/ users") @ResponseBody javni popis findAll (@RequestParam (value = "search", required = false) String search) {Params para = novi ArrayList (); if (search! = null) {Pattern pattern = Pattern.compile ("(\ w +?) (: |) (\ w +?),"); Podudaranje podudaranja = pattern.matcher (pretraživanje + ","); while (matcher.find ()) {params.add (novi kriteriji pretraživanja (matcher.group (1), matcher.group (2), matcher.group (3))); }} return api.searchUser (params); }}

Primijetite kako jednostavno izrađujemo objekte kriterija pretraživanja iz izraza za pretraživanje.

Sad smo na mjestu gdje se možemo početi igrati s API-jem i provjeriti radi li sve ispravno:

// localhost: 8080 / users? search = lastName: doe, dob> 25

I evo odgovora:

[{"id": 2, "firstName": "tom", "lastName": "doe", "email": "[email protected]", "age": 26}]

7. Zaključak

Ova jednostavna, ali moćna implementacija omogućuje prilično pametno filtriranje na REST API-ju. Da - još uvijek je grubo oko rubova i može se poboljšati (a poboljšat će se u sljedećem članku) - ali solidna je polazna točka za implementaciju ove vrste filtriranja na vaše API-je.

The puna provedba ovog članka može se naći u projektu GitHub - ovo je projekt zasnovan na Mavenu, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.

Sljedeći » REST jezik upita s proljetnim podacima JPA specifikacije REST dno

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ