بنية Struts2
1. لماذا تستخدم الأطر؟
(1) يكمل الإطار تلقائيًا العديد من المهام التافهة
بالنسبة إلى Struts2 ، فإنه يساعدنا بسهولة على إكمال تحويل نوع البيانات ، والتحقق من البيانات ، والتدويل ، إلخ.
المهام الشائعة في تطوير الويب. هناك أيضًا أوضاع القالب التي تستخدم على نطاق واسع في الربيع ، والتي تجعل جميع عملية التطوير أكثر تلقائيًا وذكاء. استخدام إطار عمل هو تجنب إعادة اختراع العجلة وإعادة نسخة رموز القالب هذه.
يتيح لنا Framework التركيز أكثر على المشكلات ذات المستوى الأعلى أكثر من مهام سير العمل المشتركة والمهام الأساسية.
(2) أن استخدام إطار يعني وراثة بنية بنية خلف الإطار بأمان
عادةً ما تحدد الهندسة المعمارية وراء الإطار سلسلة من مهام سير العمل. ما يتعين علينا القيام به هو إرفاق رمز تطبيق معين بهذه العملية ، حتى نتمكن من الاستمتاع بالمزايا المختلفة التي تقدمها الإطار. في بعض الأحيان ، يمكننا أيضًا مقاومة القواعد المعمارية للإطار ، لكن الإطار عادة ما يوفر بنيةه بطريقة يصعب رفضها. إنه أمر بسيط للغاية بحيث يمكنك أن ترث بنية ممتازة بأمان وهي مجانية ، فلماذا لا تفعل ذلك؟
(3) من الأسهل العثور على أشخاص مدربين جيدًا باستخدام الإطار
لم أستخدم أي أطر عمل تقريبًا في المشروع بأكمله لشركتي من قبل ، والبحث عن خدمات الخدمة (على غرار JNDI)
لتسجيل الطباعة (على غرار log4j) ، ثم إلى تجمع اتصال قاعدة البيانات (على غرار DBCP) ، يتم تنفيذها جميعها من قبل الموظفين الداخليين أنفسهم. أولاً ، لأن المشروع قديم نسبيًا ، وقد لا يكون هناك أي إطار مفتوح المصدر للاستخدام في ذلك الوقت. ثانياً ، بسبب الإستراتيجية المحافظة للشركة ، ومن القلق من أن استخدام إطار مصادر مفتوح غير مستقر قد يؤدي إلى مخاطر على المشروع. قد يكون هذا صحيحًا في البيئة في ذلك الوقت ، وستنظر الإدارة العليا للشركة بشكل طبيعي في المشروع بأكمله من منظور أكبر.
ومع ذلك ، عندما يصبح المشروع تدريجياً أكبر ، وهناك المزيد والمزيد من أطر عمل مفتوح المصدر الممتازة في العالم ، إذا لم يكن من الممكن إعادة تمثيل بعض الأطر الناضجة مفتوحة المصدر في الوقت المناسب وتقديمها ، فقد تكون النتيجة النهائية هي أن المطورين المعينين حديثًا يجب أن يتعلموا هذا النظام المعقد من نقطة الصفر (جميع الأنظمة الداخلية ، ولا توجد مساعدة على الإنترنت) ، وأن يكونوا على حدة في الحشرات المختلفة في الإطار الداخلي.
التكلفة مرتفعة للغاية.
(4) لا يمكن للإطار الداخلي مواكبة تطوير الصناعة
الخطأ في الإطار الداخلي المذكور سابقًا. بالنسبة لأطر المصادر المفتوحة ، قد يكون هناك فريق من مؤسسي الإطارات ، وهو عدد كبير من عشاق المصادر المفتوحة ،
مجتمع مفتوح المصدر لدعمه. قوة الناس لا حصر لها ، ويمكن تخيل سرعة إصلاح الأخطاء. هذا من المصدر المفتوح الأخير
يمكن رؤية عملية إصلاح الأخطاء من TextMate. تم حل العديد من الأخطاء التي تم تعليقها لفترة طويلة من قبل المتحمسين بعد أن تكون مفتوحة المصدر ، ولكن ماذا عن الإطار الداخلي؟ بعد أن غادر الأشخاص الذين طوروه الشركة ، لم يقرأ أحد رمز المصدر الخاص به دون أخطاء كبيرة. الفجوة واضحة!
(5) بالطبع ، فإن استخدام إطار عمل ليس ربحًا كبيرًا.
كما ذكرنا سابقًا ، يعد استخدام إطار غير ناضج محفوفًا بالمخاطر ، ومن الأفضل أن تكون محافظًا لمشروع غير جذري للغاية.
(ما لم تكن هذه مجموعة من المتعصبين الفنيين المجانيين وغير المقيدين الذين يمكنهم تحديد إطار العمل الذي يجب استخدامه وفقًا لتقديرهم ، فهذه حقًا نعمة)
تمامًا مثل Sequioa ، خدمة Java Ha عالية التوفر التي استخدمتها من قبل ، لم يعد هذا الإطار مدعومًا من قبل شركة التطوير ، والمخاطر أكبر.
بالإضافة إلى ذلك ، عند استخدام بعض الأطر غير المألوفة ، يجب عليك أيضًا الانتباه إلى بروتوكول ترخيص رمز المصدر الإطار ، ولا تشير إليه في المشروع.
تعديل رمز المصدر للإطار لتجنب النزاعات القانونية غير الضرورية.
2. الهندسة المعمارية خلف دعامات 2
نظرًا لأننا قمنا بتحليل الكثير من فوائد الإطار من قبل ، سنبدأ بشكل طبيعي في تعلم استخدام Struts2. ولكن باستخدام دعامات 2
ما نوع الهندسة المعمارية الأنيقة التي سيرثها؟ في الواقع ، من مستوى أعلى من التجريد ، لا يزال نموذج MVC على دراية به.
وفقًا لمثال HelloWorld السابق ، فإن وحدة التحكم C (FilterDispatcher) هي ما أعلنناه في web.xml
Struts2 Core Class. والنموذج M هو فئة عمل الأخبار لدينا. و View V هي News.jsp بشكل طبيعي. مفهوم النموذج يبدو غامضا بعض الشيء. ما هو النموذج؟ في الواقع ، يحتوي هذا المفهوم الذي يبدو على حد سواء على كل من بيانات الأعمال المنقولة بشكل ثابت من الواجهة الأمامية على الويب وتنفيذ منطق العمل.
قد يقول بعض الناس أن هذه الهندسة المعمارية ليست جديدة ، فهناك العديد من أطر عمل MVC ، ما هو الفرق بين هذا وأطر أخرى؟ دعنا نتشريح Struts2 على مستوى أقل من التجريد ونرى ما الذي يجعله فريدًا.
للوهلة الأولى ، تبدو معقدة للغاية. إذا نظرنا إليها فقط من منظور المستخدم ، فنحن بحاجة فقط إلى تنفيذ الجزء الأصفر أثناء التطوير ، أي أننا
Struts.xml ، NewsAction و News.jsp في مثال HelloWorld. هذا هو كل ما يتعين علينا القيام به ، كما ذكرنا سابقًا ، نحتاج فقط إلى فعل أشياء صغيرة جدًا ونصبح جزءًا من هذه الهندسة المعمارية الممتازة.
انظر الآن إلى الأجزاء الأخرى. FilterDispatcher هو مرشح Servlet الذي نقوم بتكوينه في web.xml ، وهو Struts2
يجب تكوين جميع تطبيقات الويب Struts2 بهذه الطريقة. بعد ذلك ، الأجزاء الزرقاء والخضراء هي جوهر Struts2. يمكن القول أن هذه الفئات مصممة بعناية من قبل مطوري Struts2.
(1) يرسل العميل طلبًا ، وتوصيف حاوية J2EE حزمة HTTP وتغلفها في httpservletrequest.
(2) يعترض FilterDispatcher هذا الطلب ويبحث في ActionMapper بناءً على مسار الطلب لتحديد الإجراء الذي يجب الاتصال به.
(3) وفقًا لنتيجة الإرجاع لـ ActionMapper ، يعهد FilterDispatcher ActionProxy للعثور على هذا الإجراء في Struts.xml.
(4) يقوم ActionProxy بإنشاء محدد العمل ويبدأ المكالمات العودية إلى اعتراض وعمل.
(5) كل اعتراض يكمل مهامه الخاصة
(6) تعيد الدعوة الحقيقية إلى الإجراء مسار النتيجة
(7) سيقوم كائن النتيجة بإخراج بيانات الإرجاع إلى الدفق
(8) إرجاع httpservletresponse إلى حاوية J2EE ، وترسل الحاوية حزم HTTP إلى العميل.
هذه هي عملية تنفيذ Struts2. الكائنات الأساسية هي الإجراءات والتقاطع ، وكذلك ActionContext التي لم يتم تقديمها بعد.
ActionInvocation هو الجدولة الكلية للعملية بأكملها ، والتي تشبه إلى حد كبير كائن الاحتجاج في الربيع AOP. تم دمج العديد من التقاطعات في دعامات 2. الشيء الأكثر أهمية هو حفظ معلمات الطلب وتمرير البيانات الأمامية إلى متغيرات عضو الإجراء.
ActionContext هو كائن السياق العالمي الذي يحفظ هذه البيانات ، والشيء الأكثر أهمية هو Valuestack المستخدم لحفظ مثيل الإجراء.
يعني ما يسمى Global أنه يمكن الوصول إلى ActionContext في العمل والنتيجة ، لكنه في الواقع نوع Threadlocal. سيكون لكل مؤشر ترابط طلب مثيله الخاص في الإجراء و ActionContext.
يمكن القول أن التعلم Struts2 يتعلق بشكل أساسي بالتعلم:
(1) دع الاعتراض والعمل يتعاونان لإكمال المهمة.
(2) حفظ البيانات الأمامية في الإجراء.
(3) الحصول على بيانات الإرجاع من الإجراء من خلال Valuestack.
3. الاختلافات بين Struts2 و STRUTS1
من عملية التنفيذ أعلاه ، يمكننا بالفعل رؤية الفرق الكبير بين Struts1 و 2.
(1) أين ذهب Actionform؟ هل لا يزال الإجراء هو نفس الإجراء؟
الشيء الأكثر وضوحًا هو أننا لا نستطيع رؤية كائن Actionform في العملية بأكملها ، وعلى الرغم من أن الإجراء لا يزال يسمى هذا الاسم ، يبدو أنه مختلف تمامًا عن الإجراء في Struts1.
بادئ ذي بدء ، تم التخلي عن Actionform ، ويمكن حفظ البيانات المرسلة من مكتب الاستقبال إلى أي pojo. انتهى يوم الادخار في العمل أولاً ثم يتم نسخه إلى كائن DTO. ثانياً ، هذا pojo هو في الواقع متغير عضو في كائن الإجراء. هذا في دعامات 1
من المستحيل مشاركة مثيل إجراء لجميع الطلبات في هذه الحالة. الآن ستنشئ Struts2 مثيل إجراء لكل طلب ، لذلك يعمل هذا. ثالثًا ، على الرغم من أن هذا أمر ممكن ، يبدو أن هذا الإجراء ، كنموذج M في MVC ، يحفظ البيانات ويحتوي على منطق العمل. هل هذا تصميم سيء؟ في الواقع ، إذا فكرت في الأمر بعناية ، فإن هذا التصميم مناسب للغاية ، فقد حصلنا بالفعل على البيانات.
يمكنك تشغيل طبقة الخدمة مباشرة. يبدو أن الإجراء لديه الكثير من المسؤوليات ، ولكن ليس الكثير.
(2) كيف أصبح Servlet في الواجهة الأمامية مرشحًا؟
نحن نعلم أن STRUTS1 و SPRING MVC يستخدمان كدخلات من خلال Servlets الواجهة الأمامية. لماذا تستخدم Struts2 مرشحات Servlet؟
نظرًا لأن Struts2 يعتمد على قلب الويب ، فإنه يختلف تمامًا عن Struts1. يمكن القول أن العمل على شبكة الإنترنت يقلل من التطبيقات و j2ee
اقتران API ، مثل تغيير Actionservlet إلى مرشح Servlet ، والوصول المباشر إلى httpservletrequest/الاستجابة.
على سبيل المثال ، يمكن لأي pojo أن يعمل كإجراء ، يمكن استخدام أي فئة كإجراء دون تنفيذ واجهة الإجراء ، إلخ.
لذلك ، يرث Struts2 هذا التصميم الممتاز غير الغازي.
هذا يشبه إلى حد ما أفكار تصميم الربيع. على سبيل المثال ، لا تحتاج إلى تنفيذ واجهات WARE على الإطلاق ، وذلك لتقليل الاقتران بين رمز التطبيق والإطار. يعد الغزو عاملاً مهمًا في الاعتبار عند تصميم إطار عمل.
(3) ognl بين المرشح والعمل والنتيجة
يمكن أن يوضح الشكل التالي بوضوح كيفية دمج ognl في إطار Struts2.
من المريح للغاية الوصول إلى البيانات قيد التنفيذ باستخدام علامة Struts2 في صفحة الإدخال inputform.html والعودة إلى page resultpage.jsp
تتيح ognl الوصول إلى خصائص الإجراءات المحفوظة في Valuestack على أنها مريحة مثل الوصول إلى خصائص Valuestack الخاصة.
الاستخدام الواسع لـ ognl هو ميزة رئيسية في Struts2. بما في ذلك قيم تمرير العلامة الأمامية إلى العمل ، ستستخدم النتيجة أخذ القيم من الإجراء ، وما إلى ذلك ، ognl بكميات كبيرة. ومع ذلك ، يتم استخدام الانعكاس كثيرا في ognl. أعتقد أن هذا أحد الأسباب التي تجعل STRUTS2 ليس جيدًا مثل Struts1. بعد كل شيء ، يتطلب الأمر سعرًا معينًا للحصول على بنية مرنة ومنخفضة المقاومة.
(4) قوة التقاطع لا تقهر
ميزة قوية أخرى في Struts2 هي اعتراض التقاطع. يحتوي Struts2 على عدد كبير من المقاطعات ، والتي تمكن من إعادة استخدام كمية كبيرة من التعليمات البرمجية ، مما أدى إلى أتمتة ما أطلقناه سابقًا على المهام التافهة ، مما يتيح Struts2 الوصول إلى مستوى عالٍ من الانتباه. هذا هو حقا نموذج لتطبيق أفكار AOP في الإطار!
Struts2 ثلاثة طرق نقل البيانات
يوفر Struts2 ثلاث طرق لحفظ المعلمات في طلبات HTTP: سمات Javabean ، وكائنات Javabean ، والكائنات النموذجية. دعنا نلقي نظرة على طرق نقل البيانات الثلاثة هذه من خلال مثال تسجيل الدخول الأكثر شيوعًا. رمز الصفحة بسيط للغاية. يحتوي نموذج التقديم على اسم المستخدم وكلمة المرور. يمكنك الحصول على هاتين المعلمتين في الإجراء للتحقق مما إذا كان المستخدم يقوم بتسجيل الدخول بنجاح.
1. خصائص جافابان
<٪@ page contentType = "text/html ؛ charset = utf-8" ٪> <html> <head> </head> <body> <h1> صفحة تسجيل الدخول </h1> <form action = "/cdai/login" method = "post"> <iv> </viv> <viv> <label for = "password"> كلمة المرور: </label> <inputive id = "password" name = "password" type = "password"/> </viv> <viv> <label for = "requestme"> <inputive id = "remerveme" name = "remerveme" type = "checkbox"/> </html>
حزمة com.cdai.web.ssh.action ؛ استيراد com.cdai.web.ssh.request.loginRequest ؛ استيراد com.cdai.web.ssh.service.userservice ؛ استيراد com.opensymphony.xwork2.action ؛ استيراد com.opensymphony.xwork2.modeldriven ؛ طبقة تسجيل الدخول إلى الطبقة العامة تنفذ الإجراء {private String username ؛ كلمة مرور السلسلة الخاصة ؛ Userversevice userService ؛ Override Public String Execute () {system.out.println ("تسجيل الدخول -" + طلب) ؛ العودة النجاح } السلسلة العامة getUserName () {return request ؛ } public void setusername (string username) {this.userName = username ؛ } السلسلة العامة getPassword () {return request ؛ } public void setPassword (سلسلة كلمة مرور) {this.password = password ؛ }}هذه الطريقة بسيطة نسبيًا ، احفظ المعلمات مباشرة في النموذج إلى الخصائص في الإجراء. عند التحقق ، قد يحتاج الإجراء أيضًا إلى تغليف اسم المستخدم وكلمة المرور في DTO لتمريره إلى طبقة الخدمة للتحقق. فلماذا لا تذهب خطوة واحدة إلى الأمام وحفظ اسم المستخدم وكلمة المرور مباشرة في DTO.
2. جافابان كائنات
<٪@ page contentType = "text/html ؛ charset = utf-8" ٪> <html> <head> </head> <body> <h1> صفحة تسجيل الدخول </h1> <form action = "/cdai/login" method = "post"> <iv> </viv> <viv> <label for = "password"> كلمة المرور: </label> <inputive id = "password" name = "request.password" type = "password"/> </viv> <viv> <label for = "requestme"> <inpute id = "regmeme" </body> </html>
حزمة com.cdai.web.ssh.action ؛ استيراد com.cdai.web.ssh.request.loginRequest ؛ استيراد com.cdai.web.ssh.service.userservice ؛ استيراد com.opensymphony.xwork2.action ؛ استيراد com.opensymphony.xwork2.modeldriven ؛ يقوم تسجيل الدخول إلى الطبقة العامة بتنفيذ الإجراء {طلب تسجيل الدخول الخاص ؛ Userversevice userService ؛ Override Public String Execute () {system.out.println ("تسجيل الدخول -" + طلب) ؛ العودة النجاح } loginRequest getRequest () {Return request ؛ } public void setRequest (loginRequest request) {this.request = request ؛ }} هذا يجعل من السهل استدعاء طبقة الخدمة مباشرة. ولكن هناك عيب صغير يعمق هذا عمق اسم معلمة الصفحة ، فقط إضافة طلب إلى اسم المعلمة
تمكن البادئة (اسم السمة في الإجراء) Struts2 من حفظ المعلمات بشكل صحيح في النموذج إلى كائن الطلب من خلال ognl.
3. كائن نموذج
<٪@ page contentType = "text/html ؛ charset = utf-8" ٪> <html> <head> </head> <body> <h1> صفحة تسجيل الدخول </h1> <form action = "/cdai/login" method = "post"> <iv> </viv> <viv> <label for = "password"> كلمة المرور: </label> <inputive id = "password" name = "password" type = "password"/> </viv> <viv> <label for = "requestme"> <inputive id = "remerveme" name = "remerveme" type = "checkbox"/> </html>
حزمة com.cdai.web.ssh.action ؛ استيراد com.cdai.web.ssh.request.loginRequest ؛ استيراد com.cdai.web.ssh.service.userservice ؛ استيراد com.opensymphony.xwork2.action ؛ استيراد com.opensymphony.xwork2.modeldriven ؛ يقوم تسجيل الدخول إلى الطبقة العامة بتنفيذ الإجراء ، modeldriven <GindRequest> {request private loginRequest = new loginRequest () ؛ Userversevice userService ؛ Override Public String Execute () {system.out.println ("تسجيل الدخول -" + طلب) ؛ العودة النجاح } Override public loginRequest getModel () {return request ؛ }} وبهذه الطريقة ، هناك حاجة إلى واجهة أخرى من طرازات ، ويتم حفظ الكائنات التي توفرها ModelDdriven إلى Valuestack ، بحيث يمكن تمرير الصفحة الأمامية مباشرة
تحدد أسماء سمات اسم المستخدم وكلمة المرور اسم المعلمة للنموذج.
أي من الطرق الثلاثة لا ينبغي تعميمها؟ يعتمد ذلك على الاحتياجات المحددة للمشروع ثم قرر ذلك بنفسك!