דוגמה לבקר, שירות ו- DAO עם Spring Boot ו- JSF

1. הקדמה

פנים JavaServer היא מסגרת ממשק משתמש מבוססת רכיבים בצד השרת. במקור הוא פותח כחלק מ- JE של ג'קרטה. במדריך זה, נבדוק כיצד ניתן לשלב JSF ביישום Spring Boot.

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

2. תלות Maven

עלינו להאריך את שלנו pom.xml להשתמש בטכנולוגיות JSF:

 org.apache.tomcat.embed tomcat-embed-jasper org.glassfish javax.faces 2.3.7 

ה javax.faces חפץ מכיל גם את ממשקי ה- API של JSF ואת היישומים. מידע מפורט ניתן למצוא כאן.

3. קביעת התצורה של סרוולט JSF

מסגרת JSF משתמשת בקבצי XHTML לתיאור התוכן והמבנה של ממשק המשתמש. צד השרת מייצר את קבצי JSF מתיאורי XHTML.

נתחיל ביצירת מבנה סטטי ב- index.xhtml קובץ ב- src / main / webapp מַדרִיך:

    יישום TO-DO 

ברוך הבא ביישום ה- TO-DO!

זוהי הודעה סטטית שניתנה מ- xhtml.

התוכן יהיה זמין בכתובת /index.jsf. אמנם, אנו מקבלים הודעת שגיאה בצד הלקוח אם אנו מנסים להגיע לתוכן בשלב זה:

אירעה שגיאה לא צפויה (סוג = לא נמצא, סטטוס = 404). אין הודעה זמינה

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

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

@SpringBootApplication מחלקה ציבורית JsfApplication מרחיב את SpringBootServletInitializer {main public static void (String [] args) {SpringApplication.run (JsfApplication.class, args); } @Bean ServletRegistration הציבורי Bean servletRegistrationBean () {FacesServlet servlet = FacesServlet new (); ServletRegistrationBean servletRegistrationBean = ServletRegistrationBean חדש (servlet, "* .jsf"); להחזיר servletRegistrationBean; }}

זה נראה נהדר ודי סביר אך לצערנו עדיין לא מספיק טוב. כשאנחנו מנסים לפתוח /index.jsf עכשיו נקבל שגיאה נוספת:

java.lang.IllegalStateException: לא ניתן למצוא גיבוי עבור javax.faces.context.FacesContextFactory מהמפעל.

למרבה הצער, אנו זקוקים ל web.xml לצד תצורת Java. בואו ניצור את זה ב src / webapp / WEB-INF:

 Faces Servlet javax.faces.webapp.FacesServlet 1 Faces Servlet * .jsf 

כעת, התצורה שלנו מוכנה לצאת לדרך. לִפְתוֹחַ /index.jsf:

ברוך הבא ביישום ה- TO-DO! זוהי הודעה סטטית שניתנה מ- xhtml.

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

4. יישום דפוס ה- DAO

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

כדי ליישם את דפוס ה- DAO, נגדיר תחילה ממשק כללי:

ממשק ציבורי Dao {אופציונלי לקבל (int id); אוסף getAll (); int שמירה (T t); עדכון ריק (T t); מחיקה בטלה (T t); }

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

