مقدمة
التقنيات المستخدمة
تحليل المتطلبات
نموذج البيانات
بنية التطبيق
طبقة البيانات
وحدات التحكم
معالجات العمل
وجهات النظر
المرشحات
نتائج
تطبيق الويب القائم على Java لأنشطة TODO. من خلال تطبيق الويب هذا ، يمكن للمرء إنشاء وقراءة وتحديث Todos من خلال متصفح الويب الحديث. ينفذ التطبيق أيضًا AAA ، مما يعني أن كل مستخدم لديه حساب خاص به وقائمة Tode الخاصة بهم وما إلى ذلك.
هذا الوثيقة ليست للمبتدئين. يجب أن تمتلك معرفة جيدة بالتقنيات أدناه لفهم هذا المستند والتطبيق ذي الصلة:
جافا
Servlet ، JSP
أباتشي تومكات
MySQL
HTML
Apache Netbeans IDE
Firefox
هذا هو مشروع خلفي تماما. لذلك ، لا يتم استخدام التقنيات الأمامية مثل CSS ، JavaScript. الهدف من المشروع هو تعلم وإظهار كيفية عمل قطع مختلفة من واجهة برمجة تطبيقات Java Servlet معًا.
يجب علينا تطوير تطبيق الويب بدءًا من تحليل المتطلبات. ثم سننتقل إلى تصميم قاعدة البيانات. البيانات أساسية لأي تطبيق ويب. تقريبا جميع حالات الاستخدام تتعامل مع البيانات. بمجرد أن يصبح نموذج بيانات تطبيق الويب جاهزًا ، سننتقل بعد ذلك لتصميم بنية التطبيق. في هذه المرحلة ، سنرى كيف يتصرف تطبيقنا إلى إجراءات HTTP المختلفة. لأن جميع الإجراءات التي يقوم بها مستخدمو التطبيق هي من خلال HTTP. يجب أن نفكر في جميع تصرفات المستخدم الممكنة وتحديدها بوضوح. بعد ذلك ، سننتقل إلى تصميم الواجهات والفصول.
لتطبيقنا ، نبدأ بتحديد ما هو بالنسبة لنا. TODO هي مهمة يجب إنجازها. نقوم بإنشاء قائمة بهذه المهام لمساعدتنا على العيش حياة prdocutive. نستمر في تتبع القائمة عندما نحصل على المهام واحدة تلو الأخرى. عنصر TODO بالنسبة لنا له خصائص أدناه:
في البداية ، سيكون للمهمة حالة "TODO". عندما نبدأ العمل عليها ، نغيره إلى "في التقدم". بمجرد إنجاز المهمة ، نضع علامة على وضعها على أنه "تم".
نريد أن يدعم تطبيقنا أيضًا عدة مستخدمين. ويجب أن يكون لكل مستخدم قائمة خاصة به. وبالتالي ، لا يمكن للمستخدمين رؤية قائمة الآخرين. يجب تحديد المستخدم بواسطة اسم المستخدم الخاص بهم ، وهو عنوان بريده الإلكتروني الصحيح بالنسبة لنا. يتم منح المستخدمين حسابات على تطبيقنا. وبالتالي ، فإن الحساب أدناه خصائص:
نريد حساب "المسؤول" لإدارة الحسابات فقط. يجب أن يستخدم حساب المسؤول اسم المستخدم "المسؤول". يمكن لمستخدم المسؤول:
العنصران الأخيران يستحقون مراقبة. عادة ، يُعتقد أن المستخدم الذي يحمل حقوق "المسؤول" لديه حق الوصول إلى معلومات الجميع. نحن لا نريد هذا. أيضًا ، لقد حددنا بالفعل أن حساب "المسؤول" بالنسبة لنا هو فقط لإدارة الحسابات. إنه ليس لإدارة قوائم المستخدمين. لا يتم استخدام حساب المستخدم "المسؤول" في كثير من الأحيان. هو المقصود فقط لأغراض خاصة. لتطبيقنا ، نتوقع أن يتعامل حساب مستخدم واحد أيضًا مع حساب "المسؤول". لذلك ، سيكون نفس الشخص الذي يسجل استخدام بيانات الاعتماد "المسؤول" فقط عند الاقتضاء. نظرًا لأنه حساب مستخدم حالي يستخدم حساب "المسؤول" فقط لإدارة جميع الحسابات ، لا نريد قائمة مهام منفصلة لحساب المسؤول. هذا لا يخدم أي غرض.
نريد أن تستمر قوائم TODO دائمًا. مما يعني أنه بمجرد إنشاء عنصر TODO بنجاح من قبل المستخدم ، لا يمكن حذفه أبدًا. وبالمثل ، لا نريد أيضًا حذف حساب المستخدم. في الختام ، لا نريد دعم عمليات "حذف" في تطبيقنا. وبالتالي ، نحن ندعم فقط CRU من CRUD.
لأننا نريد أن يحافظ تطبيقنا على قوائم TOD الخاصة ، نريد أن يوفر التطبيق آليات تسجيل الدخول والتسجيل. وهذا ما يسمى "المصادقة". يجب على كل مستخدم ، بما في ذلك "المسؤول" ، المصادقة على نفسه أولاً. عند المصادقة الناجحة ، سيتم إعادة توجيه المستخدم إلى مساحة عمله. نظرًا لأننا نناقش نوعين من المستخدمين (مسؤول واحد والآخر طبيعي) ، يجب أن يكون لدينا نوعان من مساحات العمل في تطبيقنا. يجب أن يعمل مستخدم المسؤول فقط مع مساحة عمل إدارة حساب المستخدم. يجب أن يعمل المستخدم العادي فقط مع مساحة عمل إدارة قائمة TODO. كلاهما حصري. لا يمكن للمستخدم العادي رؤية مساحة عمل المسؤول. ولا يمكن لمستخدم المسؤول رؤية مساحة عمل المستخدم العادية. وهذا ما يسمى "إذن".
بالإضافة إلى المتطلبات المذكورة أعلاه ، نريد تطبيقنا لتخزين تفاصيل تسجيل الدخول إلى المستخدمين ومواد تسجيل الدخول. من خلال هذا ، نقوم بتتبع نشاط المستخدمين على تطبيقنا. هذا ليس بالضبط "محاسبة" من AAA ، ولكن لتطبيقنا ، هذا يخدم الغرض من تسميته بأنه "محاسبة".
بناءً على المتطلبات التي جمعناها حتى الآن ، نتفهم أنه يتعين علينا تخزين البيانات للكيانات أدناه للتطبيق:
مثال على البيانات لعدد قليل من الحسابات:
| معرف الحساب | اسم المستخدم | الاسم الأول | اسم العائلة | كلمة المرور | تم إنشاؤها في | حالة |
|---|---|---|---|---|---|---|
| 1 | مسؤل | المسؤول | مستخدم | كلمة المرور | 2020-05-06 17:34:04 | تمكين |
| 2 | [email protected] | جون | جونسون | كلمة واحدة | 2020-05-07 12:34:04 | عاجز |
| 3 | [email protected] | إريك | إريكسون | Twoword | 2020-05-08 13:34:04 | تمكين |
| 4 | [email protected] | آنا | ماري | threword | 2020-05-09 11:34:04 | تمكين |
نرى أن حالات الحساب تتكرر في جميع أنحاء الجدول. لذلك ، كجزء من تطبيع قاعدة البيانات ، من الأفضل وضع البيانات المتكررة في جدول منفصل. هناك سبب وجيه وراء. دعنا نقول ، لدينا 100 مستخدم. ونريد استبدال الكلمات الممكّنة والتعطيل بـ 1 و 2 على التوالي. علينا تعديل عمود الحالة لجميع صفوف الجدول. تخيل كيف سيكون الأمر مرهقًا للقيام بمثل هذا التعديل لجدول مع آلاف الصفوف! تطبيع قاعدة البيانات في الإنقاذ ، والحمد لله!
بعد التطبيع ، يجب أن يكون لدينا جدولين - حساب - statuses وحسابات:
account_statuses
| بطاقة تعريف | حالة |
|---|---|
| 1 | تمكين |
| 2 | عاجز |
حسابات
| معرف الحساب | اسم المستخدم | الاسم الأول | اسم العائلة | كلمة المرور | معرف الحالة |
|---|---|---|---|---|---|
| 1 | مسؤل | المسؤول | مستخدم | كلمة المرور | 1 |
| 2 | [email protected] | جون | جونسون | كلمة واحدة | 2 |
| 3 | [email protected] | إريك | إريكسون | Twoword | 1 |
| 4 | [email protected] | آنا | ماري | threword | 2 |
وبالمثل ، سيكون لدينا ثلاثة جداول للمهام - Task_Statuses ، Task_Priorities والمهام:
Task_statuses
| بطاقة تعريف | حالة |
|---|---|
| 1 | تودو |
| 2 | في تَقَدم |
| 3 | منتهي |
Task_Priorities
| بطاقة تعريف | أولوية |
|---|---|
| 1 | مهم وعاجل |
| 2 | مهم ولكن ليس عاجل |
| 3 | ليست مهمة ولكن عاجلة |
| 4 | ليست مهمة وليست عاجلة |
المهام
| معرف المهمة | معرف الحساب | تفاصيل | تم إنشاؤها في | موعد التسليم | آخر تحديث | معرف الحالة | معرف الأولوية |
|---|---|---|---|---|---|---|---|
| 1 | 2 | شراء أقلام الرصاص. | 2019-05-06 17:40:03 | 2019-05-07 17:40:03 | 2 | 1 | |
| 2 | 3 | شراء الكتب. | 2019-05-07 7:40:03 | 2019-05-07 17:40:03 | 2019-05-07 23:40:03 | 2 | 1 |
أخيرًا ، لدينا أيضًا شرط آخر لتخزين بيانات جلسة الحساب. يجب أن نقوم بتخزينه كما هو موضح في الجدول أدناه:
account_sessions
| معرف الجلسة | معرف الحساب | جلسة تم إنشاؤها | نهاية الجلسة |
|---|---|---|---|
| ASD1GH | 1 | 2019-05-06 17:40:03 | 2019-05-06 18:00:03 |
عادة ، لا يتم تخزين معرفات تطبيقات المؤسسات كمناسبات صحيحة. لأنه سيكون من الأسهل على شخص ما الاستعلام عن معلومات الآخرين عن طريق استخدام عدد صحيح! في تطبيقات العالم الحقيقي ، لا تكون IDS رقمية بل أبجديًا رقميًا ، حيث تصل إلى 100 حرف. وبالتالي ، مما يجعل من المستحيل على شخص تخمين معرف آخر!
يجب أن نسمي قاعدة البيانات الخاصة بنا باسم "TODO" في MySQL. وإليك نموذج البيانات المدمج بناءً على المعلومات أعلاه:

