\ ServletContextListener هو واحد من العديد من سماعات الـ Servlet التي لدينا. هذا هو المقال الخامس في سلسلة تطبيقات الويب بلغة Java، قد ترغب في التحقق من المقالات الأربع السابقة أيضًا.
سماعة السيرفلت
في هذا البرنامج التعليمي، سنتعرض لـ مستمع سيرفلت، فوائد مستمعات سيرفلت، بعض المهام الشائعة التي يمكننا القيام بها باستخدام المستمعات، وواجهات مستمعات واجهة برمجة التطبيقات (API) للسيرفلت وكائنات الأحداث. في النهاية، سنقوم بإنشاء مشروع ويب بسيط لعرض مثال على تنفيذ المستمعات المستخدمة بشكل شائع لـ سياق السيرفلت، الجلسة و طلب السيرفلت.
نحن نعلم أنه باستخدام ServletContext
، يمكننا إنشاء سمة بنطاق التطبيق يمكن لجميع السيرفلتات الأخرى الوصول إليها ولكن يمكننا تهيئة معلمات بدء سياق الخدمة بصورة نصية فقط في ملف الوصف (web.xml). ماذا لو كان تطبيقنا موجهًا نحو قاعدة البيانات وأردنا تعيين سمة في ServletContext لاتصال قاعدة البيانات؟ إذا كان تطبيقك يحتوي على نقطة واحدة للدخول (تسجيل الدخول للمستخدم)، يمكنك فعل ذلك في طلب سيرفلت الأول ولكن إذا كان لدينا عدة نقاط دخول فإن القيام بذلك في كل مكان سيؤدي إلى تكرار الكود بشكل كبير. أيضا إذا كانت قاعدة البيانات غير متوفرة أو لم تكن مكونة بشكل صحيح، فلن نعرف حتى يأتي أول طلب من العميل إلى الخادم. للتعامل مع هذه السيناريوهات، توفر واجهة برمجة تطبيقات السيرفلت (Servlet API) واجهات الاستماع التي يمكننا تنفيذها وتكوينها للاستماع إلى حدث والقيام بعمليات معينة. الحدث هو حدوث شيء ما، في عالم تطبيقات الويب يمكن أن يكون الحدث تهيئة التطبيق، تدمير التطبيق، طلب من العميل، إنشاء/تدمير جلسة، تعديل السمة في الجلسة إلخ. واجهة برمجة تطبيقات السيرفلت توفر أنواعًا مختلفة من واجهات الاستماع التي يمكننا تنفيذها وتكوينها في ملف الوصف (web.xml) لمعالجة شيء ما عند حدوث حدث معين. على سبيل المثال، في السيناريو أعلاه يمكننا إنشاء مستمع لحدث بدء تشغيل التطبيق لقراءة معلمات بدء سياق التطبيق وإنشاء اتصال قاعدة بيانات وتعيينه إلى سمة السياق للاستخدام من قبل الموارد الأخرى.
- javax.servlet.AsyncEvent – الحدث الذي يتم تنشيطه عند اكتمال العملية الغير متزامنة التي تم بدءها على ServletRequest (عبر استدعاء ServletRequest#startAsync أو ServletRequest#startAsync(ServletRequest, ServletResponse)) أو عند انتهاء الوقت المحدد لها أو عند حدوث خطأ.
- javax.servlet.http.HttpSessionBindingEvent – يتم إرسال أحداث هذا النوع إما إلى كائن ينفذ HttpSessionBindingListener عند تكوينه أو إلغاء تكوينه من جلسة، أو إلى HttpSessionAttributeListener الذي تم تكوينه في ملف web.xml عند ربط أي سمة أو إلغائها أو استبدالها في جلسة. تقوم الجلسة بربط الكائن عبر استدعاء HttpSession.setAttribute وتلغي ربط الكائن عبر استدعاء HttpSession.removeAttribute. يمكننا استخدام هذا الحدث لأنشطة التنظيف عند إزالة الكائن من الجلسة.
- javax.servlet.http.HttpSessionEvent – هذه هي الفئة التي تمثل إشعارات الحدث بتغييرات في الجلسات داخل تطبيق ويب.
- javax.servlet.ServletContextAttributeEvent – فئة الحدث للإشعارات حول التغييرات في السمات التابعة لـ ServletContext لتطبيق ويب.
- javax.servlet.ServletContextEvent – هذه فئة الحدث للإشعارات حول التغييرات في سياق سيرفليت لتطبيق ويب.
- javax.servlet.ServletRequestEvent – تشير الأحداث من هذا النوع إلى أحداث دورة حياة لـ ServletRequest. مصدر الحدث هو ServletContext لهذا التطبيق على الويب.
- javax.servlet.ServletRequestAttributeEvent – هذه فئة الحدث للإشعارات حول التغييرات في السمات لطلب السيرفلت في التطبيق.
واجهة Servlet API توفر واجهات مستمع الاتصالات التالية.
-
javax.servlet.AsyncListener – مستمع يُخطر في حالة اكتمال العملية الغير متزامنة التي تم تشغيلها على ServletRequest الذي تمت إضافة المستمع إليه، أو في حالة انتهاء الوقت المحدد لها، أو إذا حدث خطأ.
-
javax.servlet.ServletContextListener – واجهة لاستقبال حدث الإشعار حول تغييرات دورة حياة ServletContext.
-
javax.servlet.ServletContextAttributeListener – واجهة لاستقبال حدث الإشعار حول تغييرات سمة ServletContext.
-
javax.servlet.ServletRequestListener – واجهة لتلقي أحداث الإشعار حول الطلبات القادمة والخارجة عن نطاق تطبيق الويب.
-
javax.servlet.ServletRequestAttributeListener – واجهة لتلقي أحداث الإشعار حول تغييرات سمات ServletRequest.
-
javax.servlet.http.HttpSessionListener – واجهة لتلقي أحداث الإشعار حول تغييرات دورة حياة HttpSession.
-
javax.servlet.http.HttpSessionBindingListener – يتسبب في إخطار الكائن عند ربطه أو فك ربطه من جلسة.
-
javax.servlet.http.HttpSessionAttributeListener – واجهة لتلقي أحداث الإشعار حول تغييرات سمات HttpSession.
-
javax.servlet.http.HttpSessionActivationListener – الكائنات المرتبطة بجلسة يمكنها الاستماع إلى أحداث الحاويات التي تخطرها بأن الجلسات ستتم تجميدها وأن الجلسة ستتم تنشيطها. يُطلب من الحاوية التي تهجر الجلسة بين الآليات الظاهرية أو تحتفظ بالجلسات إخطار جميع السمات المرتبطة بالجلسات التي تنفذ HttpSessionActivationListener.
-
تكوين مستمع السيرفلت
نستخدم @WebListener تعليق لتعريف فئة كـ Listener، ومع ذلك يجب أن تنفذ الفئة واحدة أو أكثر من واجهات الـ Listener. يمكننا تعريف الـ listener في web.xml كما يلي:
<listener>
<listener-class>
com.journaldev.listener.AppContextListener
</listener-class>
</listener>
لنقم بإنشاء تطبيق ويب بسيط لرؤية استماع السيرفلت في العمل. سنقوم بإنشاء مشروع ويب ديناميكي في Eclipse مثال على استماع السيرفلت وسيكون شكل هيكل المشروع كما في الصورة أدناه. web.xml: في وصف النشر، سأقوم بتعريف بعض معلمات بدء السياق وتكوين الاستماع.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ServletListenerExample</display-name>
<context-param>
<param-name>DBUSER</param-name>
<param-value>pankaj</param-value>
</context-param>
<context-param>
<param-name>DBPWD</param-name>
<param-value>password</param-value>
</context-param>
<context-param>
<param-name>DBURL</param-name>
<param-value>jdbc:mysql://localhost/mysql_db</param-value>
</context-param>
<listener>
<listener-class>com.journaldev.listener.AppContextListener</listener-class>
</listener>
<listener>
<listener-class>com.journaldev.listener.AppContextAttributeListener</listener-class>
</listener>
<listener>
<listener-class>com.journaldev.listener.MySessionListener</listener-class>
</listener>
<listener>
<listener-class>com.journaldev.listener.MyServletRequestListener</listener-class>
</listener>
</web-app>
مدير الاتصال بقاعدة البيانات: هذه هي الفئة لتوصيل قاعدة البيانات، لبساطة لا أقدم الشيفرة للاتصال الفعلي بقاعدة البيانات. سنقوم بتعيين هذا الكائن كسمة لسياق الخدمة.
package com.journaldev.db;
import java.sql.Connection;
public class DBConnectionManager {
private String dbURL;
private String user;
private String password;
private Connection con;
public DBConnectionManager(String url, String u, String p){
this.dbURL=url;
this.user=u;
this.password=p;
// إنشاء اتصال قاعدة البيانات الآن
}
public Connection getConnection(){
return this.con;
}
public void closeConnection(){
// إغلاق اتصال قاعدة البيانات هنا
}
}
MyServlet: فئة سيرفليت بسيطة حيث سأعمل مع الجلسة والسمات وما إلى ذلك.
package com.journaldev.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext ctx = request.getServletContext();
ctx.setAttribute("User", "Pankaj");
String user = (String) ctx.getAttribute("User");
ctx.removeAttribute("User");
HttpSession session = request.getSession();
session.invalidate();
PrintWriter out = response.getWriter();
out.write("Hi "+user);
}
}
الآن سنقوم بتنفيذ فئات المستمع، أنا أقدم فئات مستمع عينة للمستمعات الشائعة الاستخدام – ServletContextListener، ServletContextAttributeListener، ServletRequestListener و HttpSessionListener. 27. ## ServletContextListener
سنقوم بقراءة معلمات بدء سياق الخدمة لإنشاء كائن DBConnectionManager وتعيينه كسمة لكائن ServletContext.
package com.journaldev.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import com.journaldev.db.DBConnectionManager;
@WebListener
public class AppContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext ctx = servletContextEvent.getServletContext();
String url = ctx.getInitParameter("DBURL");
String u = ctx.getInitParameter("DBUSER");
String p = ctx.getInitParameter("DBPWD");
// إنشاء اتصال قاعدة البيانات من معلمات البدء وتعيينه إلى السياق
DBConnectionManager dbManager = new DBConnectionManager(url, u, p);
ctx.setAttribute("DBManager", dbManager);
System.out.println("Database connection initialized for Application.");
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ServletContext ctx = servletContextEvent.getServletContext();
DBConnectionManager dbManager = (DBConnectionManager) ctx.getAttribute("DBManager");
dbManager.closeConnection();
System.out.println("Database connection closed for Application.");
}
}
A simple implementation to log the event when attribute is added, removed or replaced in servlet context.
package com.journaldev.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class AppContextAttributeListener implements ServletContextAttributeListener {
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext attribute added::{"+servletContextAttributeEvent.getName()+","+servletContextAttributeEvent.getValue()+"}");
}
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext attribute replaced::{"+servletContextAttributeEvent.getName()+","+servletContextAttributeEvent.getValue()+"}");
}
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext attribute removed::{"+servletContextAttributeEvent.getName()+","+servletContextAttributeEvent.getValue()+"}");
}
}
A simple implementation to log the event when session is created or destroyed.
package com.journaldev.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class MySessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent sessionEvent) {
System.out.println("Session Created:: ID="+sessionEvent.getSession().getId());
}
public void sessionDestroyed(HttpSessionEvent sessionEvent) {
System.out.println("Session Destroyed:: ID="+sessionEvent.getSession().getId());
}
}
A simple implementation of ServletRequestListener interface to log the ServletRequest IP address when request is initialized and destroyed.
package com.journaldev.listener;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyServletRequestListener implements ServletRequestListener {
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
ServletRequest servletRequest = servletRequestEvent.getServletRequest();
System.out.println("ServletRequest destroyed. Remote IP="+servletRequest.getRemoteAddr());
}
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
ServletRequest servletRequest = servletRequestEvent.getServletRequest();
System.out.println("ServletRequest initialized. Remote IP="+servletRequest.getRemoteAddr());
}
}
الآن عندما نقوم بنشر تطبيقنا والوصول إلى MyServlet في المستعرض مع عنوان URL https://localhost:8080/ServletListenerExample/MyServlet
، سنرى السجلات التالية في ملف سجل الخادم.
ServletContext attribute added::{DBManager,com.journaldev.db.DBConnectionManager@4def3d1b}
Database connection initialized for Application.
ServletContext attribute added::{org.apache.jasper.compiler.TldLocationsCache,org.apache.jasper.compiler.TldLocationsCache@1594df96}
ServletRequest initialized. Remote IP=0:0:0:0:0:0:0:1%0
ServletContext attribute added::{User,Pankaj}
ServletContext attribute removed::{User,Pankaj}
Session Created:: ID=8805E7AE4CCCF98AFD60142A6B300CD6
Session Destroyed:: ID=8805E7AE4CCCF98AFD60142A6B300CD6
ServletRequest destroyed. Remote IP=0:0:0:0:0:0:0:1%0
ServletRequest initialized. Remote IP=0:0:0:0:0:0:0:1%0
ServletContext attribute added::{User,Pankaj}
ServletContext attribute removed::{User,Pankaj}
Session Created:: ID=88A7A1388AB96F611840886012A4475F
Session Destroyed:: ID=88A7A1388AB96F611840886012A4475F
ServletRequest destroyed. Remote IP=0:0:0:0:0:0:0:1%0
Database connection closed for Application.
لاحظ تسلسل السجلات وأنه يتم بترتيب التنفيذ. ستظهر السجلات الأخيرة عند إيقاف تشغيل التطبيق أو إيقاف تشغيل الحاوية.
هذا كل شيء بالنسبة للمستمع في السيرفلت، سننظر إلى الكوكيز وبعض أمثلة سيرفلت الشائعة التالية. يمكنك تنزيل المشروع من الرابط أدناه والعب به لتعلم المزيد.
تحميل مثال مشروع مستمع السيرفلت
تحقق من المقالة التالية في السلسلة حول الكوكيز في السيرفلت.
Source:
https://www.digitalocean.com/community/tutorials/servletcontextlistener-servlet-listener-example