JavaWeb开发基础ServletFilter

image1

Filter是什么

image2

Filter用于对请求和响应进行预处理和后处理。Filter链(Filter Chain)允许多个Filter依次处理同一个请求和响应。

Filter的使用场景

  1. 日志记录:记录请求和响应的详细信息,例如请求时间、响应时间、请求参数等

  2. 安全检查:检查用户是否有权限访问特定资源,例如验证用户身份、检查用户角色等

  3. 压缩:对响应内容进行压缩,例如使用GZIP压缩响应数据

  4. 字符编码设置:设置请求和响应的字符编码,例如将请求和响应的字符编码设置为UTF-8

  5. 输入验证:对请求参数进行验证,例如检查参数是否为空、参数格式是否正确等

Filter Interface

Filter接口有3个方法:

package javax.servlet;

import java.io.IOException;

public interface Filter {
    void init(FilterConfig var1) throws ServletException;

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    void destroy();
}

容器在启动时创建Filter实例,并调用其init(FilterConfig filterConfig)方法进行初始化。每次请求到达时,容器调用Filter的doFilter(ServletRequest request, ServletResponse response, FilterChain chain)方法进行过滤。容器在关闭时调用Filter的destroy()方法进行清理。

Filter可以通过两种方式进行配置:

1.在web.xml中配置:

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.example.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

如果采用web.xml,那么去掉Filter只需要修改web.xml即可,不需要修改代码。

web.xml在低版本Servlet是必须的,在高版本Servlet已经不再需要。

2.使用注解配置:

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化操作
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 预处理操作
        System.out.println("Request received at " + System.currentTimeMillis());

        // 继续执行下一个过滤器或目标资源
        chain.doFilter(request, response);

        // 后处理操作
        System.out.println("Response sent at " + System.currentTimeMillis());
    }

    @Override
    public void destroy() {
        // 清理操作
    }
}

FilterChain Interface

Filter接口的doFilter方法,第3个参数类型是FilterChain,它的定义如下:

package javax.servlet;

import java.io.IOException;

public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

FilterChain用于在Servlet过滤器链中传递请求和响应对象。FilterChain的实现由Servlet容器(如Tomcat、Jetty等)负责。容器在部署应用时,会根据web.xml配置文件或注解扫描来确定过滤器的顺序,并创建一个FilterChain对象来管理这些过滤器。当chain.doFilter(request, response)被调用时,FilterChain会递增索引并调用下一个过滤器的doFilter方法。如果没有更多的过滤器,FilterChain会将请求传递给最终的目标资源(如Servlet)。

FilterConfig Interface

FilterConfig用于在过滤器初始化时提供配置信息,它包含了过滤器的初始化参数和Servlet上下文。主要方法如下:

  1. String getFilterName():返回过滤器的名称

  2. ServletContext getServletContext():返回Servlet上下文对象

  3. String getInitParameter(String name):根据参数名称获取初始化参数的值

  4. Enumeration<String> getInitParameterNames():返回所有初始化参数的名称

Filter示例

验证用户身份:

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AuthenticationFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化代码
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 获取身份验证信息,例如从请求头中获取令牌
        String authToken = httpRequest.getHeader("Authorization");

        // 验证令牌
        if (isValidToken(authToken)) {
            // 如果令牌有效,继续处理请求
            chain.doFilter(request, response);
        } else {
            // 如果令牌无效,返回401未授权状态
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
        }
    }

    private boolean isValidToken(String token) {
        // 令牌验证逻辑,例如检查令牌是否存在和有效
        return token != null && token.equals("valid-token");
    }

    @Override
    public void destroy() {
        // 清理代码
    }
}

统计访问用户数:

import java.io.*;
import javax.servlet.*;

public class MyFilter implements Filter {
    static int count = 0;

    public void init(FilterConfig arg0) throws ServletException {}

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        PrintWriter out = res.getWriter();

        // 继续传递请求和响应
        chain.doFilter(req, res);

        // 输出总访问人数
        out.print("<br/>Total visitors " + (++count));
        out.close();
    }

    public void destroy() {}
}

计算响应时长:

import java.io.*;
import javax.servlet.*;

public class MyFilter implements Filter {
    static int count = 0;

    public void init(FilterConfig arg0) throws ServletException {}

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        PrintWriter out = res.getWriter();
        long before = System.currentTimeMillis();

        // 继续传递请求和响应
        chain.doFilter(req, res);

        long after = System.currentTimeMillis();
        out.print("<br/>Total response time " + (after - before) + " milliseconds");
        out.close();
    }

    public void destroy() {}
}

直接发送响应并关闭输出流:

import java.io.*;
import javax.servlet.*;

public class MyFilter implements Filter {
    public void init(FilterConfig arg0) throws ServletException {}

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        PrintWriter out = res.getWriter();

        out.print("<br/>This site is under construction..");
        out.close();
    }

    public void destroy() {}
}

总结,Filter是一个强大的工具,可以在请求和响应的生命周期中进行各种预处理和后处理操作。通过合理使用Filter,可以实现许多常见的Web应用需求,如日志记录、身份验证、授权、压缩等。