מבוא למסגרת האינטרנט הפונקציונלית באביב 5

1. הקדמה

Spring WebFlux היא מסגרת אינטרנטית פונקציונלית חדשה שנבנתה באמצעות עקרונות תגובתי.

במדריך זה נלמד כיצד לעבוד איתו בפועל.

אנו נבסס על המדריך הקיים שלנו ל- Spring 5 WebFlux. במדריך זה יצרנו יישום REST תגובתי פשוט תוך שימוש ברכיבים מבוססי ביאורים. כאן נשתמש במקום הפונקציונלי במקום.

2. תלות של Maven

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

 org.springframework.boot spring-boot-starter-webflux 2.2.6.RELEASE 

3. מסגרת אינטרנט פונקציונלית

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

בניגוד למודל מבוסס ההערות בו אנו משתמשים במיפוי הערות, כאן נשתמש HandlerFunction ו RouterFunctionס.

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

3.1. HandlerFunction

ה HandlerFunction מייצג פונקציה המייצרת תשובות לבקשות המנותבות אליהן:

ממשק ציבורי @FunctionalInterface HandlerFunction {ידית מונו (בקשת ServerRequest); }

ממשק זה הוא בעיקרו פוּנקצִיָה, שמתנהג מאוד כמו סרוולט.

אם כי לעומת תקן שירות # Servlet (ServletRequest בקשה, ServletResponse res), HandlerFunction אינו לוקח תגובה כפרמטר קלט.

3.2. RouterFunction

RouterFunction משמש חלופה ל @ בקשת מיפוי ביאור. אנו יכולים להשתמש בו לניתוב בקשות לפונקציות המטפלות:

ממשק ציבורי @FunctionalInterface RouterFunction {מונו מסלול (בקשת ServerRequest); // ...}

בדרך כלל אנו יכולים לייבא את פונקציית העוזר RouterFunctions.route () ליצור מסלולים, במקום לכתוב פונקציית נתב שלמה.

זה מאפשר לנו לנתב בקשות באמצעות יישום RequestPredicate. כאשר התאמה בין הפרדיקט מוחזרת הארגומנט השני, פונקציית המטפל:

מסלול נתיב סטטי ציבורי (RequestPredicate predicate, HandlerFunction handlerFunction)

בגלל ה מַסלוּל() שיטה מחזירה א RouterFunctionנוכל לשרשר אותו לבניית תוכניות ניתוב חזקות ומורכבות.

4. יישום REST תגובתי באמצעות רשת פונקציונלית

במדריך הקודם יצרנו פשוט ניהול עובדים יישום REST באמצעות @ RestController ו WebClient.

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

ראשון, עלינו ליצור מסלולים באמצעות RouterFunction לפרסם ולצרוך את זרמי התגובה שלנו עוֹבֵדס.

מסלולים רשומים כשעועית קפיצה וניתן ליצור אותם בכל מחלקת תצורה.

4.1. משאב יחיד

בואו ניצור את המסלול הראשון שלנו באמצעות RouterFunction שמפרסם סינגל עוֹבֵד מַשׁאָב:

@Bean RouterFunction getEmployeeByIdRoute () {מסלול חזרה (GET ("/ workers / {id}"), req -> בסדר (). גוף (עובדRepository (). FindEmployeeById (req.pathVariable ("id")), שכיר עובד. )); }

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

במילים אחרות, הדוגמה לעיל מנתבת את כל בקשות ה- GET עבור / עובדים / {id} ל EmployERepository # findEmployeeById (מזהה מחרוזת) שיטה.

4.2. משאב אוסף

לאחר מכן, לפרסום משאב אוסף, בואו נוסיף מסלול נוסף:

@Bean RouterFunction getAllEmployeesRoute () {מסלול חזרה (GET ("/ עובדים"), req -> בסדר (). גוף (עובדRepository (). FindAllEmployees (), שכיר עובד)); }

4.3. עדכון משאבים בודדים

לבסוף, בואו נוסיף מסלול לעדכון ה- עוֹבֵד מַשׁאָב:

@Bean RouterFunction updateEmployeeRoute () {מסלול חזרה (POST ("/ עובדים / עדכון"), req -> req.body (toMono (Employee.class)). DoOnNext (employeeRepository () :: updateEmployee). ואז (ok () .לִבנוֹת())); }

5. הרכבת מסלולים

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

בואו נראה כיצד לשלב בין המסלולים שנוצרו לעיל:

@Bean RouterFunction wroteRoutes () {מסלול חזרה (GET ("/ עובדים"), req -> בסדר (). גוף (עובד מאגר (). FindAllEmployees (), שכיר עובד)). ו- (מסלול (GET ("/ עובדים) / {id} "), req -> בסדר (). גוף (עובדRepository (). findEmployeeById (req.pathVariable (" id ")), עובד.קלאס))). (מסלול (POST (" / עובדים / עדכון) "), req -> req.body (toMono (Employee.class)) .doOnNext (employeeRepository () :: updateEmployee). ואז (ok (). build ()))); }

הנה, השתמשנו RouterFunction.and () לשלב את המסלולים שלנו.

לבסוף, יישמנו את ה- REST API המלא הדרוש עבורנו ניהול עובדים יישום, באמצעות נתבים ומטפלים.

כדי להריץ את היישום, נוכל להשתמש במסלולים נפרדים או במסלול היחיד, שיצרנו לעיל.

6. מסלולי בדיקה

אנחנו יכולים להשתמש WebTestClient לבדוק את המסלולים שלנו.

לשם כך, ראשית עלינו לאגד את המסלולים באמצעות ה- bindToRouterFunction ואז לבנות את המופע של לקוח הבדיקה.

בואו נבדוק את שלנו getEmployeeByIdRoute:

@Test ציבורי בטל givenEmployeeId_whenGetEmployeeById_thenCorrectEmployee () {לקוח WebTestClient = WebTestClient .bindToRouterFunction (config.getEmployeeByIdRoute ()). בניין (); עובד שכיר = עובד חדש ("1", "עובד 1"); given (employeeRepository.findEmployeeById ("1")). willReturn (Mono.just (עובד)); client.get () .uri ("/ עובדים / 1"). exchange () .expectStatus () .isOk () .expectBody (שכיר עובד) .isEqualTo (עובד); }

ובדומה getAllEmployeesRoute:

@Test ציבורי בטל כאשר GetAllEmployees_thenCorrectEmployees () {WebTestClient client = WebTestClient .bindToRouterFunction (config.getAllEmployeesRoute ()) .build (); רשימת עובדים = Arrays.asList (עובד חדש ("1", "עובד 1"), עובד חדש ("2", "עובד 2"); Flux employeeFlux = Flux.fromIterable (עובדים); given (employeeRepository.findAllEmployees ()). willReturn (employeeFlux); client.get () .uri ("/ עובדים"). exchange () .expectStatus () .isOk () .expectBodyList (שכיר עובד) .isEqualTo (עובדים); }

אנחנו יכולים גם לבדוק את שלנו updateEmployeeRoute על ידי הטענה כי שלנו עוֹבֵד מופע מתעדכן באמצעות מאגר עובדים:

@Test ציבור בטל כאשרUpdateEmployee_thenEmployeeUpdated () {WebTestClient client = WebTestClient .bindToRouterFunction (config.updateEmployeeRoute ()) .build (); עובד שכיר = עובד חדש ("1", "עובד 1 עודכן"); client.post () .uri ("/ עובדים / עדכון"). גוף (Mono.just (עובד), שכיר עובד). exchange () .expectStatus () .isOk (); אמת (עובדאחסן) .updateEmployee (עובד); }

לפרטים נוספים על בדיקה עם WebTestClient אנא עיין במדריך שלנו לעבודה עם WebClient ו WebTestClient.

7. סיכום

במדריך זה הצגנו את מסגרת האינטרנט הפונקציונלית החדשה באביב 5 ובדקנו את שני ממשקי הליבה שלה - RouterFunction ו HandlerFunction. למדנו גם כיצד ליצור מסלולים שונים לטיפול בבקשה ולשלוח את התגובה.

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

כמו תמיד, ניתן למצוא את קוד המקור המלא ב- Github.


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