servlet中Filter过滤器源码解析

servlet中Filter过滤器源码解析

文章目录

  • servlet中Filter过滤器源码解析
      • 一、简介
      • 二、Filter过滤器
        • 2.1 核心类
          • 2.1.1 Filter接口
          • 2.1.2 FilterConfig
          • 2.1.3 FilterChain
        • 2.2 注册
      • 三、示例

一、简介

在servlet开发中,对于请求的拦截,常使用filter过滤器,这里结合源码对Filter过滤器进行介绍。

二、Filter过滤器

Filter过滤器是实现特殊接口的java类,由servlet容器调用执行,可用于权限过滤、日志记录、图片转换、加密、数据压缩等操作。

2.1 核心类

Filter过滤器核心类是Filter,关联的还有有FilterConfig、FilterChain,其实是三个接口,。下面结合源码分别介绍。

2.1.1 Filter接口

Filter是在请求到响应(servlet或静态资源),或者一个响应到另一个响应中间,执行过滤任务的对象。Filter执行过滤任务是在方法doFilter中。源码如下:

package javax.servlet;

import java.io.IOException;
public interface Filter {
    //初始化方法,容器创建Filter对象后,立即调用init方法,整个生命周期中只执行一次。
    //在init方法成功(失败如抛异常等)执行完前,不能提供过滤服务。
    //参数FilterConfig用于获取初始化参数
    public void init(FilterConfig filterConfig) throws ServletException;

    //执行过滤任务的方法,参数FilterChain表示Filter链,doFilter方法中只有执行FilterChain只有执行了doFilter方法,
    //才能将请求交经下一个Filter或Servlet执行
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException;

    //销毁方法,当移出服务时由web容器调用。整个生命周期中destroy方法只会执行一次
    //destroy方法可用于释放持有的资源,如内存、文件句柄等
    public void destroy();
}
2.1.2 FilterConfig

FilterConfig用于获取过滤器的初始化参数。源码如下:

package javax.servlet;
import java.util.Enumeration;
public interface FilterConfig {
    //获取过滤器名称
    public String getFilterName();

    //获取关联的ServletContext
    public ServletContext getServletContext();

    //获取指定名称的初始化参数
    public String getInitParameter(String name);

    //获取初始化参数名称集合
    public Enumeration<String> getInitParameterNames();
}
2.1.3 FilterChain

FilterChain是容器提供给开发者的,用于调用Filter链上的下一个Filter或最终servlet服务。

package javax.servlet;
import java.io.IOException;

public interface FilterChain {
    //调用引用链的下一个filter或最终servlet服务
    public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
}

2.2 注册

过滤器注册有两种方式,使用常规的xml注册和使用注解注册(会在示例代码中以注释的方式体现)。这里以常规xml注册为例。xml注册是在项目的web.xml上注册的,可以对指定访问路径或指定servlet进行拦截,示例如下:

    <filter-name>demoFitlerfilter-name>
    <filter-class>filter.DemoFilterfilter-class>
    <init-param>
      
      <param-name>forbidIdsparam-name>
      <param-value>002,003,004param-value>
    init-param>
  filter>
  <filter-mapping>
    <filter-name>demoFitlerfilter-name>
    <url-pattern>/*url-pattern>
    
    
  filter-mapping>

三、示例

资源servlet类DemoServlet.java如下:

package filter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name="DemoServlet", urlPatterns = "/demoServlet")
public class DemoServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write("this is a demo test");
    }
}

过滤器DemoFilter.java

package filter;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
import java.util.Objects;

//可以使用下面注解方式注册Filter,其中urlPatterns拦截指定路径,demoServlet拦截指定servlet
//@WebFilter(filterName = "demoFilter", urlPatterns = "/*", servletNames = "demoServlet",
//        initParams = {@WebInitParam(name = "forbidIds", value = "002,003,004")})
public class DemoFilter implements Filter {
    private FilterConfig filterConfig;
    private String forbidIds;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        //获取初始化参数
        forbidIds = filterConfig.getInitParameter("forbidIds");
        System.out.println("forbidIds:" + forbidIds);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        String id = request.getParameter("id");
        if (StringUtils.isBlank(forbidIds) || !forbidIds.contains(Objects.toString(id, "001"))) {
            //不拦截,调用后续访问
            chain.doFilter(request, response);
        } else {
            //拦截,输出错误信息
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write("forbid");
        }
    }

    @Override
    public void destroy() {
        System.out.println("DemoFilter destroy");
    }
}

响应:

请求:http://localhost:8080/demoServlet?id=001
响应:this is a demo test

请求:http://localhost:8080/demoServlet?id=002
响应:forbid

你可能感兴趣的:(servlet)