REST API עם Play Framework בג'אווה

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

מטרת הדרכה זו היא לחקור את Play Framework וללמוד כיצד לבנות באמצעותו שירותי REST באמצעות ג'אווה.

נרכיב REST API ליצירת, אחזור, עדכון ומחיקה של רשומות סטודנטים.

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

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

2. צור יישום חדש

לאחר שהתקנו את Play Framework כמתואר במבוא שלנו למסגרת Play, אנו מוכנים ליצור את היישום שלנו.

בואו נשתמש ב- sbt פקודה ליצור יישום חדש שנקרא סטודנט-אפי באמצעות play-java-seed:

sbt playframework חדש / play-java-seed.g8

3. דוגמניות

עם פיגומי היישומים במקום, בוא ננווט אל סטודנט-אפי / אפליקציה / מודלים וליצור שעועית ג'אווה לטיפול במידע הסטודנטים:

מחלקה ציבורית תלמיד {פרטי מחרוזת שם פרטי; שם משפחה פרטי מחרוזת; גיל פרטי פרטי; מזהה פרטי פרטי; // קונסטרוקציות סטנדרטיות, קבוצות וקובעות}

ניצור כעת חנות נתונים פשוטה - מגובה על ידי מפת גיבוב - לנתוני סטודנטים, בשיטות עוזרות לביצוע פעולות CRUD:

מחלקה ציבורית StudentStore {סטודנטים מפה פרטית = HashMap חדש (); ציבורי אופציונלי addStudent (סטודנט סטודנט) {int id = students.size (); student.setId (id); students.put (מזהה, סטודנט); החזרה Optional.ofNullable (סטודנט); } ציבורי getStudent (int id) ציבורי {return Optional.ofNullable (students.get (id)); } ציבורי הגדר getAllStudents () {החזר HashSet חדש (students.values ​​()); } public עדכון אופציונלי סטודנט (סטודנט סטודנט) {int id = student.getId (); אם (students.containsKey (id)) {students.put (id, student); החזרה Optional.ofNullable (סטודנט); } להחזיר אפס; } delete בוליאני ציבוריStudent (id id) {return students.remove (id)! = null; }}

4. בקרים

בוא נעבור אל סטודנט-אפי / אפליקציה / בקרים וליצור בקר חדש שנקרא StudentController.java. נעבור בקוד באופן הדרגתי.

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

יש רק אזהרה אחת כשעוסקים בתכנות אסינכרוני בבקר Play Framework: עלינו לספק HttpExecutionContext. אם אנו לא מספקים את ההקשר של ביצוע HTTP, נקבל את השגיאה הידועה לשמצה "אין הקשר HTTP זמין מכאן" בעת קריאה לשיטת הפעולה.

בואו נזריק את זה:

פרטי HttpExecutionContext ec; פרטית StudentStore studentStore; @ הזריק StudentController ציבורי (HttpExecutionContext ec, StudentStore studentStore) {this.studentStore = studentStore; this.ec = ec; }

שימו לב שהוספנו גם את StudentStore והזריק את שני השדות לבנאי הבקר באמצעות ה- @לְהַזרִיק ביאור. לאחר שנעשה זאת, כעת נוכל להמשיך ביישום שיטות הפעולה.

ציין זאת שחק ספינות עם ג'קסון כדי לאפשר עיבוד נתונים - כדי שנוכל לייבא את כל שיעורי ג'קסון שאנו זקוקים להם ללא תלות חיצונית.

בואו נגדיר מחלקת שירות לביצוע פעולות חוזרות. במקרה זה, בניית תגובות HTTP.

אז בואו ניצור תלמיד-אפי / אפליקציה / כלים חבילה והוספה Util.java בּוֹ:

מחלקה ציבורית עד {ObjectNode הציבורי createResponse (תגובת אובייקט, בסדר בוליאני) {ObjectNode תוצאה = Json.newObject (); result.put ("isSuccessful", בסדר); אם (תגובה למשל של מחרוזת) {result.put ("גוף", (מחרוזת) תגובה); } אחר {result.putPOJO ("גוף", תגובה); } להחזיר תוצאה; }}

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

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

4.1. ה לִיצוֹר פעולה

ממופה כ הודעה פעולה, שיטה זו מטפלת ביצירת ה- סטוּדֶנט לְהִתְנַגֵד:

Public CompletionStage create (Http.Request בקשה) {JsonNode json = request.body (). asJson (); return supplyAsync (() -> {if (json == null) {return badRequest (Util.createResponse ("מצפה נתוני Json", false));} סטודנט אופציונלי אופציונלי = studentStore.addStudent (Json.fromJson (json, Student.class) )); return studentOptional.map (student -> {JsonNode jsonObject = Json.toJson (student); return created (Util.createResponse (jsonObject, true));}). orElse (internalServerError (Util.createResponse ("לא ניתן ליצור נתונים. ", false)));}, ec.current ()); }