כיתה ציבורית Todo {מזהה פרטי פרטי; הודעת מחרוזת פרטית; עדיפות אינטנסיבית פרטית; // סטרים וקובעים סטנדרטיים}

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

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

לדוגמא שלנו, נשתמש בכיתת אחסון בזיכרון:

מחלקה ציבורית @Component TodoDao מיישמת את Dao {רשימה פרטית todoList = ArrayList חדש (); @ Override public אופציונלי get (int id) {return Optional.ofNullable (todoList.get (id)); } @Override אוסף ציבורי getAll () {return todoList.stream () .filter (Objects :: nonNull) .collect (Collectors.collectingAndThen (Collectors.toList (), Collections :: unmodifiableList)); } @Override public int save (Todo todo) {todoList.add (todo); אינדקס int = todoList.size () - 1; todo.setId (אינדקס); מדד תשואה; } @ העבר עדכון חלל ציבורי (Todo todo) {todoList.set (todo.getId (), todo); } מחיקת בטל ציבורי @ עקוף (Todo todo) {todoList.set (todo.getId (), null); }}

5. שכבת השירות

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

שים לב שממשק DAO יופנה מהשירות:

@Scope (value = "session") @ Component (value = "todoService") מעמד ציבורי TodoService {@ Dao todoDao פרטי פרטי; טודו טודו פרטי = טודו חדש (); בטל פומבי שמור () {todoDao.save (todo); טודו = טודו חדש (); } אוסף ציבורי getAllTodo () {חזור todoDao.getAll (); } public int saveTodo (Todo todo) {validate (todo); חזור todoDao.save (todo); } אימות בטל פרטי (Todo todo) {// פרטים הושמטו} Public Todo getTodo () {return todo; }}

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

כמו כן, לשיעור זה יש היקף מושב שיהיה מספק עבור יישום פשוט זה.

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

הנחיות נוספות בנושא זמינות במדריך זה.

6. הבקר

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

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

@Scope (value = "session") @ Component (value = "jsfController") מחלקה ציבורית JsfController {public מחרוזת loadTodoPage () {checkPermission (); החזר "/todo.xhtml"; } check void checkPermission () {// פרטים הושמטו}}

הניווט מבוסס על השם שהוחזר. מכאן loadTodoPage ישלח אותנו אל todo.xhtml דף אותו נבצע בהמשך.

7. חיבור JSF ושעועית אביב

בואו נראה כיצד נוכל להתייחס לרכיבים שלנו מהקשר JSF. ראשית, נאריך את index.xthml:

  // אותו קוד כמו קודם // אותו קוד כמו קודם 

כאן הצגנו א commandButton בתוך אלמנט צורה. זה חשוב מאז כל UIC פיקוד אלמנט (למשל commandButton)צריך להיות ממוקם בתוך א UIForm אלמנט (למשל צורה).

בשלב זה אנו יכולים להתחיל את בקשתנו ולבחון אותה /index.jsf:

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

אירעה שגיאה לא צפויה (סוג = שגיאת שרת פנימית, סטטוס = 500). javax.el.PropertyNotFoundException: /index.xhtml @ 11,104 action = "# {jsfController.loadTodoPage}": יעד שאינו ניתן להשגה, מזהה [jsfController] נפתר לאפס

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

במצב זה האחרון נכון.

עלינו לחבר את הקשר האביבי עם JSF הקשר בתוך webapp / WEB-INF / faces-config.xml:

   org.springframework.web.jsf.el.SpringBeanFacesELResolver 

עכשיו כשהבקר שלנו מוכן לעבוד נצטרך את todo.xhtml!

8. אינטראקציה עם שירות מאת JSF

שֶׁלָנוּ todo.xhtml לדף יהיו שתי מטרות. ראשית, הוא יציג את כל מרכיבי המטלות.

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

לשם כך, רכיב ממשק המשתמש יתקשר ישירות עם השירות שהוכרז קודם לכן:

    יישום TO-DO רשימת פריטי TO-DO הודעה מס '{item.message} Priority # {item.priority} הוסף פריט מטלה חדש: 

שתי המטרות שהוזכרו לעיל מיושמות בשתי נפרדות div אלמנטים.

בראשון השתמשנו ב- טבלת נתונים אלמנט לייצג את כל הערכים ממנו todoService.AllTodo.

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

אנו משתמשים ב- הקלד טקסט אלמנט לקבל קלט משתמש, כאשר הקלט השני מומר אוטומטית ל- int. עם ה commandButton, המשתמש יכול להתמיד (בזיכרון עכשיו) את לעשות חפץ עם todoService.save.

9. מסקנה

ניתן לשלב את מסגרת ה- JSF במסגרת האביב. עליכם לבחור איזו מסגרת תנהל את השעועית. במדריך זה השתמשנו במסגרת האביב.

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

כמו תמיד, הקוד זמין ב- GitHub.