JavaRush /مدونة جافا /Random-AR /من Hello World إلى Spring Web MVC وما علاقة servlets بها
Viacheslav
مستوى

من Hello World إلى Spring Web MVC وما علاقة servlets بها

نشرت في المجموعة
من Hello World إلى Spring Web MVC وما علاقة servlets بها - 1

مقدمة

كما نعلم، جاء نجاح جافا على وجه التحديد بفضل تطور البرمجيات التي تسعى جاهدة للاتصال بالشبكة. لذلك، سنأخذ تطبيق وحدة التحكم المعتاد " Hello World " كأساس ونفهم ما يحتاجه ليصبح تطبيق شبكة من تطبيق وحدة التحكم. لذلك، أولا تحتاج إلى إنشاء مشروع جافا. المبرمجون أناس كسالى. في عصور ما قبل التاريخ، عندما كان البعض يصطاد الماموث، جلس آخرون وحاولوا عدم الخلط بين المجموعة الكاملة لمكتبات جافا وهياكل الدليل. حتى يتمكن المطور من التحكم في عملية إنشاء تطبيق حتى يتمكن ببساطة من كتابة "أريد مكتبة كذا وكذا الإصدار 2" ، فقد توصلوا إلى أدوات خاصة - بناء الأنظمة. أشهرهما Maven و Gradle . في هذه المقالة سوف نستخدم Gradle. إذا كان علينا في وقت سابق إنشاء بنية الدليل بأنفسنا، فإن Gradle الآن، باستخدام Gradle Init Plugin، يسمح لنا بإنشاء مشروع Java ببنية دليل وفئة رئيسية أساسية في أمر واحد: gradle init --type java-application ينفذ هذا الأمر التهيئة (init) لـ لنا تطبيق Java (تطبيق Java) مع وحدة التحكم Hello World. بعد الانتهاء، سيظهر ملف في الدليل - build.gradle . هذا هو برنامجنا النصي للبناء - أي برنامج نصي معين لإنشاء تطبيق مع وصف للإجراءات التي يجب تنفيذها لهذا الغرض. لنفتحه ونضيف السطر إليه: jar.baseName = 'webproject' يتيح لك Gradle تنفيذ إجراءات مختلفة على المشروع وتسمى هذه الإجراءات بالمهام . من خلال تنفيذ أمر (مهمة)، سيتم إنشاء ملف JAR gradle buildفي الدليل /build/libs . وكما خمنت، سيصبح اسمه الآن webproject.jar . ولكن إذا نفذنا java -jar ./build/libs/webproject.jar، فسنحصل على خطأ: no main manifest attribute. هذا لأنه بالنسبة لتطبيق Java، تحتاج إلى إرفاق بيان معين - وهذا وصف لكيفية العمل مع التطبيق، وكيفية إدراكه. بعد ذلك، سيعرف JVM، الذي سيقوم بتنفيذ تطبيق Java، الفئة التي تمثل نقطة الدخول إلى البرنامج والمعلومات الأخرى (على سبيل المثال، classpath). إذا ألقينا نظرة فاحصة على محتويات البرنامج النصي للبناء، فسنرى أن المكونات الإضافية متصلة. على سبيل المثال: apply plugin: 'java' إذا ذهبنا إلى صفحة Gradle Java Plugin ، يمكننا أن نرى أنه يمكننا تكوين البيان:
jar {
    manifest {
        attributes 'Main-Class': 'App'
    }
}
تم إنشاء الفئة الرئيسية، وهي نقطة الدخول إلى البرنامج، لنا بواسطة Gradle Init Plugin. ويتم تحديده أيضًا في المعلمة mainClassName. لكن هذا لم يناسبنا، لأن... يشير هذا الإعداد إلى مكون إضافي آخر، وهو Gradle Application Plugin . لذا، لدينا تطبيق Java يعرض Hello World على الشاشة. يتم حزم تطبيق Java هذا في JAR (Java ARchive). إنها بسيطة وتعتمد على وحدة التحكم وليست محدثة. كيفية تحويله إلى تطبيق ويب؟
От Hello World до Spring Web MVC и при чём тут сервлеты - 2

