מדריך ל- JavaLite - בניית יישום CREST של RESTful

1. הקדמה

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

במדריך זה, אנו נסתכל על תכונות JavaLite המתמקדות בבניית ממשק API פשוט.

2. התקנה

במהלך כל הדרכה זו, ניצור יישום פשוט RESTful CRUD. על מנת לעשות זאת, נשתמש ב- ActiveWeb וב- ActiveJDBC - שתיים מהמסגרות שאיתן JavaLite משתלב.

אז בואו נתחיל להוסיף את התלות הראשונה שאנחנו צריכים:

 org.javalite activeweb 1.15 

חפץ ActiveWeb כולל את ActiveJDBC, כך שאין צורך להוסיף אותו בנפרד. לידיעתך, את הגרסה האחרונה של פעיל האתרים ניתן למצוא במרכז הייבן.

התלות השנייה שאנחנו צריכים היא מחבר מסד נתונים. לדוגמא זו, אנו נשתמש ב- MySQL ולכן עלינו להוסיף:

 mysql mysql-connector-java 5.1.45 

שוב, התלות האחרונה ב- mysql-connector-java ניתן למצוא ב- Maven Central.

התלות האחרונה שעלינו להוסיף היא משהו ספציפי ל- JavaLite:

 org.javalite activejdbc-instrumentation מכשיר 1.4.13 בכיתות תהליכים 

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

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

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

3. מיפוי יחסי אובייקט

3.1. מיפוי ומכשור

בוא נתחיל ב ליצור מוצר מעמד שיהיה היישות העיקרית שלנו:

מוצר בכיתה ציבורית {}

ובואו גם צור עבורה את הטבלה המתאימה:

צור מוצרי טבלה (id int (11) ברירת מחדל NULL auto_increment מפתח ראשי, שם VARCHAR (128));

לבסוף, אנחנו יכולים לשנות שלנו מוצר בכיתה לבצע את המיפוי:

class class מוצר מרחיב את המודל {}

אנחנו רק צריכים להאריך org.javalite.activejdbc.Model מעמד. ActiveJDBC מסיק פרמטרים של סכמות DB ממסד הנתונים. בזכות יכולת זו, אין צורך להוסיף גטרים וקובעים או כל הערה.

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

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

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

מוצר p = מוצר חדש (); p.set ("שם", "לחם"); p.saveIt ();

אוֹ:

רשימת מוצרים = Product.findAll ();

זה איפה activejdbc- מכשור תוסף נכנס. מכיוון שכבר יש לנו את התלות ב- pom שלנו, עלינו לראות שיעורים מכוונים במהלך הבנייה:

... [INFO] --- פעילjdbc- מכשור: 1.4.11: מכשיר (ברירת מחדל) @ javalite --- *********************** **** התחל הוראות **************************** מדריך: ... \ מדריכים \ java-lite \ target \ classes מכשור class: ... / tutorials / java-lite / target / classes / app / models / Product.class ************************** * הוראות סיום **************************** ...

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

3.2. בדיקה

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

@Test הציבור בטל givenSavedProduct_WhenFindFirst_ThenSavedProductIsReturned () {Base.open ("com.mysql.jdbc.Driver", "jdbc: mysql: // localhost / dbname", "משתמש", "סיסמה"); מוצר toSaveProduct = מוצר חדש (); toSaveProduct.set ("שם", "לחם"); toSaveProduct.saveIt (); מוצר savedProduct = Product.findFirst ("שם =?", "לחם"); assertEquals (toSaveProduct.get ("שם"), להצילProduct.get ("שם")); }

שים לב שכל זה (ועוד) אפשרי רק על ידי דגם ומכשור ריקים.

4. בקרים

כעת, לאחר שהמיפוי שלנו מוכן, אנו יכולים להתחיל לחשוב על היישום שלנו ועל שיטות ה- CRUD שלו.

לשם כך נשתמש בבקרים אשר מעבדים בקשות HTTP.

בואו ניצור את שלנו ProductsController:

