Java Servlet 过滤器示例教程

Java Servlet Filter 用於攔截客戶端請求並進行一些預處理。它還可以攔截響應並在發送到 Web 應用程序中的客戶端之前進行後處理。這是 Web 應用程序教程系列的第四篇文章,您可能也想查看之前的文章。

  1. Java Web 應用程序
  2. Java Servlet 教程
  3. Servlet 會話管理

Servlet Filter

在本文中,我們將了解 Java 中的 Servlet Filter。我們將探討 servlet filter 的各種用法,如何創建過濾器以及通過簡單的 Web 應用程序學習其使用方法。

  1. 我們為什麼需要 Servlet Filter?

  2. Servlet Filter 接口

  3. Servlet WebFilter 注釋

  4. web.xml 中的 Servlet Filter 配置

  5. 用于日志记录和会话验证的 Servlet Filter 示例

  6. 我們為什麼需要 Servlet Filter?

    在上一篇文章中,我們了解了如何在 Web 應用程式中管理會話,如果我們想要確保只有在使用者會話有效時才能訪問資源,我們可以使用 Servlet 會話屬性來實現這一點。這種方法很簡單,但如果我們有很多 Servlet 和 JSP,由於代碼重複,維護將變得困難。如果將來我們想要更改屬性名稱,就必須更改所有已進行會話驗證的地方。這就是為什麼我們有了 Servlet Filter。Servlet Filter 是可插入的 Java 組件,我們可以使用它們來攔截並處理請求,它們在將請求發送到 Servlet 之前以及 Servlet 代碼完成後以及容器將響應發送回客戶端之前處理。一些常見的 Servlet Filter 任務包括:

    • 將請求參數記錄到日誌文件中。
    • 對資源的請求進行身份驗證和授權。
    • 在將其發送到 Servlet 之前對請求主體或標頭進行格式化。
    • 壓縮發送到客戶端的響應數據。
    • 通過添加一些 Cookie、標頭信息等來更改響應。

    正如我之前提到的,Servlet Filter 是可插入的並且在部署描述符(web.xml)文件中進行配置。Servlet 和 Filter 都不知道彼此的存在,我們可以通過編輯 web.xml 文件來添加或刪除 Servlet Filter。我們可以為單個資源設置多個過濾器,在 web.xml 中為單個資源創建過濾器鏈。我們可以通過實現 javax.servlet.Filter 接口來創建 Servlet Filter。

  7. Servlet Filter介面

    Servlet Filter介面類似於Servlet介面,我們需要實現它來創建我們自己的Servlet過濾器。Servlet Filter介面包含過濾器的生命周期方法,並由Servlet容器管理。Servlet Filter介面的生命周期方法包括:

    1. void init(FilterConfig paramFilterConfig) – 當容器初始化過濾器時,將調用此方法。此方法僅在過濾器的生命周期中調用一次,我們應該在此方法中初始化任何資源。 FilterConfig 被容器用於提供初始參數和Servlet上下文對象給過濾器。我們可以在此方法中拋出ServletException。
    2. doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) – 當容器需要對資源應用過濾器時,每次都會調用此方法。容器將請求和響應對象引用作為過濾器的參數。 FilterChain 用於調用鏈中的下一個過濾器。這是 責任鏈模式 的一個很好的例子。
    3. void destroy() – 當容器卸載過濾器實例時,將調用destroy()方法。這是我們可以關閉過濾器打開的任何資源的方法。此方法僅在過濾器的生命週期中調用一次。
  8. Servlet WebFilter 注解

    javax.servlet.annotation.WebFilter 在 Servlet 3.0 中引入,我們可以使用此注解來聲明 servlet filter。我們可以使用此注解來定義初始化參數、filter 名稱和描述、servlets、URL 模式和調度程序類型來應用該 filter。如果您經常更改 filter 配置,最好使用 web.xml,因為這不需要重新編譯 filter 類。 閱讀: Java Annotations 教程

  9. 在web.xml中配置Servlet过滤器

    我们可以像下面这样在web.xml中声明一个Servlet过滤器。

    <filter>
      <filter-name>RequestLoggingFilter</filter-name> <!-- mandatory -->
      <filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class> <!-- mandatory -->
      <init-param> <!-- optional -->
      <param-name>test</param-name>
      <param-value>testValue</param-value>
      </init-param>
    </filter>
    

    我们可以像下面这样将过滤器映射到Servlet类或url-patterns。

    <filter-mapping>
      <filter-name>RequestLoggingFilter</filter-name> <!-- mandatory -->
      <url-pattern>/*</url-pattern> <!-- either url-pattern or servlet-name is mandatory -->
      <servlet-name>LoginServlet</servlet-name>
      <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    

    注意:在为Servlet创建过滤器链时,容器首先处理url-patterns,然后是servlet-names,因此如果要确保过滤器按特定顺序执行,请在定义过滤器映射时特别注意。Servlet过滤器通常用于处理客户端请求,但有时我们希望在RequestDispatcher中也应用过滤器,可以在这种情况下使用dispatcher元素,可能的值包括REQUEST、FORWARD、INCLUDE、ERROR和ASYNC。如果未定义调度程序,则仅对客户端请求应用过滤器。

  10. 用于日志记录和会话验证的 Servlet Filter 示例

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 { // 获取userID和password的请求参数 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 ```

以上是关于Java中Servlet Filter的全部内容。这是Java EE Web应用程序的重要特性之一,我们应该将其用于各种Servlet执行的常见任务。在未来的帖子中,我们将研究Servlet监听器和Cookie。更新:在收到许多关于可下载项目的请求后,我已经将其附加到帖子中,您可以从以下链接下载。

下载Servlet Filter示例项目

請查看關於 Servlet 監聽器 的下一篇文章。 更新 Struts 2 使用 Servlet 過濾器來攔截客戶端請求並將它們轉發到適當的動作類別,這些被稱為 Struts 2 攔截器。請查看 Struts 2 初學者教程

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