REST Query Language RSQL-lel
Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:
>> ELLENŐRIZZE A FOLYAMATOT Kitartás felsőMost jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:
>> ELLENŐRIZZE A FOLYAMATOT Ez a cikk egy sorozat része: • REST Query Language with Spring and JPA Criteria• REST lekérdezési nyelv a Spring Data JPA specifikációkkal
• REST Query Language a Spring Data JPA és a Querydsl segítségével
• REST Query Language - Speciális keresési műveletek
• REST Query Language - VAGY művelet végrehajtása
• REST Query Language RSQL-lel (aktuális cikk) • REST Query Language Querydsl webes támogatással
1. Áttekintés
A sorozat ezen ötödik cikkében a REST API Query nyelv kiépítését mutatjuk be klassz könyvtár - rsql-parser.
Az RSQL a Feed Item Query Language (FIQL) szuperkészlete - tiszta és egyszerű szűrőszintaxis a hírcsatornákhoz; így természetesen illeszkedik a REST API-ba. Először adjunk hozzá egy maven függőséget a könyvtárhoz: És még meghatározza a fő entitást együtt fogunk dolgozni a példákban - Felhasználó: Az RSQL-kifejezések belső ábrázolása csomópontok formájában történik, és a látogatói mintát használják a bemenet elemzésére. Ezt szem előtt tartva fogjuk megvalósítani a RSQLVisitor felületet, és létrehozhatunk saját látogatói megvalósítást - CustomRsqlVisitor: Most foglalkoznunk kell a kitartással, és ezekből a csomópontokból össze kell állítanunk a lekérdezést. A korábban használt Spring Data JPA specifikációkat fogjuk használni - és a Leírás építője ezekből a meglátogatott csomópontokból állítsuk össze a specifikációt: Vegye figyelembe, hogyan: Például egy „név == john" - nekünk van: A lekérdezés összeállításakor a Leírás: Figyelje meg, hogy a specifikáció miként használja a generikus gyógyszereket, és nem kapcsolódik-e egyetlen entitáshoz (például a felhasználóhoz). Következő - itt a miénk enum “RsqlSearchOperation“ amely az alapértelmezett rsql-parser operátorokat tartalmazza: Most kezdjük el tesztelni új és rugalmas működésünket néhány valós forgatókönyv segítségével: Először - inicializáljuk az adatokat: Most teszteljük a különböző műveleteket: A következő példában - a felhasználók alapján keresünk felhasználókat első és vezetéknév: Ezután keressük meg azokat a felhasználókat, akik a keresztnév nem „john”: Következő - a felhasználókat a következővel keressük meg: kor nagyobb, mint "25”: Következő - megkeressük a felhasználókat a sajátjukkal keresztnév kezdve:jo”: Következő - megkeressük a felhasználókat keresztnév az „JánosVagy „Jack“: Végül - kössük össze az egészet a vezérlővel: Íme egy példa URL: És a válasz: Ez az oktatóanyag bemutatja, hogyan lehet egy REST API számára létrehozni egy lekérdezési / keresési nyelvet anélkül, hogy újra ki kellene találni a szintaxist, és ehelyett a FIQL / RSQL-t kell használni. A teljes végrehajtása cikkünk megtalálható a GitHub projektben - ez egy Maven-alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.2. Előkészületek
cz.jirutka.rsql rsql-parser 2.1.0
@Entity public class User {@Id @GeneratedValue (strategy = GenerationType.AUTO) private Long id; privát karakterlánc keresztnév; privát karakterlánc vezetéknév; privát karakterlánc e-mail; privát int kor; }
3. A kérelem elemzése
public class CustomRsqlVisitor valósítja meg az RSQLVisitor programot
public class GenericRsqlSpecBuilder {public Specification createSpecification (Node node) {if (a LogicalNode csomópont példánya) {return createSpecification ((LogicalNode) csomópont); } if (a ComparisonNode csomópont példánya) {return createSpecification ((ComparisonNode) csomópont); } return null; } public Specifikáció createSpecification (LogicalNode logikai csomópont) {List specs = logikaiNode.getChildren () .stream () .map (csomópont -> createSpecification (csomópont)) .filter (Objects :: nonNull) .collect (Collectors.toList ()); Specifikáció eredménye = specs.get (0); if (logikaiNode.getOperator () == LogicalOperator.AND) {for (int i = 1; i <specs.size (); i ++) {eredmény = Specification.where (result) .and (specs.get (i)) ; }} else if (logikaiNode.getOperator () == LogicalOperator.OR) {for (int i = 1; i <specs.size (); i ++) {eredmény = Specification.where (eredmény) .vagy (specs.get ( én)); }} visszatérési eredmény; } public Specifikáció createSpecification (ComparisonNode CompareNode) {Specifikáció eredménye = Specifikáció.where (új GenericRsqlSpecification (összehasonlításNode.getSelector (), CompareNode.getOperator (), CompareNode.getArguments ())); visszatérési eredmény; }}
4. Készítse el az Egyéni lehetőséget Leírás
public class A GenericRsqlSpecification végrehajtja a Specifikációt {private String property; magán ComparisonOperator operátor; private List argumentumok; @Override public Predicate toPredicate (Root root, CriteriaQuery query, CriteriaBuilder builder) {List args = castArguments (root); Objektum argumentum = args.get (0); kapcsoló (RsqlSearchOperation.getSimpleOperator (operátor)) {eset EQUAL: {if (argumentum a String példánya) {return builder.like (root.get (tulajdonság), argument.toString (). csere ('*', '%')) ; } else if (argumentum == null) {return builder.isNull (root.get (tulajdonság)); } else {return builder.equal (root.get (tulajdonság), argumentum); }} eset NOT_EQUAL: {if (a String argumentum példánya) {return builder.notLike (root. get (tulajdonság), argument.toString (). csere ('*', '%')); } else if (argumentum == null) {return builder.isNotNull (root.get (tulajdonság)); } else {return builder.notEqual (root.get (tulajdonság), argumentum); }} eset GREATER_THAN: {return builder.greaterThan (root. get (tulajdonság), argumentum.toString ()); } eset GREATER_THAN_OR_EQUAL: {return builder.greaterThanOrEqualTo (root. get (tulajdonság), argument.toString ()); } case LESS_THAN: {return builder.lessThan (root. get (tulajdonság), argumentum.toString ()); } eset LESS_THAN_OR_EQUAL: {return builder.lessThanOrEqualTo (root. get (tulajdonság), argument.toString ()); } case IN: return root.get (tulajdonság) .in (érvel); eset NOT_IN: return builder.not (root.get (tulajdonság) .in (args)); } return null; } privát List castArguments (végső gyökérgyökér) {Osztálytípus = root.get (tulajdonság) .getJavaType (); List args = argumentumok.stream (). Map (arg -> {if (type.equals (Integer.class)) {return Integer.parseInt (arg);} else if (type.equals (Long.class)) {return Long.parseLong (arg);} else {return arg;}}). Gyűjt (Collectors.toList ()); return args; } // szabványos konstruktor, getter, szetter}
nyilvános enum RsqlSearchOperation {EQUAL (RSQLOperators.EQUAL), NOT_EQUAL (RSQLOperators.NOT_EQUAL), GREATER_THAN (RSQLOperators.GREATER_THAN), GREATER_THAN_OR_EQUAL (RSQLOperators.GREATER_THAN_OR_EQUAL), LESS_THAN (RSQLOperators.LESS_THAN), LESS_THAN_OR_EQUAL (RSQLOperators.LESS_THAN_OR_EQUAL), IN (RSQLOperators. IN), NOT_IN (RSQLOperators.NOT_IN); magán ComparisonOperator operátor; privát RsqlSearchOperation (ComparisonOperator operátor) {this.operator = operátor; } public static RsqlSearchOperation getSimpleOperator (ComparisonOperator operator) {for (RsqlSearchOperation művelet: értékek ()) {if (művelet.getOperator () == operátor) {visszatérési művelet; }} return null; }}
5. Tesztelje a keresési lekérdezéseket
@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (class = {PersistenceConfig.class}) @Transactional @TransactionConfiguration public class RsqlTest {@Autowired private UserRepository repository; private User userJohn; private User userTom; @A nyilvános void előtt init () {userJohn = new User (); userJohn.setFirstName ("john"); userJohn.setLastName ("őz"); userJohn.setEmail ("[e-mail védett]"); userJohn.setAge (22); repository.save (userJohn); userTom = új felhasználó (); userTom.setFirstName ("tom"); userTom.setLastName ("őz"); userTom.setEmail ("[e-mail védett]"); userTom.setAge (26); repository.save (userTom); }}
5.1. Tesztelje az egyenlőséget
@Test public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect () {Csomópont rootNode = új RSQLParser (). Parse ("keresztnév == john; vezetéknév == doe"); Specifikáció spec = rootNode.accept (új CustomRsqlVisitor ()); Eredmények felsorolása = repository.findAll (spec); assertThat (userJohn, isIn (eredmények)); assertThat (userTom, nem (isIn (eredmények))); }
5.2. Test Negation
@Test public void givenFirstNameInverse_whenGettingListOfUsers_thenCorrect () {Csomópont rootNode = új RSQLParser (). Parse ("keresztnév! = John"); Specifikáció spec = rootNode.accept (új CustomRsqlVisitor ()); Eredmények felsorolása = repository.findAll (spec); assertThat (userTom, isIn (eredmények)); assertThat (userJohn, nem (isIn (eredmények))); }
5.3. Tesztelje nagyobb, mint
@Test public void givenMinAge_whenGettingListOfUsers_thenCorrect () {Csomópont rootNode = új RSQLParser (). Elemzés ("életkor> 25"); Specifikáció spec = rootNode.accept (új CustomRsqlVisitor ()); Eredmények felsorolása = repository.findAll (spec); assertThat (userTom, isIn (eredmények)); assertThat (userJohn, nem (isIn (eredmények))); }
5.4. Tetszik Like
@Test public void givenFirstNamePrefix_whenGettingListOfUsers_thenCorrect () {Csomópont rootNode = új RSQLParser (). Parse ("keresztnév == jo *"); Specifikáció spec = rootNode.accept (új CustomRsqlVisitor ()); Eredmények felsorolása = repository.findAll (spec); assertThat (userJohn, isIn (eredmények)); assertThat (userTom, nem (isIn (eredmények))); }
5.5. Teszt BAN BEN
@Test public void givenListOfFirstName_whenGettingListOfUsers_thenCorrect () {Node rootNode = new RSQLParser (). Parse ("firstName = in = (john, jack)"); Specifikáció spec = rootNode.accept (új CustomRsqlVisitor ()); Eredmények felsorolása = repository.findAll (spec); assertThat (userJohn, isIn (eredmények)); assertThat (userTom, nem (isIn (eredmények))); }
6. UserController
@RequestMapping (method = RequestMethod.GET, value = "/ users") @ResponseBody public List findAllByRsql (@RequestParam (value = "search") String search) {Node rootNode = new RSQLParser (). Elemzés (keresés); Specifikáció spec = rootNode.accept (új CustomRsqlVisitor ()); return dao.findAll (spec); }
// localhost: 8080 / users? search = keresztnév == jo *; életkor <25
[{"id": 1, "keresztnév": "john", "vezetékNév": "őz", "e-mail": "[e-mail védett]", "kor": 24}]
7. Következtetés
Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:
>> ELLENŐRIZZE A FOLYAMATOT Perzisztencia alsó Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:
>> ELLENŐRIZZE A FOLYAMATOT