تُستخدم مرشح Servlet في Java للتقاط طلب العميل وإجراء بعض العمليات القبلية. يمكن أيضًا أن يقوم بالتقاط الاستجابة وإجراء مراحل ما بعد المعالجة قبل إرسالها إلى العميل في تطبيق الويب. هذا هو المقال الرابع في سلسلة دروس تطبيقات الويب. قد ترغب في مراجعة المقالات السابقة أيضًا.
مرشح Servlet
في هذا المقال، سنتعرف على مرشح Servlet في جافا. سنلقي نظرة على مختلف استخدامات مرشح السيرفلت، كيف يمكننا إنشاء مرشح ونتعلم كيفية استخدامه مع تطبيق ويب بسيط.
-
لماذا لدينا Servlet Filter؟
في المقالة السابقة، تعلمنا كيف يمكننا إدارة الجلسة في تطبيق الويب وإذا أردنا التأكد من أن المورد يمكن الوصول إليه فقط عندما تكون جلسة المستخدم صالحة، يمكننا تحقيق ذلك باستخدام سمات جلسة السيرفلت. الطريقة بسيطة ولكن إذا كان لدينا العديد من السيرفلتات والجي إس بيز، ستصبح صعبة الصيانة بسبب تكرار الشيفرة. إذا كنا نرغب في تغيير اسم السمة في المستقبل، سنضطر إلى تغيير كل الأماكن التي قمنا فيها بالتحقق من صحة الجلسة. ولهذا السبب لدينا Servlet Filter. Servlet Filters هي مكونات جافا القابلة للتوصيل التي يمكننا استخدامها للاعتراض على الطلبات ومعالجتها قبل إرسالها إلى السيرفلتات والرد بعد أن يتم الانتهاء من شيفرة السيرفلت وقبل أن يقوم الحاوية بإرسال الرد إلى العميل. بعض المهام الشائعة التي يمكننا القيام بها باستخدام Servlet Filters هي:
- تسجيل معلمات الطلب في ملفات السجل.
- المصادقة والتفويض لطلبات الموارد.
- تنسيق جسم الطلب أو الرأس قبل إرساله إلى السيرفلت.
- ضغط بيانات الرد المرسلة إلى العميل.
- تعديل الرد بإضافة بعض الكوكيز، ومعلومات الرأس، إلخ.
كما ذكرت سابقًا، Servlet Filters قابلة للتوصيل ويتم تكوينها في ملف الوصف النهائي (web.xml). السيرفلتات والفلاتر غير مدركة لبعضها البعض ويمكننا إضافة أو إزالة فلتر سيرفلت فقط عن طريق تحرير web.xml. يمكننا أن نمتلك عدة فلاتر لمورد واحد ويمكننا إنشاء سلسلة من الفلاتر لمورد واحد في web.xml. يمكننا إنشاء فلتر سيرفلت عن طريق تنفيذ واجهة
javax.servlet.Filter
. -
واجهة مرشح Servlet Filter
واجهة مرشح Servlet Filter مشابهة لواجهة Servlet ونحتاج إلى تنفيذها لإنشاء مرشح الخاص بنا. تحتوي واجهة مرشح Servlet Filter على أساليب دورة حياة المرشح ويتم إدارتها بواسطة حاوية servlet. تشمل أساليب دورة حياة واجهة مرشح Servlet Filter ما يلي:
- void init(FilterConfig paramFilterConfig) – عندما تقوم الحاوية بتهيئة المرشح، هذه هي الطريقة التي يتم استدعاؤها. يتم استدعاء هذه الطريقة مرة واحدة فقط في دورة حياة المرشح ويجب علينا تهيئة أي موارد في هذه الطريقة. تُستخدم FilterConfig من قبل الحاوية لتوفير معلمات التهيئة وكائن سياق servlet إلى المرشح. يمكننا رمي ServletException في هذه الطريقة.
- doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) – هذه هي الطريقة التي يتم استدعاؤها في كل مرة من قبل الحاوية عندما يتعين عليها تطبيق مرشح على مورد. توفر الحاوية مراجع كائنات الطلب والاستجابة للمرشح كوسيط. يتم استخدام FilterChain لاستدعاء المرشح التالي في السلسلة. هذا مثال رائع على نمط سلسلة المسؤولية.
- void destroy() – عندما تُفرغ الحاوية مثيل المرشح، فإنها تستدعي طريقة destroy(). هذه هي الطريقة التي يمكننا فيها إغلاق أي موارد تم فتحها بواسطة المرشح. يتم استدعاء هذه الطريقة مرة واحدة فقط في حياة المرشح.
-
Servlet WebFilter التعليق
javax.servlet.annotation.WebFilter
تم إدخاله في Servlet 3.0 ويمكننا استخدام هذا التعليق لتعريف فلتر سيرفليت. يمكننا استخدام هذا التعليق لتحديد معلمات البدء، اسم الفلتر والوصف، السيرفليت، أنماط عناوين URL وأنواع الموجهات لتطبيق الفلتر. إذا قمت بتغييرات متكررة على تكوينات الفلتر ، فمن الأفضل استخدام web.xml لأن ذلك لن يتطلب إعادة تجميع فئة الفلتر. اقرأ: دليل تعليمي عن التعليقات في جافا -
تكوين مرشح Servlet في web.xml
يمكننا أن نعلن مرشح servlet في web.xml كما يلي.
<filter> <filter-name>RequestLoggingFilter</filter-name> <!-- إلزامي --> <filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class> <!-- إلزامي --> <init-param> <!-- اختياري --> <param-name>test</param-name> <param-value>testValue</param-value> </init-param> </filter>
يمكننا تعيين مرشح إلى فئات servlet أو أنماط url مثل ما يلي.
<filter-mapping> <filter-name>RequestLoggingFilter</filter-name> <!-- إلزامي --> <url-pattern>/*</url-pattern> <!-- إما url-pattern أو servlet-name إلزامي --> <servlet-name>LoginServlet</servlet-name> <dispatcher>REQUEST</dispatcher> </filter-mapping>
ملاحظة: أثناء إنشاء سلسلة المرشح لـ servlet ، يقوم الحاوية بمعالجة أنماط url أولاً ثم أسماء servlet ، لذا إذا كان عليك التأكد من تنفيذ المرشحات بترتيب معين ، فتوخ الاهتمام إضافي أثناء تعريف تعيين المرشح. عمومًا ، تُستخدم مرشحات Servlet لطلبات العميل ولكن في بعض الأحيان نريد تطبيق المرشحات مع RequestDispatcher أيضًا ، يمكننا استخدام عنصر الموزع في هذه الحالة ، القيم الممكنة هي REQUEST، FORWARD، INCLUDE، ERROR وASYNC. إذا لم يتم تحديد موزع ، يتم تطبيقه فقط على طلبات العميل.
-
مثال على مرشح الخدمة لتسجيل الدخول والتحقق من الجلسة
In our **servlet filter example**, we will create filters to log request cookies and parameters and validate session to all the resources except static HTMLs and LoginServlet because it will not have a session. We will create a dynamic web project **ServletFilterExample** whose project structure will look like the below image. [](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Example-Project.png) login.html is the entry point of our application where the user will provide the login id and password for authentication. login.html code:
```
Login Page
```
LoginServlet is used to authenticate the request from the client for login.
```
package com.journaldev.servlet.session;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class LoginServlet
*/
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final String userID = "admin";
private final String password = "password";
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// الحصول على معلمات الطلب لمعرف المستخدم وكلمة المرور
String user = request.getParameter("user");
String pwd = request.getParameter("pwd");
if(userID.equals(user) && password.equals(pwd)){
HttpSession session = request.getSession();
session.setAttribute("user", "Pankaj");
// ضبط جلسة الاستخدام لتنتهي خلال 30 دقيقة
session.setMaxInactiveInterval(30*60);
Cookie userName = new Cookie("user", user);
userName.setMaxAge(30*60);
response.addCookie(userName);
response.sendRedirect("LoginSuccess.jsp");
}else{
RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
PrintWriter out= response.getWriter();
out.println("Either user name or password is wrong.");
rd.include(request, response);
}
}
}
```
When the client is authenticated, it's forwarded to LoginSuccess.jsp LoginSuccess.jsp code:
```
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
Login Success Page
<%
// السماح بالوصول فقط إذا كانت الجلسة موجودة
String user = (String) session.getAttribute("user");
String userName = null;
String sessionID = null;
Cookie[] cookies = request.getCookies();
if(cookies !=null){
for(Cookie cookie : cookies){
if(cookie.getName().equals("user")) userName = cookie.getValue();
if(cookie.getName().equals("JSESSIONID")) sessionID = cookie.getValue();
}
}
%>
Hi <%=userName %>, Login successful. Your Session ID=<%=sessionID %>
User=<%=user %>
Checkout Page
```
Notice that there is no session validation logic in the above JSP. It contains a link to another JSP page, CheckoutPage.jsp. CheckoutPage.jsp code:
```
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
Login Success Page
<%
String userName = null;
String sessionID = null;
Cookie[] cookies = request.getCookies();
if(cookies !=null){
for(Cookie cookie : cookies){
if(cookie.getName().equals("user")) userName = cookie.getValue();
}
}
%>
Hi <%=userName %>, do the checkout.
```
LogoutServlet is invoked when a client clicks on the Logout button in any of the JSP pages.
```
package com.journaldev.servlet.session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class LogoutServlet
*/
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
if(cookie.getName().equals("JSESSIONID")){
System.out.println("JSESSIONID="+cookie.getValue());
break;
}
}
}
// إلغاء الجلسة إذا كانت موجودة
HttpSession session = request.getSession(false);
System.out.println("User="+session.getAttribute("user"));
if(session != null){
session.invalidate();
}
response.sendRedirect("login.html");
}
}
```
Now we will create logging and authentication servlet filter classes.
```
package com.journaldev.servlet.filters;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
/**
* Servlet Filter implementation class RequestLoggingFilter
*/
@WebFilter("/RequestLoggingFilter")
public class RequestLoggingFilter implements Filter {
private ServletContext context;
public void init(FilterConfig fConfig) throws ServletException {
this.context = fConfig.getServletContext();
this.context.log("RequestLoggingFilter initialized");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
Enumeration params = req.getParameterNames();
while(params.hasMoreElements()){
String name = params.nextElement();
String value = request.getParameter(name);
this.context.log(req.getRemoteAddr() + "::Request Params::{"+name+"="+value+"}");
}
Cookie[] cookies = req.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
this.context.log(req.getRemoteAddr() + "::Cookie::{"+cookie.getName()+","+cookie.getValue()+"}");
}
}
// تمرير الطلب عبر سلسلة الفلتر
chain.doFilter(request, response);
}
public void destroy() {
// يمكننا إغلاق الموارد هنا
}
}
```
```
package com.journaldev.servlet.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebFilter("/AuthenticationFilter")
public class AuthenticationFilter implements Filter {
private ServletContext context;
public void init(FilterConfig fConfig) throws ServletException {
this.context = fConfig.getServletContext();
this.context.log("AuthenticationFilter initialized");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String uri = req.getRequestURI();
this.context.log("Requested Resource::"+uri);
HttpSession session = req.getSession(false);
if(session == null && !(uri.endsWith("html") || uri.endsWith("LoginServlet"))){
this.context.log("Unauthorized access request");
res.sendRedirect("login.html");
}else{
// تمرير الطلب عبر سلسلة الفلتر
chain.doFilter(request, response);
}
}
public void destroy() {
// إغلاق أي موارد هنا
}
}
```
Notice that we are not authenticating any HTML page or LoginServlet. Now we will configure these filters mapping in the web.xml file.
```
ServletFilterExample
login.html
RequestLoggingFilter
com.journaldev.servlet.filters.RequestLoggingFilter
AuthenticationFilter
com.journaldev.servlet.filters.AuthenticationFilter
RequestLoggingFilter
/*
REQUEST
AuthenticationFilter
/*
```
Now when we will run our application, we will get response pages like below images. [](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login.png) [](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-Success.png) [](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Checkout.png) If you are not logged in and try to access any JSP page, you will be forwarded to the login page. In the server log file, you can see the logs written by servlet filters as well as servlets.
```
Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A}
Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
INFO: Requested Resource::/ServletFilterExample/
Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
INFO: Unauthorized access request
Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A}
Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
INFO: Requested Resource::/ServletFilterExample/login.html
Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Request Params::{pwd=password}
Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Request Params::{user=admin}
Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A}
Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
INFO: Requested Resource::/ServletFilterExample/LoginServlet
Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
INFO: Requested Resource::/ServletFilterExample/LoginSuccess.jsp
Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log
INFO: Requested Resource::/ServletFilterExample/CheckoutPage.jsp
Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
INFO: Requested Resource::/ServletFilterExample/LogoutServlet
JSESSIONID=8BDF777933194EDCAC1D8F1B73633C56
User=Pankaj
Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
INFO: Requested Resource::/ServletFilterExample/login.html
Aug 13, 2013 1:07:06 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
INFO: Requested Resource::/ServletFilterExample/LoginSuccess.jsp
Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
INFO: Unauthorized access request
Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
INFO: Requested Resource::/ServletFilterExample/login.html
```
هذا كل شيء بالنسبة لـ فلتر السيرفليت في جافا. إنها واحدة من الميزات المهمة لتطبيقات الويب في جافا إي إي، ويجب علينا استخدامها للمهام الشائعة التي يقوم بها مختلف السيرفليت. في المشاركات المستقبلية، سننظر إلى المستمعين الخاصين بالسيرفليت والكوكيز. التحديث: بعد الحصول على الكثير من الطلبات للمشروع القابل للتنزيل، لقد قمت بتضمينه في المنشور، قم بتنزيله من الرابط أدناه.
تحميل مثال مشروع فلتر السيرفليت
تحقق من المقالة التالية في السلسلة حول سماع الخدمة. تحديث يستخدم Struts 2 مرشح الخدمة للتقاط طلبات العميل وتوجيهها إلى فئات الإجراء المناسبة، وتُسمى هذه المرشحات Struts 2 Interceptors. تحقق من دورة تعليمية لمبتدئي Struts 2.
Source:
https://www.digitalocean.com/community/tutorials/java-servlet-filter-example-tutorial