אנו משתמשים בשיחה מהמוזמנים Http. בקשה בכיתה להכניס את גוף הבקשה לג'קסון JsonNode מעמד. שימו לב כיצד אנו משתמשים בשיטת השירות כדי ליצור תגובה אם הגוף נמצא ריק.

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

אנחנו יכולים להעביר אליו כל דבר חוּט או א JsonNode, יחד עם א בוליאני דגל לציון סטטוס.

שימו לב גם כיצד אנו משתמשים Json.fromJson () להמיר את אובייקט JSON הנכנס לא סטוּדֶנט התנגד וחזרה ל- JSON לקבלת התגובה.

לבסוף, במקום בסדר() שאנחנו רגילים אלינו, אנו משתמשים ב- נוצר שיטת עוזר מה play.mvc.results חֲבִילָה. הרעיון הוא להשתמש בשיטה הנותנת מעמד HTTP נכון עבור הפעולה המתבצעת בהקשר מסוים. לדוגמה, בסדר() למצב HTTP OK 200, ו- נוצר () כאשר HTTP CREATED 201 הוא סטטוס התוצאה כפי ששימש לעיל. מושג זה יעלה לאורך כל שאר הפעולות.

4.2. ה עדכון פעולה

א לָשִׂים בקשה ל // localhost: 9000 / פוגע ב StudentController.עדכון שיטה, אשר מעדכן את המידע על התלמיד על ידי התקשרות ל - updateStudent שיטת ה- StudentStore:

עדכון ציבורי של CompletionStage (בקשת Http.Request) {JsonNode json = request.body (). asJson (); return supplyAsync (() -> {if (json == null) {return badRequest (Util.createResponse ("מצפה נתוני Json", false));} סטודנט אופציונלי אופציונלי = studentStore.updateStudent (Json.fromJson (json, Student.class) )); return studentOptional.map (student -> {if (student == null) {return notFound (Util.createResponse ("התלמיד לא נמצא", שקר));} JsonNode jsonObject = Json.toJson (סטודנט); להחזיר בסדר (Util.createResponse (jsonObject, true));}). OrElse (internalServerError (Util.createResponse ("לא ניתן ליצור נתונים.", שקר)));}, ec.current ()); }

4.3. ה להחזיר פעולה

כדי לאחזר תלמיד, אנו מעבירים את מזהה התלמיד כפרמטר נתיב ב- לקבל בקשה ל // localhost: 9000 /: id. זה יפגע ב- להחזיר פעולה:

Public CompletionStage retrieve (int id) {return supplyAsync (() -> {final Optional studentOptional = studentStore.getStudent (id); return studentOptional.map (student -> {JsonNode jsonObjects = Json.toJson (student); return ok (Util .createResponse (jsonObjects, true));}). orElse (notFound (Util.createResponse ("תלמיד עם מזהה:" + id + "לא נמצא", שקר)))}}, ec.current ()); }

4.4. ה לִמְחוֹק פעולה

ה לִמְחוֹק פעולה ממופה ל // localhost: 9000 /: id. אנו מספקים את תְעוּדַת זֶהוּת לזהות איזו רשומה למחוק:

Public CompletionStage delete (int id) {return supplyAsync (() -> {boolean status = studentStore.deleteStudent (id); if (! status) {return notFound (Util.createResponse ("סטודנט עם מזהה:" + id + "לא נמצא ", שקר));} להחזיר בסדר (Util.createResponse (" תלמיד עם מזהה: "+ id +" נמחק ", נכון));}, ec.current ()); }

4.5. ה listStudents פעולה

סוף - סוף, ה listStudents הפעולה מחזירה רשימה של כל התלמידים שאוחסנו עד כה. זה ממופה ל // localhost: 9000 / כ לקבל בַּקָשָׁה:

Public CompletionStage listStudents () {return supplyAsync (() -> {Set result = studentStore.getAllStudents (); MapMapper Object = New ObjectMapper (); JsonNode jsonData = mapper.convertValue (result, JsonNode.class); return ok (Util. createResponse (jsonData, true));}, ec.current ()); }

