REST jezik upita s Spring Data JPA i Querydsl

Ovaj je članak dio serije: • REST jezik upita s proljetnim i JPA kriterijima

• REST jezik upita s Spring Data JPA specifikacijama

• REST jezik upita s Spring podacima JPA i Querydsl (trenutni članak) • REST jezik upita - operacije naprednog pretraživanja

• REST upitni jezik - implementacija ILI operacija

• REST jezik upita s RSQL-om

• OSTALI jezik upita s web podrškom Querydsl

1. Pregled

U ovom uputstvu razmatramo izgradnju jezika upita za REST API koristeći Spring Data JPA i Querydsl.

U prva dva članka ove serije izgradili smo istu funkciju pretraživanja / filtriranja koristeći JPA kriterije i Spring Data JPA specifikacije.

Dakle - 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 vam filtriranje do točno potrebnih resursa.

2. Konfiguracija Querydsl

Prvo - pogledajmo kako konfigurirati naš projekt tako da koristi Querydsl.

Moramo dodati sljedeće ovisnosti pom.xml:

 com.querydsl querydsl-apt 4.2.2 com.querydsl querydsl-jpa 4.2.2 

Također moramo konfigurirati APT - Alat za obradu bilješki - dodatak kako slijedi:

 com.mysema.maven apt-maven-plugin 1.1.3 proces target / generated-sources / java com.mysema.query.apt.jpa.JPAAnnotationProcessor 

Ovo će generirati Q-tipove za naše entitete.

3. The MyUser Entitet

Dalje - pogledajmo "MyUser”Entitet koji ćemo koristiti u našem API-ju za pretraživanje:

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

4. Prilagođeno Predikat Wi PathBuilder

Sada - izradimo običaj Predikat na temelju nekih proizvoljnih ograničenja.

Koristimo PathBuilder ovdje umjesto automatski generiranih Q-tipova, jer moramo dinamički kreirati staze za apstraktniju upotrebu:

javna klasa MyUserPredicate {kriteriji privatnog kriterija pretraživanja; javni BooleanExpression getPredicate () {PathBuilder entityPath = novi PathBuilder (MyUser.class, "user"); if (isNumeric (kriterij.getValue (). toString ())) {NumberPath path = entityPath.getNumber (kriterij.getKey (), Integer.class); int vrijednost = Integer.parseInt (kriteriji.getValue (). toString ()); switch (kriterij.getOperation ()) {case ":": povratna putanja.eq (vrijednost); slučaj ">": return path.goe (vrijednost); case "<": return path.loe (vrijednost); }} else {StringPath put = entityPath.getString (kriteriji.getKey ()); if (kriterij.getOperation (). equalsIgnoreCase (":")) {return path.containsIgnoreCase (kriterij.getValue (). toString ()); }} return null; }}

Obratite pažnju na izvedbu predikata generičko bavljenje više vrsta operacija. To je zato što je jezik upita po definiciji otvoreni jezik u kojem možete filtrirati bilo koje polje, koristeći bilo koju podržanu operaciju.

Da bismo predstavili takvu vrstu kriterija otvorenog filtriranja, koristimo jednostavnu, ali prilično fleksibilnu implementaciju - Kriterij pretrage:

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

The Kriterij pretrage sadrži detalje koji su nam potrebni da predstavljaju ograničenje:

  • ključ: naziv polja - na primjer: ime, dob, ... itd
  • operacija: operacija - na primjer: Jednakost, manja od, ... itd
  • vrijednost: vrijednost polja - na primjer: john, 25, ... itd

5. MyUserRepository

Sada - pogledajmo naše MyUserRepository.

Trebamo svoje MyUserRepository proširiti QuerydslPredicateExecutor kako bismo mogli koristiti Predikati kasnije za filtriranje rezultata pretraživanja:

