שפת שאילתת REST עם נתוני אביב JPA ו- Querydsl

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

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

• שפת שאילתת REST עם נתוני אביב JPA ו- Querydsl (מאמר נוכחי) • שפת שאילתת REST - פעולות חיפוש מתקדמות

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

• שפת שאילתת מנוחה עם RSQL

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

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

במדריך זה אנו בוחנים בניית שפת שאילתות עבור a REST API באמצעות Spring Data JPA ו- Querydsl.

בשני המאמרים הראשונים בסדרה זו בנינו את אותה פונקציונליות חיפוש / סינון באמצעות JPA Criteria ו- Spring Data JPA Specifications.

כך - למה שפת שאילתות? כי - לכל ממשק API מורכב מספיק - חיפוש / סינון המשאבים שלך לפי שדות פשוטים מאוד פשוט לא מספיק. שפת שאילתות גמישה יותר, ומאפשר לך לסנן בדיוק את המשאבים שאתה צריך.

2. תצורת Querydsl

ראשית - בואו נראה כיצד להגדיר את הפרויקט שלנו לשימוש ב- Querydsl.

עלינו להוסיף את התלות הבאות ל pom.xml:

 com.querydsl querydsl-apt 4.2.2 com.querydsl querydsl-jpa 4.2.2 

עלינו להגדיר את התוסף APT - כלי עיבוד ההערות - תוסף כדלקמן:

 com.mysema.maven apt-maven-plugin 1.1.3 יעד תהליך / מקורות שנוצרו / java com.mysema.query.apt.jpa.JPAAnnotationProcessor 

זה ייצור סוגי Q עבור הישויות שלנו.

3. ה MyUser יֵשׁוּת

הבא - בואו נסתכל על "MyUserישות שבה אנו הולכים להשתמש בממשק ה- API שלנו לחיפוש:

@Untity מחלקה ציבורית MyUser {@Id @GeneratedValue (אסטרטגיה = GenerationType.AUTO) פרטי מזהה ארוך; פרטי מחרוזת firstName; שם משפחה פרטי מחרוזת; דוא"ל מחרוזת פרטי; גיל פרטי פרטי; }

4. מותאם אישית לחזות With PathBuilder

עכשיו - בואו ניצור מנהג לְבַסֵס בהתבסס על אילוצים שרירותיים מסוימים.

אנחנו משתמשים PathBuilder כאן במקום סוגי Q שנוצרו אוטומטית מכיוון שעלינו ליצור נתיבים באופן דינמי לשימוש מופשט יותר:

מחלקה ציבורית MyUserPredicate {קריטריונים פרטיים של SearchCriteria; ציבורי BooleanExpression getPredicate () {PathBuilder entityPath = PathBuilder חדש (MyUser.class, "משתמש"); if (isNumeric (criteria.getValue (). toString ())) {NumberPath path = entityPath.getNumber (criteria.getKey (), Integer.class); ערך int = Integer.parseInt (criteria.getValue (). toString ()); switch (criteria.getOperation ()) {case ":": path path.eq (value); case ">": path path.goe (ערך); מקרה "<": path path.loe (ערך); }} אחר {נתיב StringPath = entityPath.getString (criteria.getKey ()); אם (criteria.getOperation (). equalsIgnoreCase (":")) {path return.containsIgnoreCase (criteria.getValue (). toString ()); }} להחזיר null; }}

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

כדי לייצג סוג זה של קריטריונים לסינון פתוח, אנו משתמשים ביישום פשוט אך די גמיש - SearchCriteria:

מחלקה ציבורית SearchCriteria {מפתח מחרוזת פרטי; פעולת מחרוזת פרטית; ערך אובייקט פרטי; }

ה SearchCriteria מחזיק בפרטים שאנחנו צריכים כדי לאפשר אילוץ:

  • מַפְתֵחַ: שם השדה - לדוגמא: שם פרטי, גיל, … וכו
  • מבצע: הפעולה - לדוגמא: שוויון, פחות מ ... וכו '
  • ערך: ערך השדה - לדוגמא: john, 25, ... וכו '

5. MyUserRepository

עכשיו - בואו נסתכל על שלנו MyUserRepository.

אנחנו צריכים את שלנו MyUserRepository להרחיב QuerydslPredicateExecutor כדי שנוכל להשתמש מנבא מאוחר יותר לסינון תוצאות החיפוש:

ממשק ציבורי MyUserRepository מרחיב את JpaRepository, QuerydslPredicateExecutor, QuerydslBinderCustomizer {@Override ברירת מחדל ציבורית מותאמת אישית (QuerydslBindings bindings, QMyUser root) {bindings.bind (String.class). first ((SingleValueBinding) StringExpression מכיל; כריכות. לא כולל (root.email); }}

שים לב שאנחנו משתמשים כאן בסוג ה- Q שנוצר עבור ה- MyUser ישות, שתיקרא שם QMyUser.

6. שלבו מנבא

הבא - בואו נסתכל על שילוב של Predicates לשימוש באילוצים מרובים בסינון התוצאות.

בדוגמה הבאה - אנו עובדים עם בונה - MyUserPredicatesBuilder - לשלב מנבא:

מחלקה ציבורית MyUserPredicatesBuilder {params רשימה פרטית; ציבורי MyUserPredicatesBuilder () {params = ArrayList חדש (); } MyUserPredicatesBuilder ציבורי עם (מפתח מחרוזת, פעולת מחרוזת, ערך אובייקט) {params.add (SearchCriteria חדש (מפתח, פעולה, ערך)); להחזיר את זה; } build בוליאני-ביטוי ציבורי () {if (params.size () == 0) {return null; } רשום פרדיקטים = params.stream (). מפה (param -> {MyUserPredicate predicate = new MyUserPredicate (param); return predicate.getPredicate ();}). Filter (Objects :: nonNull) .collect (Collectors.toList () ); תוצאה של BooleanExpression = Expressions.asBoolean (true) .isTrue (); עבור (predictate BooleanExpression: predicates) {result = result.and (predicate); } להחזיר תוצאה; }}

7. בדוק את שאילתות החיפוש

לאחר מכן - בואו נבדוק את ה- API שלנו לחיפוש.

נתחיל באתחול מסד הנתונים עם כמה משתמשים - שיהיו מוכנים וזמינים לבדיקה:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (class = {PersistenceConfig.class}) @ Transactional @Rollback class public JPAQuerydslIntegrationTest {@Autowired MyUserRepository repo; משתמש MyUser פרטי ג'ון; פרטי MyUser userTom; @ לפני init בטל פומבי () {userJohn = משתמש חדש שלי (); userJohn.setFirstName ("ג'ון"); userJohn.setLastName ("איילה"); userJohn.setEmail ("[דוא"ל מוגן]"); userJohn.setAge (22); repo.save (userJohn); userTom = MyUser חדש (); userTom.setFirstName ("טום"); userTom.setLastName ("איילה"); userTom.setEmail ("[דוא"ל מוגן]"); userTom.setAge (26); repo.save (userTom); }}

בשלב הבא, נראה כיצד למצוא משתמשים איתם ניתן שם משפחה:

@ מבחן ציבורי בטל נתון Last_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder builder = MyUserPredicatesBuilder חדש (). With ("lastName", ":", "Doe"); תוצאות ניתנות לשינוי = repo.findAll (builder.build ()); assertThat (תוצאות, מכיל InAnyOrder (userJohn, userTom)); }

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

@Test ציבורי בטל givenFirstAndLastName_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder () .with ("firstName", ":", "John"). With ("lastName", ":", "Doe"); תוצאות ניתנות לשינוי = repo.findAll (builder.build ()); assertThat (תוצאות, מכיל (userJohn)); assertThat (תוצאות, לא (מכיל (userTom))); }

לאחר מכן, בואו נראה כיצד למצוא משתמש עם נתון גם שם משפחה וגם גיל מינימום

@ מבחן פומבי בטל שניתן LastAndAge_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder () .with ("lastName", ":", "Doe"). With ("age", ">", "25"); תוצאות ניתנות לשינוי = repo.findAll (builder.build ()); assertThat (תוצאות, מכיל (userTom)); assertThat (תוצאות, לא (מכיל (userJohn))); }