سنقوم بتطوير هذا التطبيق بعد نمط MVC 2 الشهير والمستخدم على نطاق واسع. يوضح الشكل أدناه كيف سنقوم بتنفيذ MVC لتطبيقنا: 
سيكون تطبيقنا قائمًا على الإجراء. عندما يرسل المستخدم طلب HTTP إلى تطبيقنا ، نترجمه إلى الإجراء المقابل في تطبيقنا. الإجراءات التي ندعمها هي إنشاء وقراءة وتحديث (CRU). تطبيقنا هو أساسا مدفوعة البيانات. إنه يسهل الإجراءات على قاعدة البيانات. يساعد المستخدمين على تخزين وإدارة بياناتهم على قاعدة بيانات عن بُعد بأمان وأمان بمساعدة آليات المصادقة والتفويض. يعمل كواجهة قائمة على HTML و HTTP إلى قاعدة البيانات.
عندما يقدم المستخدم طلب HTTP إلى تطبيقنا ، نرسل البيانات المطلوبة مرة أخرى في شكل HTML. تدعم HTML الروابط والنماذج لمساعدة المستخدمين على التفاعل مع تطبيقات الويب. يتم استخدام الروابط لاسترداد/الحصول على (HTTP GET) ، بينما يتم استخدام النماذج لنشر البيانات (POST HTTP) إلى تطبيق الويب.
لذا ، إليك كيفية ترجمة طلبات HTTP إلى الإجراءات:
| عنصر HTML | طريقة HTTP | إجراء التطبيق |
|---|---|---|
| ارتباط تشعبي | HTTP الحصول على | اقرأ التفاصيل |
| استمارة | HTTP Post | إنشاء أو تحديث |
HTTP GET يرسل البيانات كمعلمات استعلام إلى عنوان URL. بينما ، يرسل HTTP Post البيانات في هيئة طلب HTTP. لا يكشف Post HTTP عن البيانات من خلال عنوان URL ، في حين أن HTTP GET لا. لذلك ، HTTP GET غير مناسب لإرسال بيانات اعتماد تسجيل الدخول. لا أحد يريد أن يرى اسم المستخدم وكلمة المرور الخاصة بهما على عنوان URL طلب HTTP! يجب أن نستخدم منشور HTTP لإرسال بيانات اعتماد المستخدم أثناء تسجيل الدخول.
لذلك ، قررنا كيف سنستخدم HTTP و HTML وقاعدة بيانات. هناك مفهوم آخر لـ HTTP ضروري بالنسبة لنا لفهم أن نقرر بنية تطبيق HTTP القائم. هذا هو عنوان URL - محدد الموارد الموحد. إليك مثال عنوان URL لتطبيق الويب يسمى "WebApp" المستضافة على خادم example.com:
http://www.example.com/webapp/details?id=12
في المثال أعلاه عنوان URL ، "HTTP" هو البروتوكول ، www.example.com هو اسم المجال أو اسم الخادم ، "WebApp" هو سياق التطبيق الذي تم نشره على الخادم و "التفاصيل" هو التطبيق الذي نرسله طلب HTTP الخاص بنا. "ID" هي معلمة الاستعلام التي ننتقل إليها إلى "التفاصيل" بقيمة "12". توفر لنا معلمات الاستعلام آلية لتمرير المعلمات إلى تطبيق الويب واستلام المحتوى ذي الصلة مرة أخرى استجابة من تطبيق الويب. على سبيل المثال ، تخيل تطبيق الطقس الذي يعمل على خادم ويب. بدلاً من تزويدنا بقائمة تقارير الطقس لجميع المواقع ، يمكننا إرسال اختيارنا للموقع كمعلمة استعلام إلى تطبيق الويب. ثم يرسل التطبيق رداً على تفاصيل الطقس لاختيارنا للموقع.
يعمل تطبيق الويب على خادم الويب ، على عكس التطبيقات التي يتم تشغيلها على أجهزة الكمبيوتر الخاصة بنا. يسمى تطبيق Java الذي يعمل على خادم الويب كخدمة. Servlets محاكاة تطبيقات الويب. يركضون داخل حاوية. Apache Tomcat هو مثال شائع لمثل هذه الحاوية. يقوم برنامج الحاوية بترجمة طلبات RAW HTTP والاستجابات إلى كائنات Java ويوفرها لـ Servlets. يخدم موقع ويب ثابت نفس المحتوى لكل طلب HTTP. ولكن ، يمكن لـ Servlet إنشاء محتوى ديناميكي متميز لكل طلب HTTP المقدم.
سيحتوي تطبيق TODO Web الذي نقوم ببنائه على أجزاء متعددة - Servlets ، المرشحات ، ملفات JSP ، فئات قاعدة البيانات ، Pojos ، إلخ. سنضعها جميعًا (مثل تجميعها) تحت سياق تطبيق واحد (أو بيئة تطبيق) على الحاوية (Tomcat). يجب أن نسمي سياق التطبيق هذا باسم "TODO". لذلك ، إذا قمنا بتشغيل tomcat على جهاز الكمبيوتر الخاص بنا في المنفذ 8080 ، فيمكن الوصول إلى سياق التطبيق الخاص بنا "TODO" من خلال عنوان URL:
http://localhost:8080/todo/
تتكون طبقة البيانات الخاصة بنا من تنفيذ نمط DAO ونمط المصنع على رأس DataSource JDBC. نختار JDBC DataSource بدلاً من Drivermanager لأننا نريد جني فوائد تجميع الاتصال.
لدينا فقط servlet واحد بمثابة وحدة تحكم ، تسمى "الرئيسية". طلب HTTP الخاص بالمستخدم هو إجراء بالنسبة لنا. لذلك ، فإن الغرض من وحدة التحكم الخاصة بنا هو مجرد اختيار إجراء مناسب لطلب HTTP المقدم. يختار Servlet وحدة التحكم معالج الإجراء ويسلمه على الطلب الذي قدمه المستخدم. نحن لا نكتب خطوات تنفيذ الإجراء في وحدة التحكم الخاصة بنا. نبقيها نظيفة وليهين. الغرض منه هو "اختيار" معالج العمل. عدم "تنفيذ" الإجراء في حد ذاته. بعد تنفيذ معالج الإجراء الإجراء المطلوب ، يتلقى وحدة التحكم "الخطوة التالية" التي سيتم تنفيذها كرد على معالج الإجراء. تتمثل وظيفة وحدة التحكم في اختيار المورد الذي يؤدي الاستجابة المطلوبة. في الختام ، نحافظ على وحدة التحكم الخاصة بنا بعيدًا عن كل منطق العمل.
يجب أن نرسم خريطة وحدة التحكم الخاصة بنا إلى نمط URI /app/* . لذلك ، سوف يتعامل Servlet وحدة التحكم لدينا مع كل URI يتبع النمط /app/ .
الإجراء الذي يطلبه المستخدم هو منطق العمل لتطبيقنا. معالجات الإجراءات هي النموذج في تطبيق MVC الخاص بنا. كل إجراء يجب أن ينفذ واجهة العمل:
public interface Action {
/*
An action is supposed to execute and return results. ActionResponse represents the response.
*/
public abstract ActionResponse execute ( HttpServletRequest request , HttpServletResponse response )
throws Exception ;
}من المفترض أن يقوم الإجراء بتنفيذ نتائج وإرجاعها. نقوم بإنشاء فئة خاصة لمثل هذه النتيجة - ActionResponse. يمكن لمعالج الإجراء اختيار "إعادة التوجيه" أو "إعادة التوجيه".
public class ActionResponse {
private String method ;
private String viewPath ;
public ActionResponse () {
this . method = "" ;
this . viewPath = "" ;
}
public void setMethod ( String method ) {
this . method = method ;
}
public String getMethod () {
return this . method ;
}
public void setViewPath ( String viewPath ) {
this . viewPath = viewPath ;
}
public String getViewPath () {
return this . viewPath ;
}
@ Override
public String toString () {
return this . getClass (). getName ()+ "[" + this . method + ":" + this . viewPath + "]" ;
}
}ننفذ نمط تصميم المصنع. نقوم بإنشاء فئة مصنع - ActionFactory - لنعطينا فئة معالج الإجراءات التي نطلبها:
public class ActionFactory {
private static Map < String , Action > actions = new HashMap < String , Action >() {
{
put ( new String ( "POST/login" ), new LoginAction ());
put ( new String ( "GET/login" ), new LoginAction ());
put ( new String ( "GET/logout" ), new LogoutAction ());
put ( new String ( "GET/admin/accounts/dashboard" ), new AdminAccountsDashboardAction ());
put ( new String ( "GET/admin/accounts/new" ), new AdminNewAccountFormAction ());
put ( new String ( "POST/admin/accounts/create" ), new AdminCreateAccountAction ());
put ( new String ( "GET/admin/accounts/details" ), new AdminReadAccountDetailsAction ());
put ( new String ( "POST/admin/accounts/update" ), new AdminUpdateAccountAction ());
put ( new String ( "GET/tasks/dashboard" ), new UserTasksDashboardAction ());
put ( new String ( "GET/tasks/new" ), new UserNewTaskFormAction ());
put ( new String ( "GET/tasks/details" ), new UserReadTaskDetailsAction ());
put ( new String ( "POST/tasks/create" ), new UserCreateTaskAction ());
put ( new String ( "POST/tasks/update" ), new UserUpdateTaskAction ());
put ( new String ( "GET/users/profile" ), new UserReadProfileAction ());
put ( new String ( "POST/users/update" ), new UserUpdateProfileAction ());
}
;
};
public static Action getAction ( HttpServletRequest request ) {
Action action = actions . get ( request . getMethod () + request . getPathInfo ());
if ( action == null ) {
return new UnknownAction ();
} else {
return action ;
}
}
}الغرض من جهاز التحكم الخاص بنا هو:
protected void processRequest ( HttpServletRequest request , HttpServletResponse response )
throws ServletException , IOException {
Action action = ActionFactory . getAction ( request );
try {
ActionResponse actionResponse = action . execute ( request , response );
if ( actionResponse . getMethod (). equalsIgnoreCase ( "forward" )) {
System . out . println ( this . getClass (). getCanonicalName () + ":forward:" + actionResponse );
this . getServletContext (). getRequestDispatcher ( actionResponse . getViewPath ()). forward ( request , response );
} else if ( actionResponse . getMethod (). equalsIgnoreCase ( "redirect" )) {
System . out . println ( this . getClass (). getCanonicalName () + ":redirect:" + actionResponse );
if ( actionResponse . getViewPath (). equals ( request . getContextPath ())) {
response . setHeader ( "Cache-Control" , "no-cache, no-store, must-revalidate" );
response . setHeader ( "Pragma" , "no-cache" );
response . setDateHeader ( "Expires" , 0 );
}
response . sendRedirect ( actionResponse . getViewPath ());
} else if ( actionResponse . getMethod (). equalsIgnoreCase ( "error" )) {
System . out . println ( this . getClass (). getCanonicalName () + ":error:" + actionResponse );
response . sendError ( 401 );
} else {
System . out . println ( this . getClass (). getCanonicalName () + ":" + actionResponse );
response . sendRedirect ( request . getContextPath ());
}
} catch ( Exception e ) {
e . printStackTrace ();
}
} يعرض الجدول أدناه قائمة طلبات HTTP التي يستجيب لتطبيقنا ومعالجات الإجراءات المرتبطة بها:
| الإجراء المقصود للمستخدم | طلب HTTP URI | معالج العمل |
|---|---|---|
| إرسال بيانات اعتماد تسجيل الدخول الفارغة | GET /app/login | تسجيل الدخول |
| إرسال بيانات اعتماد تسجيل الدخول | POST /app/login | تسجيل الدخول |
| احصل على لوحة معلومات الحسابات | GET /app/admin/accounts/dashboard | adminAccountSdashboardAction |
| احصل على نموذج حساب جديد | GET /app/admin/accounts/new | AdminNewAccouptFormAction |
| إرسال تفاصيل الحساب الجديدة | POST /app/admin/accounts/create | admincreateacCountAction |
| احصل على تفاصيل حساب | GET /app/admin/accounts/details?id=xx | adminreadAccountDetailsaction |
| تحديث تفاصيل الحساب | POST /app/admin/accounts/update | adminupdateaccountAction |
| الحصول على المهام لوحة القيادة | GET /app/tasks/dashboard | USERTASKSDASHBOARDACTION |
| احصل على نموذج مهمة جديد | GET /app/tasks/new | usernewtaskFormAction |
| إرسال تفاصيل المهمة الجديدة | POST /app/tasks/create | userCreateTAskAction |
| احصل على تفاصيل المهمة | GET /app/tasks/details?id=xx | UserreadTaskDetailsaction |
| تحديث تفاصيل المهمة | POST /app/tasks/update | userupDateTaskAction |
| احصل على تفاصيل ملف التعريف الخاص بي | GET /app/users/profile | UserreadProfileAction |
| تحديث تفاصيل ملف التعريف الخاص بي | POST /app/users/update | userupDateProfileAction |
| تسجيل الخروج | GET /app/logout | تسجيل الدخول |
تتمثل مهمة معالج الإجراء في تنفيذ منطق العمل واختيار مكون العرض المناسب كرد فعل للطلب الذي قدمه المستخدم. يوضح الجدول أدناه جميع معالجات الإجراءات ومكونات العرض الخاصة بهم:
| معالج العمل | عرض المكون |
|---|---|
| تسجيل الدخول | /WEB-INF/pages/admin/accounts/dashboard.jsp/WEB-INF/pages/tasks/dashboard.jsp |
| adminAccountSdashboardAction | /WEB-INF/pages/admin/accounts/dashboard.jsp |
| AdminNewAccouptFormAction | /WEB-INF/pages/admin/accounts/newAccount.jsp |
| admincreateacCountAction | /WEB-INF/pages/admin/accounts/createAccountResult.jsp |
| adminreadAccountDetailsaction | /WEB-INF/pages/admin/accounts/accountDetails.jsp |
| adminupdateaccountAction | /WEB-INF/pages/admin/accounts/updateAccountResult.jsp |
| USERTASKSDASHBOARDACTION | /WEB-INF/pages/tasks/dashboard.jsp |
| usernewtaskFormAction | /WEB-INF/pages/tasks/newTask.jsp |
| userCreateTAskAction | /WEB-INF/pages/tasks/createTaskResult.jsp |
| UserreadTaskDetailsaction | /WEB-INF/pages/tasks/taskDetails.jsp |
| userupDateTaskAction | /WEB-INF/pages/tasks/updateTaskResult.jsp |
| UserreadProfileAction | /WEB-INF/pages/users/viewProfile.jsp |
| userupDateProfileAction | /WEB-INF/pages/users/updateProfileResult.jsp |
| غير معروف | /WEB-INF/pages/users/unknownAction.jsp |
يقوم مكون العرض بإنشاء استجابة HTML المطلوبة التي سيتم إرسالها إلى المستخدم. يُقرأ عرض المكون الرسائل المحددة بواسطة معالج الإجراء ويعرضها للمستخدم.
نستخدم المرشحات لاعتراض طلبات HTTP الواردة. سيتم استخدام جميع المرشحات قبل تمرير الطلب إلى Servlet وحدة التحكم. سيتم التعامل مع أي طلب HTTP الوارد أولاً بواسطة مرشح المصادقة. من خلال هذا المرشح ، نتحقق مما إذا كان المستخدم قد تم تسجيل الدخول بالفعل أم لا. إذا لم يتم تسجيل الدخول ، فإننا نعيد توجيه المستخدم إلى صفحة تسجيل الدخول. بعد المرور بنجاح من خلال مرشح المصادقة ، سيتم اعتراض طلب HTTP بواسطة مرشحين آخرين. في هذه المرشحات ، نتحقق من مسار URI والمستخدم هو "المسؤول" أو المستخدم العادي. إذا كان المستخدم العادي يحاول الوصول إلى مسارات URI "المسؤول" ، فإننا نمنع هذا الوصول. إذا كان مستخدم "المسؤول" يحاول الوصول إلى مسارات URI ذات الصلة بالمهام ، فإننا نمنع هذا الوصول.
يمكن فقط لـ "المسؤول" الوصول إلى URIs بدءًا من /app/admin/* ويمكن للمستخدم العادي فقط الوصول إلى URIs بدءًا من /app/tasks/* . يمكن الوصول إلى URIS /app/login الأخرى ، /app/logout ، /app/users/* من قبل كليهما.
نحن لا نعترض الردود التي نرسلها.
لذلك ، إليك كيف يبدو تطبيقنا. لقد حافظت على واجهة المستخدم للبساطة. لا يوجد CSS أو JavaScript.