javno sučelje MyUserRepository proširuje JpaRepository, QuerydslPredicateExecutor, QuerydslBinderCustomizer {@Override zadana javna void prilagodba (QuerydslBindings vezovi, QMyUser korijen) {bindings.bind (String.class) .first ((SingleValuexpression) String; vezovi.isključujući (root.email); }}

Imajte na umu da ovdje koristimo generirani Q-tip za MyUser entitet, koji će biti imenovan QMyUser.

6. Kombinirajte Predikati

Dalje - pogledajmo kombiniranje predikata kako bismo koristili više ograničenja u filtriranju rezultata.

U sljedećem primjeru - radimo s graditeljem - MyUserPredicatesBuilder - kombinirati Predikati:

javna klasa MyUserPredicatesBuilder {parametari privatnog popisa; javni MyUserPredicatesBuilder () {params = novi ArrayList (); } javni MyUserPredicatesBuilder sa (ključ niza, operacija niza, vrijednost objekta) {params.add (novi kriteriji pretraživanja (ključ, operacija, vrijednost)); vrati ovo; } javni BooleanExpression build () {if (params.size () == 0) {return null; } Navesti predikate = params.stream (). Karta (param -> {MyUserPredicate predikat = novi MyUserPredicate (param); vratiti predikat.getPredicate ();}). Filter (Objects :: nonNull) .collect (Collectors.toList () ); Rezultat BooleanExpression = Expressions.asBoolean (true) .isTrue (); za (predikat BooleanExpression: predikati) {rezultat = rezultat.i (predikat); } vratiti rezultat; }}

7. Testirajte upite za pretraživanje

Dalje - testirajmo naš API za pretraživanje.

Počet ćemo inicijalizacijom baze podataka s nekoliko korisnika - kako bi ovi bili spremni i dostupni za testiranje:

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

Dalje, pogledajmo kako pronaći korisnike pomoću dato prezime:

@Test javna praznina givenLast_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder (). With ("lastName", ":", "Doe"); Rezultati koji se mogu provjeriti = repo.findAll (builder.build ()); assertThat (rezultati, sadržiInAnyOrder (userJohn, userTom)); }

Sada, da vidimo kako pronaći korisnika s danim i ime i prezime:

@Test javna praznina givenFirstAndLastName_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder () .with ("firstName", ":", "John"). With ("lastName", ":", "Doe" Rezultati koji se mogu provjeriti = repo.findAll (builder.build ()); assertThat (rezultat, sadrži (userJohn)); assertThat (rezultati, ne (sadrži (userTom))); }

Dalje, pogledajmo kako pronaći korisnika s danim i prezime i minimalna dob

@Test javna praznina givenLastAndAge_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder () .with ("lastName", ":", "Doe"). With ("age", ">", "25"); Rezultati koji se mogu provjeriti = repo.findAll (builder.build ()); assertThat (rezultat, sadrži (userTom)); assertThat (rezultati, ne (sadrži (userJohn))); }

Sada, da vidimo kako tražiti MyUser da zapravo ne postoji:

@Test javna praznina givenWrongFirstAndLast_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder () .with ("firstName", ":", "Adam"). With ("lastName", ":", "Fox Rezultati koji se mogu provjeriti = repo.findAll (builder.build ()); assertThat (results, emptyIterable ()); }

Napokon - da vidimo kako pronaći MyUser dobio samo dio imena - kao u sljedećem primjeru:

@Test javna praznina givenPartialFirst_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder (). With ("firstName", ":", "jo"); Rezultati koji se mogu provjeriti = repo.findAll (builder.build ()); assertThat (rezultat, sadrži (userJohn)); assertThat (rezultati, ne (sadrži (userTom))); }

8. UserController

Na kraju, spojimo sve i izgradimo REST API.

Definiramo a UserController koja definira jednostavnu metodu findAll () s "traži“Parametar koji se prosljeđuje u niz upita:

@Controller javna klasa UserController {@Autowired private MyUserRepository myUserRepository; @RequestMapping (method = RequestMethod.GET, value = "/ myusers") @ResponseBody javno iterable pretraživanje (@RequestParam (value = "search") String search) {MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder (); if (search! = null) {Pattern pattern = Pattern.compile ("(\ w +?) (: |) (\ w +?),"); Podudaranje podudaranja = pattern.matcher (pretraživanje + ","); while (matcher.find ()) {builder.with (matcher.group (1), matcher.group (2), matcher.group (3)); }} BooleanExpression exp = builder.build (); vrati myUserRepository.findAll (exp); }}

Evo primjera brzog testnog URL-a:

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

I odgovor:

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

9. Zaključak

Ovaj treći članak obuhvaća prvi koraci izgradnje jezika upita za REST API, koristeći se knjižnicom Querydsl.

Implementacija je naravno rana, ali lako se može razviti kao podrška dodatnim operacijama.

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 upitni jezik - Napredno pretraživanje « Prethodni REST jezik upita s Spring Data JPA specifikacijama

$config[zx-auto] not found$config[zx-overlay] not found