@RESTful מחלקה ציבורית ProductsController מרחיב את AppController {אינדקס הריק הציבורי () {// ...}}

עם הטמעה זו, ActiveWeb תמפה באופן אוטומטי אינדקס() שיטה ל- URI הבא:

//:/מוצרים

בקרים מוסרים עם @מַרגִיעַ, לספק קבוצה קבועה של שיטות הממופה אוטומטית ל- URI שונים. בואו נראה את אלה שיהיו שימושיים לדוגמא CRUD שלנו:

שיטת בקרשיטת HTTPURI
לִיצוֹרלִיצוֹר()הודעה// מארח: נמל / מוצרים
קרא אחדהופעה()לקבל// host: port / products / {id}
תקרא הכלאינדקס()לקבל// מארח: נמל / מוצרים
עדכוןעדכון()לָשִׂים// host: port / products / {id}
לִמְחוֹקלהרוס()לִמְחוֹק// host: port / products / {id}

ואם נוסיף את סט השיטות הזה ProductsController:

@RESTful מחלקה ציבורית ProductsController מרחיב את AppController {אינדקס חלל ציבורי () {// קוד כדי לקבל את כל המוצרים} יצירת חלל ציבורי () {// קוד ליצירת מוצר חדש} עדכון חלל ציבורי () {// קוד לעדכון קיים מוצר} הצגת חלל ציבורי () {// קוד למציאת מוצר אחד} חלל ציבורי הרס () {// קוד להסרת מוצר קיים}}

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

5. תצורה

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

src | ---- ראשי | ---- java.app | | ---- תצורה | | ---- בקרים | | ---- דגמים | ---- משאבים | ---- webapp | ---- WEB-INF | ---- צפיות

יש חבילה ספציפית אחת שאנחנו צריכים להסתכל עליה - אpp.config.

בתוך החבילה הזו ניצור שלוש כיתות:

מחלקה ציבורית DbConfig מרחיב את AbstractDBConfig {@Override public void init (AppContext appContext) {this.configFile ("/ database.properties"); }}

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

development.driver = com.mysql.jdbc. דרייבר development.username = user development.password = password password.url = jdbc: mysql: // localhost / dbname

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

המחלקה השנייה שאנחנו צריכים לכלול בתוכה app.config החבילה היא:

מחלקה ציבורית AppControllerConfig מרחיבה את AbstractControllerConfig {@Override public void init (AppContext appContext) {add (new DBConnectionFilter ()). to (ProductsController.class); }}

קוד זהיחייב את החיבור שהגדרנו זה עתה לבקר שלנו.

הכיתה השלישית רָצוֹןהגדר את ההקשר של האפליקציה שלנו:

מחלקה ציבורית AppBootstrap מרחיב את Bootstrap {init public void (הקשר AppContext) {}}

לאחר יצירת שלושת המחלקות, הדבר האחרון בקשר לתצורה הוא יצירת שלנו web.xml קוֹבֶץ תַחַת webapp / WEB-INF מַדרִיך:

   משגר org.javalite.activeweb.RequestDispatcher אי הכללות css, תמונות, js, קידוד ico UTF-8 משדר / * 

כעת לאחר התצורה, נוכל להמשיך ולהוסיף את ההיגיון שלנו.

6. יישום לוגיקת CRUD

עם יכולות דמויי DAO שמספקים שלנו מוצר בכיתה, זה פשוט מאוד להוסיף פונקציונליות CRUD בסיסית:

@RESTful מחלקה ציבורית ProductsController מרחיב את AppController {ממפה פרטי ObjectMapper = ObjectMapper חדש (); אינדקס חלל ציבורי () {List products = Product.findAll (); // ...} בטל ציבורי create () {Map payload = mapper.readValue (getRequestString (), Map.class); מוצר p = מוצר חדש (); p.fromMap (מטען); p.saveIt (); // ...} עדכון חלל ציבורי () {Maploadload = mapper.readValue (getRequestString (), Map.class); מחרוזת מזהה = getId (); מוצר p = Product.findById (id); p.fromMap (מטען); p.saveIt (); // ...} מופע חלל ציבורי () {String id = getId (); מוצר p = Product.findById (id); // ...} חלל ציבורי הרס () {String id = getId (); מוצר p = Product.findById (id); p.delete (); // ...}}

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

7. צפיות

ActiveWeb משתמש ב- FreeMarker כמנוע תבניות, וכל התבניות שלו צריכות להיות ממוקמות תחת src / main / webapp / WEB-INF / views.

בתוך הספרייה הזו, נציב את תצוגותינו בתיקיה בשם מוצרים (זהה לבקר שלנו). בואו ניצור את התבנית הראשונה שלנו שנקראת _product.ftl:

{"id": $ {product.id}, "name": "$ {product.name}"}

בשלב זה די ברור שזו תגובת JSON. כמובן, זה יעבוד רק עבור מוצר אחד, אז בואו נמשיך ויצור תבנית אחרת בשם index.ftl:

[]

זה בעצם יהפוך אוסף בשם מוצרים, כאשר כל אחד מעוצב על ידי _product.ftl.

סוף כל סוף, עלינו לאגד את התוצאה מהבקר שלנו לתצוגה המקבילה:

@RESTful מחלקה ציבורית ProductsController מרחיב את AppController {אינדקס חלל ציבורי () {List products = Product.findAll (); תצוגה ("מוצרים", מוצרים); לְדַקלֵם(); } מופע חלל ציבורי () {String id = getId (); מוצר p = Product.findById (id); תצוגה ("מוצר", עמ '); לעבד ("_ מוצר"); }}

במקרה הראשון אנו מקצים מוצרים רשימת אוסף התבניות שלנו בשם גם מוצרים.

ואז, מכיוון שאיננו מציינים שום תצוגה, index.ftl יהיה בשימוש.

בשיטה השנייה אנו מקצים מוצר עמ ' לאלמנט מוצר בתצוגה ואנחנו אומרים במפורש איזו תצוגה להציג.

נוכל גם ליצור נוף message.ftl:

{"message": "$ {message}", "code": $ {code}}

ואז לקרוא לזה ליצור כל אחד משלנו ProductsControllerשיטת:

תצוגה ("הודעה", "הייתה שגיאה.", "קוד", 200); עיבוד ("הודעה");

בואו נראה את הגמר שלנו ProductsController:

@RESTful מחלקה ציבורית ProductsController מרחיב את AppController {ממפה פרטי ObjectMapper = ObjectMapper חדש (); אינדקס חלל ציבורי () {view ("products", Product.findAll ()); render (). contentType ("application / json"); } בטל ציבורי ליצור () {Maploadload = mapper.readValue (getRequestString (), Map.class); מוצר p = מוצר חדש (); p.fromMap (מטען); p.saveIt (); תצוגה ("הודעה", "מזהה מוצר שנשמר בהצלחה" + p.get ("מזהה"), "קוד", 200); עיבוד ("הודעה"); } עדכון חלל ציבורי () {Maploadload = mapper.readValue (getRequestString (), Map.class); מחרוזת מזהה = getId (); מוצר p = Product.findById (id); אם (p == null) {view ("הודעה", "מזהה מוצר" + מזהה + "לא נמצא.", "קוד", 200); עיבוד ("הודעה"); לַחֲזוֹר; } p.fromMap (מטען); p.saveIt (); תצוגה ("הודעה", "מזהה מוצר שעודכן בהצלחה" + מזהה, "קוד", 200); עיבוד ("הודעה"); } מופע חלל ציבורי () {String id = getId (); מוצר p = Product.findById (id); אם (p == null) {view ("הודעה", "מזהה מוצר" + מזהה + "לא נמצא.", "קוד", 200); עיבוד ("הודעה"); לַחֲזוֹר; } תצוגה ("מוצר", p); לעבד ("_ מוצר"); } חלל ציבורי להרוס () {String id = getId (); מוצר p = Product.findById (id); אם (p == null) {view ("הודעה", "מזהה מוצר" + מזהה + "לא נמצא.", "קוד", 200); עיבוד ("הודעה"); לַחֲזוֹר; } p.delete (); תצוגה ("הודעה", "מזהה מוצר שנמחק בהצלחה" + מזהה, "קוד", 200); עיבוד ("הודעה"); } @Override מוגן מחרוזת getContentType () {להחזיר "יישום / json"; } @Override מוגן מחרוזת getLayout () {return null; }}

בשלב זה היישום שלנו נעשה ואנחנו מוכנים להריץ אותו.

8. הפעלת האפליקציה

נשתמש בתוסף ג'טי:

 org.eclipse.jetty jetty-maven-plugin 9.4.8.v20171121 

מצא את התוסף האחרון של jetty-maven במרכז Maven.

ואנחנו מוכנים, אנחנו יכולים להריץ את היישום שלנו:

מזח mvn: לרוץ

בואו ניצור כמה מוצרים:

$ curl -X POST // localhost: 8080 / products -H 'type content: application / json' -d '{"name": "Water"}' {"message": "מזהה מוצר 1 נשמר בהצלחה", " קוד ": 200}
$ curl -X POST // localhost: 8080 / products -H 'type type: application / json' -d '{"name": "Bread"}' {"message": "מזהה מוצר 2 נשמר בהצלחה", " קוד ": 200}

.. קרא אותם:

$ curl -X GET // localhost: 8080 / products [{"id": 1, "name": "Water"}, {"id": 2, "name": "Bread"}]

.. עדכן אחד מהם:

$ curl -X PUT // localhost: 8080 / products / 1 -H 'type content: application / json' -d '{"name": "Juice"}' {"message": "מזהה מוצר 1 עודכן בהצלחה" , "קוד": 200}

... קרא את זה שרק עדכנו:

$ curl -X GET // localhost: 8080 / products / 1 {"id": 1, "name": "Juice"}

לבסוף, אנו יכולים למחוק אחת:

$ curl -X DELETE // localhost: 8080 / products / 2 {"message": "מזהה מוצר 2 נמחק בהצלחה", "code": 200}

9. מסקנה

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

זה היה רק ​​מבוא ל- ActiveWeb ו- ActiveJDBC, מצא תיעוד נוסף באתר שלהם וחפש את יישום המוצרים שלנו בפרויקט Github.