הדוגמה הממומנת של פילטר של Java Servlet

Java Servlet Filter משמש להפרעה בבקשה של הלקוח ולביצוע עיבוד מוקדם. ניתן גם להפרע מהתגובה ולבצע עיבוד לאחר מכן לפני שנשלח ללקוח באפליקציית האינטרנט. זהו המאמר הרביעי בסדרה של מדריכי אפליקציות אינטרנט, ייתכן שתרצה לבדוק גם מאמרים קודמים.

  1. Java Web Application
  2. Java Servlet Tutorial
  3. Servlet Session Management

Servlet Filter

במאמר זה, נלמד על סינון Servlet ב-Java. נבחן שימושים שונים של סינון servlet, כיצד ניתן ליצור סינון ונלמד על השימוש שלו באמצעות אפליקציה אינטרנט פשוטה.

  1. למה יש לנו סינון Servlet?

  2. ממשק סינון Servlet

  3. הערה Servlet WebFilter

  4. תצורת פילטר סרוולט ב-web.xml

  5. דוגמת פילטר סרוולט ללוגים ואימות הסשן

  6. למה יש לנו מסנני Servlet?

    במאמר האחרון, למדנו כיצד ניתן לנהל סשן ביישום אינטרנטי ואם רוצים לוודא שמשאב נגיש רק כאשר הסשן של המשתמש תקין, נוכל להשיג זאת באמצעות תכונות הסשן של Servlet. הגישה פשוטה אך אם יש לנו הרבה סרבלטים וJSPs, אז זה יהפוך לקשה לתחזוקה בגלל קוד מיותר. אם נרצה לשנות את שם התכונה בעתיד, נצטרך לשנות את כל המקומות בהם יש אימות סשן. לכן יש לנו מסנן Servlet. מסנני Servlet הם מרכיבי ג'אווה הניתנים להרכבה שאנו יכולים להשתמש בהם כדי להתערב ולעבד בקשות לפני שהן נשלחות לסרבלטים ולתגובה לאחר שקוד הסרבלט נגמר ולפני שהתכולה של המכולה נשלחת בחזרה ללקוח. כמה משימות נפוצות שניתן לבצע באמצעות מסנני Servlet הם:

    • יומן שימוש בפרמטרי בקשה לקבצי לוג.
    • אימות ואישור של בקשה למשאבים.
    • עיצוב של גוף הבקשה או הכותרת לפני ששולחים אותו לסרבלט.
    • כיווץ נתוני התגובה שנשלחים ללקוח.
    • שינוי התגובה על ידי הוספת עוגיות, מידע כותרת וכו '.

    כפי שצוין למעלה, מסנני Servlet הם רכיבי ג'אווה הניתנים להרכבה ומוגדרים בקובץ מתאר הפיתוח (web.xml). סרבלטים ומסננים הם שניים עצמאיים זה מזה וניתן להוסיף או להסיר מסנן Servlet רק על ידי עריכת web.xml. ניתן להוסיף מסננים מרובים עבור משאב יחיד וניתן ליצור שרשרת של מסננים עבור משאב יחיד ב web.xml. ניתן ליצור מסנן Servlet על ידי המימוש javax.servlet.Filter.

  7. ממשק מסננת של Servlet

    ממשק מסננת של Servlet דומה לממשק של Servlet, ואנו צריכים לממש אותו כדי ליצור מסנן Servlet משלנו. ממשק מסננת של Servlet מכיל את שלבי החיים של מסנן, והוא מנוהל על ידי מכונת ה-Servlet. שלבי החיים של ממשק מסננת של Servlet הם:

    1. void init(FilterConfig paramFilterConfig) – כאשר מכונת ה-Container מאתחלת את המסנן, זוהי השיטה שמופעלת. שיטה זו נקראת רק פעם אחת במחזור חיי המסנן, ועלינו לאתחל כל משאבים בשיטה זו. FilterConfig משמש על ידי מכונת ה-Container לספק פרמטרי init ועצם ה-Kontext של ה-Servlet למסנן. אנו יכולים לזרוק ServletException בשיטה זו.
    2. doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) – זו השיטה שמופעלת בכל פעם על ידי מכונת ה-Container כאשר עליה להחיל מסנן על משאב. מכונת ה-Container סופקת את רפרנסי אובייקטי הבקשה והתגובה למסנן כפרמטר. FilterChain משמש לקרוא למסנן הבא בשרשור. זהו דוגמה נהדרת לתבנית של Chain of Responsibility Pattern.
    3. void destroy() – כאשר מכונת ה-Container מעמידה את מופע המסנן להורדה, היא מפעילה את שיטת ה destroy(). זוהי השיטה בה ניתן לסגור כל משאב שנפתח על ידי המסנן. שיטה זו נקראת רק פעם אחת במחזור חיי המסנן.
  8. Servlet WebFilter annotation

    javax.servlet.annotation.WebFilter נוכנסה ב- Servlet 3.0 וניתן להשתמש באנוטציה זו כדי להכריז על פילטר סרבל. ניתן להשתמש באנוטציה זו כדי להגדיר פרמטרי יישום, שם פילטר ותיאור, סרבלים, דפוסי כתובות URL וסוגי תפעול ליישום הפילטר. אם אתה עושה שינויים תדידים בהגדרות הפילטר, עדיף להשתמש ב-web.xml מכיוון שזה לא ידרוש ממך להפעיל מחדש את מחלקת הפילטר.קרא: מדריך לאנוטציות ב-Java

  9. הגדרת מסנן 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 גם, אפשר להשתמש ברכיב ה-Dispatcher במקרה זה, הערכים האפשריים הם REQUEST, FORWARD, INCLUDE, ERROR ו-ASYNC. אם לא הוגדר Dispatcher, המסנן מיושם רק על דרישות לקוח.

  10. דוגמה על מסנן Servlet לרישום ואימות סשן

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. [![Servlet Filter Example, Java Filter](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Example-Project.png)](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


Username:
Password:
``` 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. [![Servlet Filter Example](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-450x141.png)](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login.png) [![Servlet Filter, Java Filter](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-Success-450x229.png)](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-Success.png) [![Servlet Filter Tutorial, Java Servlet Filter](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Checkout-450x181.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 ```

זהו כל הקשור לסנן Servlet ב-Java. זו אחת מתכונות Java EE שחשוב להשתמש בה למשימות נפוצות בין סרבלים שונים. בפוסטים עתידים, נבחן את האזנני Servlet ועוגיות. עדכון: לאחר קבלת הרבה בקשות לפרויקט הניתן להורדה, הוסרתי אותו לפוסט, ניתן להוריד אותו מהקישור למטה.

הורד פרויקט דוגמת Servlet Filter

בדוק את המאמר הבא בסדרת המאמרים על ספר התקשורת. עדכון Struts 2 משתמש בפילטר Servlet כדי להתערב בבקשות הלקוח ולהעביר אותן למחלקות פעולה מתאימות, אלו נקראים Struts 2 מתערבים. בדוק מדריך למתחילים ב-Struts 2.

Source:
https://www.digitalocean.com/community/tutorials/java-servlet-filter-example-tutorial