REST-forespørgselssprog med forårs- og JPA-kriterier

REST Top

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN Denne artikel er en del af en serie: • REST Query Language with Spring and JPA Criteria (nuværende artikel) • REST Query Language with Spring Data JPA Specifications

• REST forespørgselssprog med Spring Data JPA og Querydsl

• REST-forespørgselssprog - Avanceret søgning

• REST Query Language - Implementering ELLER drift

• REST Query Language med RSQL

• REST forespørgselssprog med Querydsl Web Support

1. Oversigt

I denne første artikel i denne nye serie vil vi udforske et simpelt forespørgselssprog til en REST API. Vi bruger god Spring til REST API og JPA 2-kriterier til persistensaspekterne.

Hvorfor et forespørgselssprog? Fordi - for enhver kompleks nok API - er søgning / filtrering af dine ressourcer efter meget enkle felter simpelthen ikke nok. Et forespørgselssprog er mere fleksibelt og giver dig mulighed for at filtrere ned til nøjagtigt de ressourcer, du har brug for.

2. Bruger Enhed

Først - lad os fremlægge den enkle enhed, som vi skal bruge til vores filter / søgning API - en grundlæggende Bruger:

@Entity offentlig klasse bruger {@Id @GeneratedValue (strategi = GenerationType.AUTO) privat Lang id; privat streng fornavn; privat streng efternavn; privat streng e-mail; privat int alder }

3. Filtrer ved hjælp CriteriaBuilder

Lad os nu komme ind i problemets kød - forespørgslen i persistenslaget.

Opbygning af en forespørgsel abstraktion er et spørgsmål om balance. Vi har brug for en god mængde fleksibilitet på den ene side, og vi er nødt til at holde kompleksiteten håndterbar på den anden. Højt niveau, funktionaliteten er enkel - du overlever nogle begrænsninger, og du får nogle resultater tilbage.

Lad os se, hvordan det fungerer:

@Repository public class UserDAO implementerer IUserDAO {@PersistenceContext private EntityManager entityManager; @ Override public List searchUser (Listeparametre) {CriteriaBuilder builder = entityManager.getCriteriaBuilder (); CriteriaQuery-forespørgsel = builder.createQuery (User.class); Root r = query.from (User.class); Predikatpredikat = builder.conjunction (); UserSearchQueryCriteriaConsumer searchConsumer = ny UserSearchQueryCriteriaConsumer (predikat, builder, r); params.stream (). forEach (searchConsumer); predikat = searchConsumer.getPredicate (); query.where (predikat); Listeresultat = entityManager.createQuery (forespørgsel) .getResultList (); returresultat } @ Overstyr offentlig tomrum gemme (brugerenhed) {entityManager.persist (enhed); }}

Lad os se på UserSearchQueryCriteriaConsumer klasse:

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

Som du kan se, er searchUser API tager en liste over meget enkle begrænsninger, komponerer en forespørgsel baseret på disse begrænsninger, foretager søgningen og returnerer resultaterne.

Begrænsningsklassen er også ganske enkel:

offentlig klasse SearchCriteria {privat strengnøgle; privat streng operation; privat objektværdi }

Det Søgekriterier implementering holder vores Forespørgsel parametre:

  • nøgle: bruges til at holde feltnavn - for eksempel: fornavn, alder, … etc.
  • operation: bruges til at holde operationen - for eksempel: Ligestilling, mindre end, ... osv.
  • værdi: bruges til at holde feltværdien - for eksempel: john, 25, ... osv.

4. Test søgeforespørgsler

Lad os nu teste vores søgemekanisme for at sikre, at den holder vand.

Først - lad os initialisere vores database til test ved at tilføje to brugere - som i følgende eksempel:

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

Lad os nu få en Bruger med specifikke fornavn og efternavn - som i følgende eksempel:

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

Lad os derefter få en Liste af Bruger med det samme efternavn:

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

Lad os derefter få brugere med alderstørre end eller lig med 25:

@Test offentligt ugyldigt givenLastAndAge_whenGettingListOfUsers_thenCorrect () {List params = new ArrayList (); params.add (ny SearchCriteria ("efternavn", ":", "Doe")); params.add (ny SearchCriteria ("alder", ">", "25")); Listeresultater = userApi.searchUser (params); assertThat (userTom, isIn (resultater)); assertThat (brugerJohn, ikke (isIn (resultater))); }

Lad os derefter søge efter brugere det eksisterer faktisk ikke:

@Test offentlig ugyldighed givenWrongFirstAndLast_whenGettingListOfUsers_thenCorrect () {Liste params = ny ArrayList (); params.add (ny SearchCriteria ("fornavn", ":", "Adam")); params.add (ny SearchCriteria ("efternavn", ":", "Fox")); Listeresultater = userApi.searchUser (params); assertThat (brugerJohn, ikke (isIn (resultater))); assertThat (userTom, not (isIn (results))); }

Lad os endelig kun søge efter brugere delvisfornavn:

@Test public void 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

Endelig, lad os nu koble persistensstøtten til denne fleksible søgning til vores REST API.

Vi opretter en simpel UserController - med en findAll ()bruger "Søg”For at videregive hele søgnings- / filterudtrykket:

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

Bemærk, hvordan vi simpelthen opretter vores søgekriterieobjekter ud af søgeudtrykket.

Vi er nu på det punkt, hvor vi kan begynde at spille med API'en og sørge for, at alt fungerer korrekt:

// localhost: 8080 / brugere? search = sidste navn: doe, alder> 25

Og her er dets svar:

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

7. Konklusion

Denne enkle, men kraftfulde implementering muliggør en hel del smart filtrering på en REST API. Ja - det er stadig ru rundt om kanterne og kan forbedres (og forbedres i næste artikel) - men det er et solidt udgangspunkt for at implementere denne form for filtreringsfunktionalitet på dine API'er.

Det fuld implementering af denne artikel kan findes i GitHub-projektet - dette er et Maven-baseret projekt, så det skal være let at importere og køre som det er.

Næste » REST Query Language med Spring Data JPA Specifikationer REST bund

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN

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