واجهة برمجة تطبيقات سيرفلت

لكي تتمكن Java من العمل مع الشبكة، ظهرت مواصفات تسمى Servlet API في العصور القديمة . هذه المواصفات هي التي تصف التفاعل بين العميل والخادم، وتلقي رسالة من العميل (على سبيل المثال، متصفح) وإرسال استجابة (على سبيل المثال، مع نص الصفحة). بطبيعة الحال، لقد تغير الكثير منذ ذلك الحين، ولكن النقطة المهمة هي أنه لكي يصبح تطبيق Java تطبيق ويب، يتم استخدام Servlet API. لكي لا نتكهن بشكل لا أساس له من الصحة، دعنا نختار هذه المواصفات ذاتها: JSR-000340 JavaTM Servlet 3.1 . بادئ ذي بدء، نحن مهتمون بـ " الفصل الأول: نظرة عامة ". فهو يصف المفاهيم الأساسية التي يجب أن نفهمها. أولاً، ما هو السيرفلت؟ يوضح الفصل " 1.1 ما هو Servlet؟ " أن Servlet هو مكون Java تتم إدارته بواسطة حاوية ويقوم بإنشاء محتوى ديناميكي. مثل مكونات Java الأخرى، يعد servlet فئة Java تم تجميعها في كود بايت ويمكن تحميلها إلى خادم ويب باستخدام تقنية Java. من المهم أن تتفاعل servlet مع عميل الويب (على سبيل المثال، المتصفح) في إطار نموذج الطلب/الاستجابة، والذي يتم تنفيذه بواسطة حاوية Servlet. اتضح أن Servlet تعيش في نوع من حاوية Servlet. ما هذا؟ في الفصل " 1.2 ما هي حاوية Servlet؟ " يُقال أن حاوية Servlet هي جزء من خادم الويب أو خادم التطبيقات الذي يوفر خدمات الشبكة التي يتم من خلالها إرسال الطلبات وإرسال الاستجابات. تدير حاوية Servlet هذه دورة حياة servlet. جميع حاويات Servlet مطلوبة لدعم بروتوكول HTTP كحد أدنى، ولكنها قد تدعم الآخرين. على سبيل المثال، HTTPS. من المهم أيضًا أن تتمكن حاوية Servlet من فرض أي قيود متعلقة بالأمان على البيئة التي يتم فيها تنفيذ servlet. من المهم أيضًا أنه وفقًا لـ " 10.6 ملف أرشيف تطبيقات الويب "، يجب تعبئة تطبيق الويب في ملف WAR (Web ARchive). أي أننا نحتاج الآن إلى إزالة المكونات الإضافية للتطبيقات والجرة الخاصة بنا لشيء آخر. وهذا هو البرنامج المساعد Gradle WAR . وبدلاً من jar.baseName، حدد war.baseName لأنه نظرًا لأننا لم نعد نستخدم البرنامج الإضافي jar، فقد قمنا أيضًا بإزالة إعدادات البيان. عندما أطلقنا JAR، كان لا بد من إخبار Java Virtual Machine (JVM) من خلال البيان بكيفية العمل مع تطبيقنا. لأن JVM كان يقوم بتشغيله. يبدو أن تطبيق الويب يتم تنفيذه بواسطة خادم ويب ما. اتضح أنه يحتاج إلى إخباره بطريقة أو بأخرى بكيفية العمل مع تطبيق الويب الخاص بنا؟ واتضح أن نعم. تطبيقات الويب لها بيان خاص بها. يطلق عليه واصف النشر . تم تخصيص قسم كامل لها: " 14. واصف النشر ". هناك قسم مهم: " الفصل 10:". يتحدث عن ماهية تطبيق الويب من وجهة نظر Servlet API. على سبيل المثال، في الفصل " 10.5 بنية الدليل " يُشار إلى المكان الذي يجب أن يكون فيه واصف النشر: /WEB-INF/web.xml. أين يتم وضع WEB-INF؟ كما هو مذكور في ملحق Gradle WAR، فإنه يضيف تخطيطًا جديدًا : src/main/webappلذلك، دعونا ننشئ مثل هذا الدليل، في الداخل سننشئ دليل WEB-INF، وفي الداخل سننشئ ملف web.xml. من المهم أن الدليل يسمى WEB-INF، وليس META-INF! فلننسخه من مثال XML " 14.5.1 مثال أساسي ":
От Hello World до Spring Web MVC и при чём тут сервлеты - 3
كما نرى، يتم استخدام مستند XML للتكوين. يجب أن تتوافق وثيقة XML، لكي تعتبر صالحة (صالحة)، مع بعض "المخطط". يمكنك التفكير في هذا كنوع من الواجهة لمستند XML. يحدد المخطط العناصر التي يمكن أن تكون موجودة في مستند XML، ونوع البيانات التي يمكن أن تحدد العنصر، والترتيب، والمتطلبات، والجوانب الأخرى. يشير المثال المنسوخ من الوثائق إلى الإصدار 2.5، لكننا نريد استخدام الإصدار 3.1. وبطبيعة الحال، تغيرت المواصفات مع تغير الإصدارات، وتمت إضافة ميزات جديدة. لذلك، تحتاج إلى استخدام مخطط آخر غير المخطط المستخدم للإصدار 2.5 (web-app_2_5.xsd). ما هو المخطط الذي يجب أن أستخدمه للإصدار 3.1؟ ستساعدنا الوثائق في هذا، الفصل " 14.3 واصف النشر "، الذي ينص على specification is available at http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd أننا بحاجة إلى استبدال رابط المخطط بـ xsd المحدد في كل مكان، دون أن ننسى تغييره version="2.5"إلى 3.1، وكذلك تغيير مساحة الاسم في كل مكان ( xmlns وفي xsi:schemaLocation). إنها تشير إلى مساحة الاسم التي سنعمل فيها (بكل بساطة، ما هي أسماء العناصر التي يمكننا استخدامها). إذا قمت بفتح ملف المخطط، فستحتوي مساحة targetNamespace على نفس مساحة الاسم التي يجب أن نحددها:
От Hello World до Spring Web MVC и при чём тут сервлеты - 4
كما نتذكر، في بيان ملف Jar، كتبنا الفئة التي نريد استخدامها. ماذا تفعل هنا؟ نحتاج هنا إلى تحديد فئة servlet التي نريد استخدامها عندما نتلقى طلبًا من عميل الويب. يمكن قراءة الوصف في الفصل " 14.4 مخطط واصف النشر ". سوف يبدو مثل هذا:
От Hello World до Spring Web MVC и при чём тут сервлеты - 5
كل شيء بسيط هنا. يتم الإعلان عن الخادم، ثم يتم تعيينه إلى قالب معين. في هذه الحالة، على /app. عند تنفيذ القالب، سيتم تنفيذ طريقة servlet. من أجل الجمال، يجب نقل فئة التطبيق إلى الحزمة، دون أن ننسى تصحيح تكوين XML. ولكن هذا ليس كل شيء. يجب أن يكون التطبيق servlet. ماذا يعني أن تكون servlet؟ هذا يعني أننا يجب أن نرث من HttpServlet . يمكن رؤية مثال في الفصل " 8.1.1 @WebServlet ". وفقًا لذلك، ستبدو فئة التطبيقات الخاصة بنا كما يلي:
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class App extends HttpServlet {
    public String getGreeting() {
        return "Hello world.";
    }

	public void doGet(HttpServletRequest request, HttpServletResponse response) {
		response.setContentType("text/html");
		try {
			response.getWriter().println(getGreeting());
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}
}
لكن مشروعنا ليس جاهزا بعد. لأننا نعتمد الآن على الإصدار 3.1 من Servlet API. هذا يعني أنه في نص البناء الخاص بنا نحتاج إلى الإشارة إلى التبعية على Servlet API. يحتاج JVM إلى معرفة أن ما كتبته في الكود صحيح وكيفية استخدامه. وكما نتذكر، فإن المواصفات هي في الأساس مجرد واجهات تصف كيفية عمل كل شيء. وتقع التطبيقات على جانب خادم الويب. لذلك، بدون واجهة برمجة تطبيقات Servlet، سيكون هناك العثور على المكتبة المطلوبة على Maven Central: javax.servlet-api . وأضف إدخالاً إلى كتلة التبعيات . في مستودع Maven، كما رأيت، تم توفيره. قبل استخدام التبعية، يجب عليك تحديد النطاق. لا يحتوي Gradle على نطاق يسمى "مقدم"، ولكنه يحتوي على نطاق " ترجمة فقط ". لذلك سنشير: providedCompile 'javax.servlet:javax.servlet-api:3.1.0' آه، يبدو أن كل شيء على ما يرام؟ سيقوم Gradle Build ببناء مشروعنا في ملف WAR. وماذا يجب أن نفعل معه بعد ذلك؟ أولا، نحن بحاجة إلى خادم ويب. في جوجل نكتب " قائمة جافا لخادم الويب " ونرى قائمة بخوادم الويب. لنختار من هذه القائمة، على سبيل المثال، TomCat . انتقل إلى موقع ويب Apache Tomcat ، وقم بتنزيل أحدث إصدار (الإصدار 9 حاليًا) كأرشيف مضغوط (إذا كان لنظام التشغيل Windows). قم بفك ضغطه في بعض الدليل. يا هلا، لدينا خادم ويب. من دليل خادم الويب في الدليل الفرعي bin ، نقوم بتنفيذ catalina من سطر الأوامر ونرى الخيارات المتاحة. دعنا نفعل: catalina start. يحتوي كل خادم ويب على دليل يراقبه خادم الويب. إذا ظهر ملف تطبيق ويب هناك، فسيبدأ خادم الويب في تثبيته. يُسمى هذا التثبيت بالنشر أو النشر . نعم نعم، لهذا السبب " واصف النشر ". وهذا يعني كيفية نشر التطبيق بشكل صحيح. في Tomcat هذا الدليل هو تطبيقات الويب . دعونا ننسخ الحرب التي قمنا بها باستخدام Gradle build هناك. بعد ذلك، سنرى في السجل شيئًا مثل: Deployment of web application archive [tomcat\webapps\webproject.war] has finished in [время] ms لفهم أفضل، في دليل Tomcat، سنقوم بتحرير الملف \conf\tomcat-users.xml، وإضافة الأسطر التالية:
От Hello World до Spring Web MVC и при чём тут сервлеты - 6
الآن نقوم بإعادة تشغيل الخادم (catalina stop, catalina start) ونذهب إلى العنوان http://127.0.0.1:8080/manager وهنا سنرى مسارات جميع التطبيقات. من المرجح أن يكون مشروع الويب الخاص بنا مُعطى للمسار /webproject. ما هو هذا الطريق؟ تنص المواصفات الواردة في الفصل " 10.1 تطبيقات الويب داخل خوادم الويب " على أن تطبيق الويب يرتبط بمسار ما داخل التطبيق (في هذه الحالة، /webproject). سيتم ربط جميع الطلبات من خلال هذا المسار بنفس ServletContext. يُسمى هذا المسار أيضًا contextRoot . ووفقًا لـ " 10.2 العلاقة بـ ServletContext "، تربط حاوية servlet تطبيق الويب وServletContext واحدًا لواحد. أي أن كل تطبيق ويب له ServletContext الخاص به. ما هو سياق Servlet ؟ كما تنص المواصفات، فإن ServletContext هو كائن يزود servlet "بعرض التطبيق " الذي تعمل فيه. تم وصف سياق Servlet بمزيد من التفاصيل في الفصل 4 من مواصفات Servlet API. من المثير للدهشة أن واجهة برمجة تطبيقات Servlet في الإصدار 3.1 لم تعد تتطلب وجود web.xml. على سبيل المثال، يمكنك تعريف servlet باستخدام التعليقات التوضيحية:
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/app2")
public class App2 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        response.getWriter().println("app2");
    }
}
يوصى أيضًا بهذا الموضوع: " مقابلة Java EE - JEE Servlet API (أسئلة وأجوبة) ". لذلك، لدينا Servlet - وهو مسؤول عن الاستجابة التي يجب تقديمها لعميل الويب. لدينا حاوية Servlet تتلقى الطلبات من المستخدم، وتطابق المسار الذي تم الوصول إليه مع المسار إلى servlet، وإذا تم العثور على تطابق، فسيتم تنفيذ Servlet. بخير. ما المكان الذي يحتله الربيع في هذه الصورة للعالم ؟