עכשיו, בואו נראה איך לחפש MyUser זֶה לא ממש קיים:

@Test ציבורי בטל givenWrongFirstAndLast_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder בונה = חדש MyUserPredicatesBuilder (). עם ("firstName", ":", "אדם"). עם ("שם אחר", ":", "פוקס"); תוצאות ניתנות לשינוי = repo.findAll (builder.build ()); assertThat (results, emptyIterable ()); }

לבסוף - בואו נראה איך למצוא א MyUser ניתן רק חלק מהשם הפרטי - כמו בדוגמה הבאה:

@Test ציבורי בטל givenPartialFirst_whenGettingListOfUsers_thenCorrect () {MyUserPredicatesBuilder בונה = MyUserPredicatesBuilder חדש (). עם ("firstName", ":", "jo"); תוצאות ניתנות לשינוי = repo.findAll (builder.build ()); assertThat (תוצאות, מכיל (userJohn)); assertThat (תוצאות, לא (מכיל (userTom))); }

8. UserController

לבסוף, בואו נרכיב הכל ונבנה את ה- REST API.

אנו מגדירים א UserController שמגדירה שיטה פשוטה מצא הכל() עם "לחפשפרמטר להעביר במחרוזת השאילתה:

@Controller מחלקה ציבורית UserController {@ פרטי פרטי MyUserRepository myUserRepository; @RequestMapping (method = RequestMethod.GET, value = "/ myusers") @ResponseBody public Iterable search (@RequestParam (value = "search") חיפוש מחרוזות) {MyUserPredicatesBuilder Builder = MyUserPredicatesBuilder חדש (); אם (חיפוש! = null) {תבנית תבנית = תבנית. קומפילציה ("(\ w +?) (: |) (\ w +?),"); התאמת התאמה = דפוס. התאמה (חיפוש + ","); בעוד (matcher.find ()) {builder.with (matcher.group (1), matcher.group (2), matcher.group (3)); }} BooleanExpression exp = builder.build (); להחזיר myUserRepository.findAll (exp); }}

הנה דוגמה מהירה של כתובת אתר לבדיקה:

// localhost: 8080 / myusers? search = lastName: איילה, גיל> 25

והתגובה:

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

9. מסקנה

מאמר שלישי זה סיקר הצעדים הראשונים לבניית שפת שאילתות עבור REST API, תוך שימוש טוב בספריית Querydsl.

היישום כמובן מוקדם, אך ניתן לפתח אותו בקלות כדי לתמוך בפעולות נוספות.

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

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

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