שפת שאילתת REST - יישום או פעולה

REST למעלה

רק הכרזתי על החדש למד אביב קורס, המתמקד ביסודות האביב 5 ומגף האביב 2:

>> בדוק את הקורס מאמר זה הוא חלק מסדרה: • שפת שאילתות REST עם קריטריוני אביב ו- JPA

• שפת שאילתת REST עם מפרט JPA של Spring Data

• שפת שאילתת REST עם JPA ו- Querydsl Data Data

• שפת שאילתת REST - פעולות חיפוש מתקדמות

• שפת שאילתת REST - יישום או פעולה (מאמר נוכחי) • שפת שאילתת REST עם RSQL

• שפת שאילתת מנוחה עם תמיכה ברשת Querydsl

1. סקירה כללית

במאמר מהיר זה נרחיב את פעולות החיפוש המתקדמות שיישמנו במאמר הקודם וכוללות קריטריוני חיפוש מבוססי OR בשפת שאילתת ה- REST API שלנו.

2. גישת יישום

לפני כן כל הקריטריונים ב לחפש פרמטר השאילתה יצר פרדיקטים מקובצים רק לפי אופרטור AND. בואו נשנה את זה.

אנו אמורים להיות מסוגלים ליישם תכונה זו כשינוי פשוט ומהיר לגישה הקיימת או ככזו חדשה מאפס.

בגישה הפשוטה, נסמן את הקריטריונים כדי לציין שיש לשלב אותם באמצעות מפעיל OR.

לדוגמה, הנה כתובת ה- URL לבדיקת ה- API עבור "שם פרטי או שם משפחה ”:

// localhost: 8080 / משתמשים? search = firstName: john, 'lastName: doe

שים לב שסימנו את הקריטריונים שם משפחה עם ציטוט יחיד כדי להבדיל אותו. אנו נתפוס פרדיקט זה למפעיל OR באובייקט ערך הקריטריונים שלנו - SpecSearchCriteria:

SpecSearchCriteria ציבורי (String orPredicate, מפתח מחרוזת, פעולת SearchOperation, ערך אובייקט) {super (); this.orPredicate = orPredicate! = null && orPredicate.equals (SearchOperation.OR_PREDICATE_FLAG); this.key = מפתח; this.operation = פעולה; this.value = ערך; }

3. UserSpecificationBuilder הַשׁבָּחָה

עכשיו, בואו ונשנה את בונה המפרט שלנו, UserSpecificationBuilder, לשקול את הקריטריונים המוסמכים או בבנייה מִפרָט:

build מפרט ציבורי () {if (params.size () == 0) {return null; } תוצאת מפרט = מפרט משתמש חדש (params.get (0)); עבור (int i = 1; i <params.size (); i ++) {result = params.get (i) .isOrPredicate ()? Specification.where (תוצאה). או (UserSpecification חדש (params.get (i))): Specification.where (תוצאה). ו- (UserSpecification חדש (params.get (i)))); } להחזיר תוצאה; }

4. UserController הַשׁבָּחָה

לבסוף, בוא נקבע נקודת קצה חדשה של REST בבקר שלנו לשימוש בפונקציונליות חיפוש זו עם מפעיל OR. לוגיקת הניתוח המשופרת מחלצת את הדגל המיוחד המסייע בזיהוי הקריטריונים עם מפעיל OR:

@GetMapping ("/ users / espec") @ResponseBody רשימת הציבור findAllByOrPredicate (@RequestParam חיפוש מחרוזות) {Specification spec = resolutionSpecification (search); החזר dao.findAll (spec); } מוגן מפרט resolSpecification (מחרוזת searchParameters) {UserSpecificationsBuilder בונה = UserSpecificationsBuilder חדש (); מחרוזת operationSetExper = Joiner.on ("|") .join (SearchOperation.SIMPLE_OPERATION_SET); תבנית תבנית = תבנית.קומפילציה ("(\ p {Punct}?) (\ w +?) (" + OperationSetExper + ") (\ p {Punct}?) (\ w +?) (\ p { נקודה}?), "); התאמת התאמה = דפוס. התאמה (searchParameters + ","); ואילו (matcher.find ()) {builder.with (matcher.group (1), matcher.group (2), matcher.group (3), matcher.group (5), matcher.group (4), matcher. קבוצה (6)); } להחזיר builder.build (); }

5. מבחן חי עם אוֹ מַצָב

בדוגמה לבדיקה חיה זו, עם נקודת הקצה החדשה של ה- API, נחפש משתמשים בשם הפרטי "ג'ון" או שם משפחה "איילה". שים לב לפרמטר זה שם משפחה יש הצעת מחיר יחידה, שמסמכת אותה כ"קובץ OR ":

מחרוזת פרטית EURL_PREFIX = "// localhost: 8082 / spring-rest-full / auth / users / espec? search ="; @Test הציבור בטל givenFirstOrLastName_whenGettingListOfUsers_thenCorrect () {תגובה תגובה = givenAuth (). קבל (EURL_PREFIX + "firstName: john, 'lastName: doe"); תוצאת מחרוזת = response.body (). AsString (); assertTrue (result.contains (userJohn.getEmail ())); assertTrue (result.contains (userTom.getEmail ())); }

6. מבחן התמדה עם אוֹ מַצָב

עכשיו, בואו נערוך את אותה בדיקה שעשינו לעיל, ברמת ההתמדה למשתמשים עם שם פרטי "ג'ון" או שם משפחה "איילה":

