Java Servlet 过滤器示例教程

Java Servlet Filter 用于拦截客户端请求并进行一些预处理。它还可以拦截响应并在发送到 Web 应用程序的客户端之前进行后处理。这是 Web 应用程序教程系列的第四篇文章,您可能也想查看之前的文章。

  1. Java Web 应用程序
  2. Java Servlet 教程
  3. Servlet 会话管理

Servlet 过滤器

在这篇文章中,我们将学习有关 Java 中 Servlet 过滤器的内容。我们将探讨 Servlet 过滤器的各种用途,以及如何创建过滤器,并通过一个简单的 Web 应用程序学习其用法。

  1. 为什么我们需要 Servlet 过滤器?

  2. Servlet 过滤器接口

  3. Servlet WebFilter 注解

  4. 在web.xml中的Servlet Filter配置

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

  6. 为什么我们需要Servlet过滤器?

    在上一篇文章中,我们学习了如何在Web应用程序中管理会话,如果我们想确保只有在用户会话有效时才能访问资源,我们可以使用Servlet会话属性来实现。这种方法很简单,但如果我们有很多Servlet和JSP,那么由于冗余代码的存在,维护将变得困难。如果我们将来想要更改属性名称,就必须更改所有存在会话认证的地方。这就是为什么我们有了Servlet过滤器。Servlet过滤器是可插拔的Java组件,我们可以使用它们来拦截和处理请求,在将请求发送到Servlet和在容器将响应发送回客户端之前处理响应之前。一些常见的使用Servlet过滤器的任务包括:

    • 将请求参数记录到日志文件中。
    • 对资源的请求进行身份验证和授权。
    • 在将其发送到Servlet之前格式化请求主体或标头。
    • 压缩发送到客户端的响应数据。
    • 通过添加一些Cookie、标头信息等来修改响应。

    正如我之前提到的,Servlet过滤器是可插拔的,并在部署描述符(web.xml)文件中配置。Servlet和过滤器都不知道彼此的存在,我们可以通过编辑web.xml来添加或删除Servlet过滤器。我们可以为单个资源拥有多个过滤器,并且我们可以在web.xml中为单个资源创建过滤器链。我们可以通过实现javax.servlet.Filter接口来创建Servlet过滤器。

  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过滤器。我们可以使用此注解来定义初始化参数、过滤器名称和描述、Servlet、URL模式和分发器类型以应用该过滤器。如果您经常更改过滤器配置,最好使用web.xml,因为这样就不需要重新编译过滤器类。 阅读Java注解教程

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

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

    <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-patterns。

    <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-patterns,然后是servlet-names,所以如果您要确保过滤器按特定顺序执行,请在定义过滤器映射时特别注意。Servlet过滤器通常用于客户端请求,但有时我们希望在RequestDispatcher中应用过滤器,也可以在这种情况下使用dispatcher元素,可能的值包括REQUEST、FORWARD、INCLUDE、ERROR和ASYNC。如果未定义分派程序,则仅应用于客户端请求。

  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 { // 获取userID和密码的请求参数 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过滤器的全部内容。这是Java EE Web应用程序的重要特性之一,我们应该将其用于各种Servlet执行的常见任务。在将来的帖子中,我们将深入研究Servlet监听器和Cookie。更新:由于收到了许多关于可下载项目的请求,我已将其附加到帖子中,可以从下面的链接下载。

下载Servlet过滤器示例项目

查看查看系系列列文章文章中中关于关<于diServlet3> 监Servlet听监听器器3的下>y的4下>一更新 Struts 2 使用 Servlet 过客 Str户uts端 请求2并 使用将Servlet其过转滤发器到拦适当的操作类,这些称为截 Struts客 户2端请求 拦并将截其器转。查发看<到diy5>的Struts操作 类2, 初这学些者称教为程。截器。 查看Struts 2初学者教程

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