مقدمة
كما نعلم، جاء نجاح جافا على وجه التحديد بفضل تطور البرمجيات التي تسعى جاهدة للاتصال بالشبكة. لذلك، سنأخذ تطبيق وحدة التحكم المعتاد " 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). إنها بسيطة وتعتمد على وحدة التحكم وليست محدثة. كيفية تحويله إلى تطبيق ويب؟
واجهة برمجة تطبيقات سيرفلت
لكي تتمكن 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 مثال أساسي ":
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 على نفس مساحة الاسم التي يجب أن نحددها:
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
، وإضافة الأسطر التالية:
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 نعلن:
applicationContext.xml
الذي حددناه سابقًا. لنأخذ مثالاً من وثائق الربيع: " 1.10.3. اكتشاف الفئات تلقائيًا وتسجيل تعريفات الفول ".
-
تكوين الويب على سبيل المثال تكوين نمط 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 الافتراضي واستخدامه ".
-
وحدة تحكم 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 التي يجب عرضها للعميل. وبالتالي، سيحصل العميل في النهاية على تلك الصفحة العزيزة جدًا.
GO TO FULL VERSION