REST Query Language med vår- og JPA-kriterier

REST Topp

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET Denne artikkelen er en del av en serie: • REST Query Language with Spring and JPA Criteria (nåværende artikkel) • REST Query Language with Spring Data JPA Specifications

• REST Query Language med vårdata JPA og Querydsl

• REST-spørrespråk - Avanserte søkeoperasjoner

• REST Query Language - Implementering ELLER drift

• REST Query Language med RSQL

• REST Query Language med Querydsl Web Support

1. Oversikt

I denne første artikkelen i denne nye serien vil vi utforske et enkelt spørrespråk for et REST API. Vi vil bruke Spring til REST API og JPA 2-kriterier for utholdenhetsaspekter.

Hvorfor et spørrespråk? Fordi det ikke er nok å søke etter / filtrere ressursene dine etter veldig enkle felt - for ethvert komplekst API. Et spørrespråk er mer fleksibelt, og lar deg filtrere ned til nøyaktig de ressursene du trenger.

2. Bruker Enhet

Først - la oss legge frem den enkle enheten som vi skal bruke til filter- / søk-API-et vårt - en grunnleggende Bruker:

@Entity offentlig klasse bruker {@Id @GeneratedValue (strategi = GenerationType.AUTO) privat Lang id; privat streng fornavn; privat streng etternavn; privat streng e-post; privat alder; }

3. Filtrer ved hjelp CriteriaBuilder

Nå - la oss komme inn i kjøttet av problemet - spørringen i utholdenhetslaget.

Å bygge en spørreabstraksjon er et spørsmål om balanse. Vi trenger en god mengde fleksibilitet på den ene siden, og vi må holde kompleksiteten håndterbar på den andre. Høyt nivå, funksjonaliteten er enkel - du gir noen begrensninger, og du får tilbake noen resultater.

La oss se hvordan det fungerer:

@Repository public class UserDAO implementerer IUserDAO {@PersistenceContext private EntityManager entityManager; @Override public List searchUser (List params) {CriteriaBuilder builder = entityManager.getCriteriaBuilder (); CriteriaQuery-spørring = builder.createQuery (User.class); Root r = query.from (User.class); Predikatpredikat = builder.conjunction (); UserSearchQueryCriteriaConsumer searchConsumer = ny UserSearchQueryCriteriaConsumer (predikat, byggherre, r); params.stream (). forEach (searchConsumer); predikat = searchConsumer.getPredicate (); query.where (predikat); Liste resultat = entityManager.createQuery (spørring) .getResultList (); returresultat; } @ Overstyr offentlig tomrom lagre (brukerenhet) {entityManager.persist (enhet); }}

La oss ta en titt på UserSearchQueryCriteriaConsumer klasse:

offentlig klasse UserSearchQueryCriteriaConsumer implementerer Consumer {private Predicate predicate; privat CriteriaBuilder byggherre; private Root r; @Override public void accept (SearchCriteria param) {if (param.getOperation (). EqualsIgnoreCase (">")) {predicate = builder.and (predicate, builder .greaterThanOrEqualTo (r.get (param.getKey ()), param .getValue (). toString ())); } ellers hvis (param.getOperation (). equalsIgnoreCase ("<")) {predicate = builder.and (predicate, builder.lessThanOrEqualTo (r.get (param.getKey ()), param.getValue (). toString () )); } annet hvis (param.getOperation (). equalsIgnoreCase (":")) {if (r.get (param.getKey ()). getJavaType () == String.class) {predicate = builder.and (predicate, builder .like (r.get (param.getKey ()), "%" + param.getValue () + "%")); } annet {predicate = builder.and (predicate, builder.equal (r.get (param.getKey ()), param.getValue ())); }}} // standardkonstruktør, getter, setter}

Som du kan se, er søk Bruker API tar en liste over veldig enkle begrensninger, komponerer et spørsmål basert på disse begrensningene, søker og returnerer resultatene.

Begrensningsklassen er også ganske enkel:

offentlig klasse SearchCriteria {privat strengnøkkel; privat streng operasjon; privat Objektverdi; }

De Søkekriterier implementering holder vår Spørsmål parametere:

  • nøkkel: brukes til å holde feltnavn - for eksempel: fornavn, alder, … etc.
  • operasjon: brukes til å holde operasjonen - for eksempel: Likhet, mindre enn, ... etc.
  • verdi: brukes til å holde feltverdien - for eksempel: john, 25, ... etc.

4. Test søkene

Nå - la oss teste søkemekanismen vår for å sikre at den holder vann.

Først - la oss initialisere databasen vår for testing ved å legge til to brukere - som i følgende eksempel:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfig.class}) @ Transactional @TransactionConfiguration public class JPACriteriaQueryTest {@Autowired private IUserDAO userApi; privat bruker brukerJohn; privat bruker userTom; @Før offentlig ugyldig init () {userJohn = ny bruker (); userJohn.setFirstName ("John"); userJohn.setLastName ("Doe"); userJohn.setEmail ("[email protected]"); userJohn.setAge (22); userApi.save (userJohn); userTom = ny bruker (); userTom.setFirstName ("Tom"); userTom.setLastName ("Doe"); userTom.setEmail ("[email protected]"); userTom.setAge (26); userApi.save (userTom); }}

La oss få en Bruker med spesifikk fornavn og etternavn - som i følgende eksempel:

@Test offentlig ugyldighet givenFirstAndLastName_whenGettingListOfUsers_thenCorrect () {List params = new ArrayList (); params.add (nye SearchCriteria ("fornavn", ":", "John")); params.add (ny SearchCriteria ("etternavn", ":", "Doe")); Listeresultater = userApi.searchUser (params); assertThat (userJohn, isIn (resultater)); assertThat (userTom, not (isIn (results))); }

Neste, la oss få en Liste av Bruker med det samme etternavn:

@Test offentlig ugyldig givenLast_whenGettingListOfUsers_thenCorrect () {List params = new ArrayList (); params.add (ny SearchCriteria ("etternavn", ":", "Doe")); Listeresultater = userApi.searchUser (params); assertThat (userJohn, isIn (resultater)); assertThat (userTom, isIn (resultater)); }

Deretter, la oss få brukere med alderstørre enn eller lik 25:

@Test offentlig ugyldig givenLastAndAge_whenGettingListOfUsers_thenCorrect () {List params = new ArrayList (); params.add (ny SearchCriteria ("etternavn", ":", "Doe")); params.add (nye SearchCriteria ("alder", ">", "25")); Listeresultater = userApi.searchUser (params); assertThat (userTom, isIn (resultater)); assertThat (userJohn, not (isIn (results))); }

Deretter, la oss søke etter brukere som eksisterer faktisk ikke:

@Test public void givenWrongFirstAndLast_whenGettingListOfUsers_thenCorrect () {List params = new ArrayList (); params.add (ny SearchCriteria ("fornavn", ":", "Adam")); params.add (ny SearchCriteria ("etternavn", ":", "Fox")); Listeresultater = userApi.searchUser (params); assertThat (userJohn, not (isIn (results))); assertThat (userTom, not (isIn (results))); }

Til slutt, la oss søke etter brukere bare gitt delvisfornavn:

@Test offentlig ugyldig givenPartialFirst_whenGettingListOfUsers_thenCorrect () {List params = new ArrayList (); params.add (ny SearchCriteria ("fornavn", ":", "jo")); Listeresultater = userApi.searchUser (params); assertThat (userJohn, isIn (resultater)); assertThat (userTom, not (isIn (results))); }

6. Den UserController

Til slutt, la oss nå koble inn utholdenhetsstøtten for dette fleksible søket til REST API.

Vi skal sette opp en enkel UserController - med en findAll ()bruker "Søk”For å sende inn hele søke- / filteruttrykket:

@Controller offentlig klasse UserController {@Autowired private IUserDao api; @RequestMapping (method = RequestMethod.GET, value = "/ users") @ResponseBody public List findAll (@RequestParam (value = "search", required = false) String search) {List params = new ArrayList (); hvis (søk! = null) {Mønstermønster = Mønster.kompilere ("(\ w +?) (: |) (\ w +?),"); Matcher matcher = mønster.matcher (søk + ","); mens (matcher.find ()) {params.add (ny SearchCriteria (matcher.group (1), matcher.group (2), matcher.group (3))); }} returner api.searchUser (params); }}

Legg merke til hvordan vi bare lager våre søkekriterieobjekter ut av søkeuttrykket.

Vi er nå på det punktet hvor vi kan begynne å spille med API og sørge for at alt fungerer som det skal:

// localhost: 8080 / brukere? search = etternavn: doe, alder> 25

Og her er svaret:

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

7. Konklusjon

Denne enkle, men kraftige implementeringen muliggjør ganske mye smart filtrering på et REST API. Ja - det er fortsatt grovt rundt kantene og kan forbedres (og vil forbedres i neste artikkel) - men det er et solid utgangspunkt for å implementere denne typen filtreringsfunksjonalitet på API-ene dine.

De full gjennomføring av denne artikkelen finnes i GitHub-prosjektet - dette er et Maven-basert prosjekt, så det skal være enkelt å importere og kjøre som det er.

Neste » REST-spørrespråk med vårdata JPA-spesifikasjoner REST-bunn

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET

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