5. מיפיות

לאחר שהגדרנו את פעולות הבקר שלנו, כעת אנו יכולים למפות אותן על ידי פתיחת הקובץ תלמיד- api / conf / מסלולים והוספת מסלולים אלה:

GET / controllers.StudentController.listStudents () GET /: controllers id.StudentController.retrieve (id: Int) POST / controllers.StudentController.create (בקשה: בקשה) PUT / controllers.StudentController.update (בקשה: בקשה) מחק /: controllers id.StudentController.delete (id: Int) בקרי קבצים GET / נכסים / *. Assets.versioned (path = "/ public", file: Asset)

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

אחרי זה, סיימנו לבנות את סטוּדֶנט ממשק API.

למידע נוסף על הגדרת מיפויי מסלול, בקרו במדריך שלנו לניתוב ניתוב.

6. בדיקות

כעת אנו יכולים להריץ בדיקות ב- API שלנו על ידי שליחת בקשות אל // localhost: 9000 / והוספת ההקשר המתאים. הפעלת נתיב הבסיס מהדפדפן אמורה להופיע:

{"isSuccessful": נכון, "body": []}

כפי שאנו רואים, הגוף ריק מכיוון שעדיין לא הוספנו רשומות. באמצעות סִלְסוּלבואו נערוך כמה בדיקות (לחלופין נוכל להשתמש בלקוח REST כמו דואר הדוור).

בוא נפתח חלון מסוף ונבצע את פקודת התלתל ל- להוסיף סטודנט:

תלתל -X POST -H "סוג תוכן: יישום / json" \ -d '{"firstName": "John", "lastName": "Baeldung", "age": 18}' \ // localhost: 9000 /

זה יחזיר את התלמיד החדש שנוצר:

{"isSuccessful": true, "body": {"firstName": "John", "lastName": "Baeldung", "age": 18, "id": 0}}

לאחר הפעלת המבחן הנ"ל, הטעינה // localhost: 9000 מהדפדפן אמור לתת לנו כעת:

{"isSuccessful": true, "body": [{"firstName": "John", "lastName": "Baeldung", "age": 18, "id": 0}]} 

ה תְעוּדַת זֶהוּת המאפיין יגדל עבור כל רשומה חדשה שנוסיף.

ל למחוק רשומה אנו שולחים א לִמְחוֹק בַּקָשָׁה:

תלתל -X מחק // localhost: 9000/0 {"isSuccessful": true, "body": "סטודנט עם מזהה: 0 נמחק"} 

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

תלתל -X POST -H "סוג תוכן: יישום / json" \ -d '{"firstName": "John", "lastName": "Baeldung", "age": 18}' \ // localhost: 9000 / {"isSuccessful": true, "body": {"firstName": "John", "lastName": "Baeldung", "age": 18, "id": 0}}

בואו עכשיו לעדכן את הרשומה על ידי הגדרת השם הפרטי ל"אנדרו "וגיל 30:

תלתל -X PUT -H "סוג תוכן: יישום / json" \ -d '{"firstName": "Andrew", "lastName": "Baeldung", "age": 30, "id": 0}' \ // localhost: 9000 / {"isSuccessful": true, "body": {"firstName": "Andrew", "lastName": "Baeldung", "age": 30, "id": 0}}

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

בואו ניצור כמה רשומות דמה נוספות, נוסיף שניים: ג'ון דו וסם בלדונג:

תלתל -X POST -H "סוג תוכן: יישום / json" \ -d '{"firstName": "John", "lastName": "Doe", "age": 18}' \ // localhost: 9000 /
תלתל -X POST -H "סוג תוכן: יישום / json" \ -d '{"firstName": "Sam", "lastName": "Baeldung", "age": 25}' \ // localhost: 9000 /

עכשיו, בואו נקבל את כל הרשומות:

תלתל -X GET // localhost: 9000 / {"isSuccessful": true, "body": [{"firstName": "Andrew", "lastName": "Baeldung", "age": 30, "id": 0 }, {"firstName": "John", "lastName": "Doe", "age": 18, "id": 1}, {"firstName": "Sam", "lastName": "Baeldung", " גיל ": 25," id ": 2}]}

במבחן הנ"ל אנו בודקים את תפקודו התקין של ה- listStudents פעולת בקר.

7. מסקנה

במאמר זה, הראינו כיצד לבנות ממשק API REST מלא באמצעות Play Framework.

כרגיל, קוד המקור של הדרכה זו זמין ב- GitHub.


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