@Test הציבור בטל givenFirstOrLastName_whenGettingListOfUsers_thenCorrect () {UserSpecificationsBuilder בונה = UserSpecificationsBuilder חדש (); SpecSearchCriteria spec = חדש SpecSearchCriteria ("firstName", SearchOperation.EQUALITY, "john"); SpecSearchCriteria spec1 = SpecSearchCriteria חדש ("'", "lastName", SearchOperation.EQUALITY, "Doe"); תוצאות רשימה = מאגר .findAll (builder.with (spec) .with (spec1) .build ()); assertThat (תוצאות, יש גודל (2)); assertThat (userJohn, isIn (תוצאות)); assertThat (userTom, isIn (תוצאות)); }

7. גישה חלופית

בגישה החלופית נוכל לספק את שאילתת החיפוש יותר כמו שלמה איפה סעיף של שאילתת SQL.

לדוגמה, הנה כתובת ה- URL לחיפוש מורכב יותר מאת שם פרטי ו גיל:

// localhost: 8080 / משתמשים? search = (firstName: john OR firstName: tom) AND גיל> 22

שים לב שהפרדנו קריטריונים, אופרטורים וסוגריים מקבצים בודדים עם רווח ליצירת ביטוי תקף של תקן.

הבה ננתח את ביטוי האינפיקס עם a CriteriaParser. שֶׁלָנוּ CriteriaParser מחלק את ביטוי האינפיקס הנתון לאסימונים (קריטריונים, סוגריים, ומפעילי AND & OR) ויוצר ביטוי postfix לאותו:

ניתוח Deque ציבורי (String searchParam) {Deque output = new LinkedList (); מחסנית Deque = LinkedList חדש (); Arrays.stream (searchParam.split ("\ s +")). ForEach (token -> {if (ops.containsKey (token)) {while (! Stack.isEmpty () && isHigerPrecedenceOperator (token, stack.peek ()) )) {output.push (stack.pop (). equalsIgnoreCase (SearchOperation.OR_OPERATOR)? SearchOperation.OR_OPERATOR: SearchOperation.AND_OPERATOR);} stack.push (token.equalsIgnoreCase (SearchOperation.OR_OPERATOR)? SearchOperation.OR_OPERATION: );} אחר אם (token.equals (SearchOperation.LEFT_PARANTHESIS)) {stack.push (SearchOperation.LEFT_PARANTHESIS);} אחר אם (token.equals (SearchOperation.RIGHT_PARANTHESIS)) {בעוד (! stack.peek (). שווה ( SearchOperation.LEFT_PARANTHESIS)) {output.push (stack.pop ());} stack.pop ();} אחר {Matcher matcher = SpecCriteraRegex.matcher (token); while (matcher.find ()) {output.push ( SpecSearchCriteria חדשה (matcher.group (1), matcher.group (2), matcher.group (3), matcher.group (4), matcher.group (5)));}}}); בעוד (! stack.isEmpty ()) {output.push (stack.pop ()); } פלט החזר; }

בואו נוסיף שיטה חדשה בבונה המפרט שלנו, GenericSpecificationBuilder, לבנות את החיפוש מִפרָט מהביטוי שלאחר התיקון:

 build מפרט ציבורי (Deque postFixedExprStack, פונקציה ממיר) {Deque specStack = חדש LinkedList (); while (! postFixedExprStack.isEmpty ()) {Object mayBeOperand = postFixedExprStack.pollLast (); אם (! (מופע mayBeOperand מחרוזת)) {specStack.push (converter.apply ((SpecSearchCriteria) mayBeOperand)); } אחר {מפרט operand1 = specStack.pop (); מפרט operand2 = specStack.pop (); אם (mayBeOperand.equals (SearchOperation.AND_OPERATOR)) {specStack.push (Specification.where (operand1) .and (operand2)); } אחר אם (mayBeOperand.equals (SearchOperation.OR_OPERATOR)) {specStack.push (Specification.where (operand1) .or (operand2)); }}} להחזיר specStack.pop ();

לסיום, בואו נוסיף נקודת קצה נוספת של REST ב UserController לנתח את הביטוי המורכב עם החדש CriteriaParser:

@GetMapping ("/ users / spec / adv") @ResponseBody public List FindAllByAdvPredicate (@RequestParam חיפוש מחרוזות) {Specification spec = resolSpecificationFromInfixExpr (search); החזר dao.findAll (spec); } מפרט מוגן resolSpecificationFromInfixExpr (מחרוזת searchParameters) {CriteriaParser מנתח = CriteriaParser חדש (); GenericSpecificationsBuilder specBuilder = GenericSpecificationsBuilder חדש (); להחזיר את specBuilder.build (parser.parse (searchParameters), UserSpecification :: new); }

8. מסקנה

במדריך זה שיפרנו את שפת שאילתת REST שלנו עם היכולת לחפש עם מפעיל OR.

היישום המלא של מאמר זה נמצא בפרויקט GitHub. זהו פרויקט מבוסס Maven, כך שיהיה קל לייבא ולהפעיל אותו כפי שהוא.

הַבָּא » שפת שאילתת מנוחה עם RSQL « שפת שאילתת REST קודמת - פעולות חיפוש מתקדמות REST למטה

רק הכרזתי על החדש למד אביב קורס, המתמקד ביסודות האביב 5 ומגף האביב 2:

>> בדוק את הקורס

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