ربيع ويب MVC

عظيم، لدينا تطبيق ويب. الآن نحن بحاجة إلى ربط الربيع. كيف يمكننا عمل ذلك؟ أولاً، عليك معرفة كيفية ربط Spring بمشروعك بشكل صحيح. اتضح أنه في وقت سابق كان من الممكن القيام بذلك وفقًا لتوثيق مشروع منصة الربيع ، ولكن الآن " ستصل المنصة إلى نهاية عمرها المدعوم في 9 أبريل 2019 "، أي أنه ليس من المستحسن استخدامه، لأنه ولن يتم دعمه قريبًا. المخرج الوحيد هو " يتم تشجيع مستخدمي النظام الأساسي على البدء في استخدام إدارة تبعية Spring Boot ". لذلك، دعونا ننتقل إلى وثائق التمهيد الربيع . اسمحوا لي أن أوضح أننا لا نستخدم Spring Boot نفسه، ولكننا نستخدم فقط إدارة التبعيات من Spring Boot. أي أن مشروع Spring Boot يمكنه توفير المعرفة حول إصدارات المكتبات التي سيتم استخدامها (بما في ذلك Spring MVC). هناك سنجد 3.2. استخدام إدارة تبعية Spring Boot بشكل منفصل . وفقًا للوثائق، أضف ما يلي إلى البرنامج النصي للإنشاء:
plugins {
    id 'org.springframework.boot' version '2.0.4.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
و
dependencyManagement {
    imports {
        mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
    }
}
كما ترون، أشرنا apply false، أي. نحن لا نستخدم Spring Boot نفسه، ولكننا نستخدم إدارة التبعية من هناك. تسمى إدارة التبعية هذه أيضًا BOM - " قائمة المواد ". نحن الآن جاهزون لربط مشروع Spring Web MVC نفسه. يعد Spring Web MVC جزءًا من مشروع Spring Framework ونحن مهتمون بقسم " Web Servlet ". دعونا نضيف التبعية إلى البرنامج النصي للبناء: compile 'org.springframework:spring-webmvc'. كما نرى، قمنا بتعيين نطاق الترجمة، لأن خادم الويب لا يزودنا بـ Spring. يضطر مشروعنا إلى تضمين مكتبة الربيع بداخله. بعد ذلك، من المهم بالنسبة لنا قراءة القسم " 1.2.DispatcherServlet "، حيث يُقال أن Spring MVC مبني حول نمط " Front Controller "، حيث يوجد نوع من servlet المركزي الذي يوفر التكوين والتفويض للمكونات الأخرى . يمكن ترجمة المرسل على أنه مرسل. لذلك، أولاً وقبل كل شيء، في web.xml نعلن:
От Hello World до Spring Web MVC и при чём тут сервлеты - 7
كما نرى، هذا في الواقع مستمع عادي محدد في مواصفات Servlet API. لنكون أكثر دقة، هذا هو ServletContextListener، أي أنه يتم تشغيله لتهيئة سياق Servlet لتطبيق الويب الخاص بنا. بعد ذلك، تحتاج إلى تحديد الإعداد الذي سيخبر Spring بمكان وجود تكوين XML الخاص به مع الإعدادات:
От Hello World до Spring Web MVC и при чём тут сервлеты - 8
كما ترون، هذا مجرد إعداد عادي يتم تخزينه على مستوى سياق Servlet، ولكن سيتم استخدامه بواسطة Spring عند تهيئة سياق التطبيق. أنت الآن بحاجة إلى الإعلان، بدلاً من جميع السيرفلتس، عن مرسل واحد يقوم بتوزيع كافة الطلبات الأخرى.
От Hello World до Spring Web MVC и при чём тут сервлеты - 9
وليس هناك سحر هنا. إذا نظرنا إليها، فهي HttpServlet، حيث يقوم Spring بالكثير من الأشياء التي تجعله إطار عمل. كل ما تبقى هو ربط (تعيين) قالب URL محدد مع servlet:
От Hello World до Spring Web MVC и при чём тут сервлеты - 10
كل شيء كما فعلنا من قبل. لنقم الآن بإنشاء شيء يجب أن يعرضه خادم الويب الخاص بنا. على سبيل المثال، لنقم بإنشاء دليل فرعي للصفحات في WEB-INF الخاص بنا، وسيكون هناك ملف hello.jsp. يمكن أن يكون المحتوى هو الأكثر بدائية. على سبيل المثال، يوجد داخل علامات html علامة h1 تحتوي على النص " Hello World ". ولا تنس إنشاء الملف applicationContext.xmlالذي حددناه سابقًا. لنأخذ مثالاً من وثائق الربيع: " 1.10.3. اكتشاف الفئات تلقائيًا وتسجيل تعريفات الفول ".
От Hello World до Spring Web MVC и при чём тут сервлеты - 11
لأن نحن نقوم بتمكين الاكتشاف التلقائي بهذه الطريقة، يمكننا الآن إنشاء فئتين (سيتم اعتبارهما فاصوليا الربيع بسبب استخدام التعليقات التوضيحية الخاصة بـ Spring)، والتي سيقوم Spring الآن بإنشائها بنفسه وتخصيص تطبيقنا بمساعدتهم:
  1. تكوين الويب على سبيل المثال تكوين نمط Java:

    @Configuration
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void configureViewResolvers(ViewResolverRegistry registry) {
            registry.jsp("/WEB-INF/pages/", ".jsp");
        }
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
    }

    تم وصف هذا المثال في وثائق Spring Framework: " 1.11.MVC Config ".

    نقوم هنا بتسجيل ViewResolver، والذي سيساعد في تحديد مكان وجود صفحات jsp. الطريقة الثانية تضمن تمكين " servlet الافتراضي ".

    يمكنك قراءة المزيد عن هذا هنا: " ما هي الحاجة إلى معالج servlet الافتراضي واستخدامه ".

  2. وحدة تحكم HelloController لوصف تعيين الطلبات إلى JSP محدد

    @Controller
    public class HelloController {
        @GetMapping("/hello")
        public String handle(Model model) {
            return "hello";
        }
    }

    لقد استخدمنا هنا التعليق التوضيحي @Controller الموضح في الوثائق في الفصل " 1.4. وحدات التحكم المشروحة ".

الآن، عندما يتم نشر تطبيقنا، عندما نرسل طلبًا /webproject/hello(حيث /webproject هو جذر السياق)، ستتم معالجة DispatcherServlet أولاً. بصفته المرسل الرئيسي، سيحدد أننا /* نطابق الطلب الحالي، مما يعني أن DispatcherServlet يجب أن يفعل شيئًا ما. وبعد ذلك سوف يستعرض جميع التعيينات التي يجدها. سوف نرى أن هناك HelloController مع طريقة مقبض تم تعيينها إلى /hello وسيتم تنفيذها. ستعيد هذه الطريقة النص "مرحبًا". سيتم استلام هذا النص بواسطة ViewResolver، والذي سيخبر الخادم بمكان البحث عن ملفات jsp التي يجب عرضها للعميل. وبالتالي، سيحصل العميل في النهاية على تلك الصفحة العزيزة جدًا.

خاتمة

آمل أن يكون واضحًا من المقال أن كلمة "سياق" ليست مخيفة. تبين أن هذه المواصفات مفيدة للغاية. والتوثيق صديقنا وليس عدونا. آمل أن يكون واضحًا ما يعتمد عليه Spring وكيفية اتصاله وما علاقة Servlet API به.
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION