REST dotazovací jazyk s RSQL
Práve som oznámil nové Naučte sa jar kurz zameraný na základy jari 5 a Spring Boot 2:
>> SKONTROLUJTE KURZ Perzistencia horePráve som oznámil nové Naučte sa jar kurz zameraný na základy jari 5 a Spring Boot 2:
>> SKONTROLUJTE KURZ Tento článok je súčasťou série: • Dotazovací jazyk REST s kritériami Spring a JPA• Dotazovací jazyk REST so špecifikáciami JPA Spring Data
• REST dotazovací jazyk s Spring Data JPA a Querydsl
• REST Query Language - Pokročilé vyhľadávacie operácie
• REST Query Language - implementácia ALEBO prevádzka
• Dotazovací jazyk REST s RSQL (aktuálny článok) • Dotazovací jazyk REST s webovou podporou Querydsl
1. Prehľad
V tomto piatom článku série ilustrujeme zostavenie dotazovacieho jazyka REST API pomocou skvelá knižnica - rsql-parser.
RSQL je nadstavba informačného kanála dotazu na položku (FIQL) - čistá a jednoduchá syntax filtra pre kanály; takže celkom prirodzene zapadá do REST API. Najprv pridáme do knižnice závislosť maven: A tiež definovať hlavnú entitu budeme pracovať s príkladmi - Používateľ: Spôsob, akým sú výrazy RSQL interne reprezentované, je vo forme uzlov a vzor návštevníka sa používa na analýzu vstupu. Z tohto dôvodu ideme implementovať RSQLVisitor rozhranie a vytvoriť si vlastnú implementáciu pre návštevníkov - CustomRsqlVisitor: Teraz sa musíme vyrovnať s perzistenciou a zostaviť náš dotaz z každého z týchto uzlov. Budeme používať špecifikácie Spring Data JPA, ktoré sme používali predtým - a budeme implementovať a Špecifikácia staviteľ z každého z týchto uzlov, ktoré navštívime, zostavte Špecifikácie: Všimnite si, ako: Napríklad pre dopyt „meno == john" - máme: Pri konštrukcii dotazu sme použili a Špecifikácia: Všimnite si, ako špecifikácia používa všeobecné informácie a nie je viazaná na žiadny konkrétny subjekt (napríklad Používateľa). Ďalej - tu je náš enum “RsqlSearchOperation“ ktorý obsahuje predvolené operátory rsql-parser: Začnime teraz testovať naše nové a flexibilné operácie prostredníctvom niekoľkých scenárov z reálneho sveta: Najprv - inicializujme údaje: Teraz otestujme rôzne operácie: V nasledujúcom príklade - budeme vyhľadávať používateľov podľa ich najprv a priezvisko: Ďalej poďme hľadať používateľov, ktorí sú podľa nich krstné meno nie „john“: Ďalej - budeme hľadať používateľov s Vek väčší než "25”: Ďalej - budeme hľadať používateľov s ich krstné meno začínajúce „jo”: Ďalej - vyhľadáme ich používateľov krstné meno je "john“Alebo„zdvihák“: Nakoniec - všetko spojíme s ovládačom: Tu je ukážka adresy URL: A odpoveď: Tento výukový program ilustroval, ako vytvoriť dotazovací / vyhľadávací jazyk pre rozhranie REST API bez toho, aby ste museli znova vymýšľať syntax a namiesto toho používať FIQL / RSQL. The úplná implementácia tohto článku nájdete v projekte GitHub - jedná sa o projekt založený na Maven, takže by malo byť ľahké ho importovať a spustiť tak, ako je.2. Prípravy
cz.jirutka.rsql rsql-parser 2.1.0
@Entity verejná trieda Používateľ {@Id @GeneratedValue (strategy = GenerationType.AUTO) private Long id; private String meno; private String priezvisko; súkromný reťazcový e-mail; súkromný int vek; }
3. Analyzujte žiadosť
verejná trieda CustomRsqlVisitor implementuje RSQLVisitor
verejná trieda GenericRsqlSpecBuilder {verejná špecifikácia createSpecification (uzol uzla) {if (uzol instanceof LogicalNode) {návrat createSpecification ((LogicalNode) uzol); } if (node instanceof ComparisonNode) {return createSpecification ((ComparisonNode) node); } return null; } verejná špecifikácia createSpecification (LogicalNode logicalNode) {List specs = logicalNode.getChildren () .stream () .map (node -> createSpecification (node)) .filter (Objects :: nonNull) .collect (Collectors.toList ()); Výsledok špecifikácie = specs.get (0); if (logicalNode.getOperator () == LogicalOperator.AND) {for (int i = 1; i <specs.size (); i ++) {result = Specification.where (result) .and (specs.get (i)) ; }} else if (logicalNode.getOperator () == LogicalOperator.OR) {for (int i = 1; i <specs.size (); i ++) {result = Specification.where (result) .or (specs.get ( i)); }} vrátiť výsledok; } public Specification createSpecification (ComparisonNode comparisonNode) {Specification result = Specification.where (new GenericRsqlSpecification (comparisonNode.getSelector (), comparisonNode.getOperator (), comparisonNode.getArguments ())); návratový výsledok; }}
4. Vytvorte vlastné Špecifikácia
verejná trieda GenericRsqlSpecification implementuje Specification {private String property; súkromný operátor ComparisonOperator; argumenty súkromného zoznamu; @Override public Predicate toPredicate (root root, CriteriaQuery query, CriteriaBuilder builder) {List args = castArguments (root); Argument objektu = args.get (0); switch (RsqlSearchOperation.getSimpleOperator (operator)) {case EQUAL: {if (argument instanceof String) {return builder.like (root.get (property), argument.toString (). replace ('*', '%')) ; } else if (argument == null) {return builder.isNull (root.get (property)); } else {návrat builder.equal (root.get (vlastnosť), argument); }} prípad NOT_EQUAL: {if (argument instanceof String) {return builder.notLike (root. get (property), argument.toString (). replace ('*', '%')); } else if (argument == null) {return builder.isNotNull (root.get (property)); } else {návrat builder.notEqual (root.get (vlastnosť), argument); }} prípad GREATER_THAN: {návrat builder.greaterThan (root. get (vlastnosť), argument.toString ()); } prípad GREATER_THAN_OR_EQUAL: {návrat builder.greaterThanOrEqualTo (root. get (vlastnosť), argument.toString ()); } prípad LESS_THAN: {návrat builder.lessThan (root. get (vlastnosť), argument.toString ()); } prípad LESS_THAN_OR_EQUAL: {návrat builder.lessThanOrEqualTo (root. get (vlastnosť), argument.toString ()); } prípad IN: návrat root.get (vlastnosť) .in (args); prípad NOT_IN: návrat builder.not (root.get (vlastnosť) .in (args)); } return null; } private List castArgumenty (konečný koreňový koreň) {Typ triedy = root.get (vlastnosť) .getJavaType (); Zoznam args = arguments.stream (). Mapa (arg -> {if (type.equals (Integer.class)) {návrat Integer.parseInt (arg);} else if (type.equals (Long.class)) {návrat Long.parseLong (arg);} else {return arg;}}). Collect (Collectors.toList ()); návrat args; } // štandardný konštruktor, getter, setter}
verejné 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), V (RSQLOperators. IN), NOT_IN (RSQLOperators.NOT_IN); súkromný operátor ComparisonOperator; private RsqlSearchOperation (ComparisonOperator operator) {this.operator = operator; } verejný statický RsqlSearchOperation getSimpleOperator (operátor ComparisonOperator) {pre (operácia RsqlSearchOperation: values ()) {if (operation.getOperator () == operátor) {návratová operácia; }} return null; }}
5. Vyskúšajte vyhľadávacie dotazy
@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfig.class}) @Transactional @TransactionConfiguration verejná trieda RsqlTest {@Autowired súkromné úložisko UserRepository; súkromný používateľ userJohn; súkromný používateľ userTom; @ Pred public void init () {userJohn = nový používateľ (); userJohn.setFirstName ("john"); userJohn.setLastName ("laň"); userJohn.setEmail ("[chránený e-mailom]"); userJohn.setAge (22); repository.save (userJohn); userTom = nový užívateľ (); userTom.setFirstName ("tom"); userTom.setLastName ("laň"); userTom.setEmail ("[chránený e-mailom]"); userTom.setAge (26); repository.save (userTom); }}
5.1. Testovať rovnosť
@Test public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect () {Node rootNode = new RSQLParser (). Parse ("firstName == john; lastName == doe"); Špecifikácia spec = rootNode.accept (nový CustomRsqlVisitor ()); Zoznam výsledkov = repository.findAll (spec); assertThat (userJohn, isIn (výsledky)); assertThat (userTom, nie (isIn (výsledky))); }
5.2. Testujte negáciu
@Test public void givenFirstNameInverse_whenGettingListOfUsers_thenCorrect () {Node rootNode = new RSQLParser (). Parse ("firstName! = John"); Špecifikácia spec = rootNode.accept (nový CustomRsqlVisitor ()); Zoznam výsledkov = repository.findAll (spec); assertThat (userTom, isIn (výsledky)); assertThat (userJohn, nie (isIn (results))); }
5.3. Vyskúšajte väčšie ako
@Test public void givenMinAge_whenGettingListOfUsers_thenCorrect () {Node rootNode = new RSQLParser (). Parse ("age> 25"); Špecifikácia spec = rootNode.accept (nový CustomRsqlVisitor ()); Zoznam výsledkov = repository.findAll (spec); assertThat (userTom, isIn (výsledky)); assertThat (userJohn, nie (isIn (results))); }
5.4. Vyskúšajte ako
@Test public void givenFirstNamePrefix_whenGettingListOfUsers_thenCorrect () {Node rootNode = new RSQLParser (). Parse ("firstName == jo *"); Špecifikácia spec = rootNode.accept (nový CustomRsqlVisitor ()); Zoznam výsledkov = repository.findAll (spec); assertThat (userJohn, isIn (výsledky)); assertThat (userTom, nie (isIn (výsledky))); }
5.5. Test IN
@Test public void givenListOfFirstName_whenGettingListOfUsers_thenCorrect () {Uzol rootNode = nový RSQLParser (). Parse ("firstName = in = (john, jack)"); Špecifikácia spec = rootNode.accept (nový CustomRsqlVisitor ()); Zoznam výsledkov = repository.findAll (spec); assertThat (userJohn, isIn (výsledky)); assertThat (userTom, nie (isIn (výsledky))); }
6. UserController
@RequestMapping (method = RequestMethod.GET, value = "/ users") @ResponseBody public List findAllByRsql (@RequestParam (value = "search") String search) {Node rootNode = new RSQLParser (). Parse (search); Špecifikácia spec = rootNode.accept (nový CustomRsqlVisitor ()); vrátiť dao.findAll (spec); }
// localhost: 8080 / users? search = firstName == jo *; vek <25
[{"id": 1, "firstName": "john", "lastName": "doe", "email": "[chránený e-mailom]," vek ": 24}]
7. Záver
Práve som oznámil nové Naučte sa jar kurz zameraný na základy jari 5 a Spring Boot 2:
>> SKONTROLUJTE KURZ Perzistencia dno Práve som oznámil nové Naučte sa jar kurz zameraný na základy jari 5 a Spring Boot 2:
>> SKONTROLUJTE KURZ