Filter

简介

Filter是对客户端访问资源的过滤,符合条件的放行,不符合条件的不放行,并且可以对目标资源访问前后进行逻辑处理的一个组件。

过滤器的作用

​ Java过滤器是处于客户端与服务器资源文件之间的一道过滤网,在访问资源文件之前,通过一系列的过滤器可以对请求进行修改、判断等,把不符合规则的请求在中途拦截或修改;也可以对响应进行过滤,拦截或修改响应。例如:修改响应体或是请求体的字符集。


快速入门

  • 步骤:
    • 使用Maven创建一个Web项目
    • 导入javax.servlet-api依赖
    • 编写一个过滤器继承Filter执行过滤操作
    • 编写一个Servlet继承HttpServlet执行业务处理操作
    • web.xml/注解中进行配置(配置servletfilter

CharsetFilter.java

public class CharsetFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("这里做一些初始化操作");
}

@Override
public void destroy() {
System.out.println("这里做一些过滤器被销毁前的操作");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("这里执行过滤请求");
//比如将请求的字符集改为utf-8
request.setCharacterEncoding("utf-8");
System.out.println(request.getCharacterEncoding());

//这里也可以设置响应体的相关参数
System.out.println(response.getCharacterEncoding());
//改后放行
chain.doFilter(request,response);

System.out.println("这里过滤响应");
System.out.println(response.getCharacterEncoding());

}
}

ServiceServlet.java

public class ServiceServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println(req.getParameter("name"));
}
}

web.xml

<!--    注册servlet-->
<servlet>
<servlet-name>servlet</servlet-name>
<servlet-class>servlet.ServiceServlet</servlet-class>
<!-- <load-on-startup>0</load-on-startup>-->
</servlet>
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>/servlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>filter</filter-name>
<filter-class>filter.CharsetFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<servlet-name>servlet</servlet-name>
<url-pattern>/servlet</url-pattern>
</filter-mapping>

xml配置

url-pattern:代表要过滤的资源的匹配

filter-name:过滤器名称 用于映射 于servlet-name作用相同

filter-class: 过滤器类的全限定名称

servlet-name:代表要过滤的Servlet的资源匹配


Filter的生命周期其与生命周期相关的方法

Filter接口有三个方法,这三个方法都与Filter的生命后期有关。

  • init(FilterConfig): 代表filter对象初始化方法,filter对象由tomcat创建并且会将配置文件(web.xml)生成一个FilterConfig对象注入其中。
  • doFilter(ServletRequest,ServletResponse,FilterChain): 代表filter对象执行过滤的核心方法如果某资源在已经被配置到这个filter进行过滤的话,那么每次访问这个资源都会执行doFilter()方法,与ServletService()方法类似。
  • destory(): 代表filter销毁的方法,这里可以执行一些销毁前的操作, 当filter对象销毁时会执行这个方法。

Filter对象的生命周期

  • Filter何时创建:服务器启动时就创建该filter对象
  • Filter合适销毁: 服务器关闭时filter销毁

注意:FilterServlet一样都是默认单例的。


Filter相关API

  1. init(FilterConfig)

    1. Filter创建时会去执行的init方法
    2. 参数FilterConfig代表该Filter对象配置信息的对象,内部封装的是该Filter的配置信息。由Tomcat创建该Filter对象时从配置文件中读取封装为一个FilterConfig后注入。
  2. destroy()

    1. filter对象销毁时执行
    2. 这里可以执行一些销毁前需要执行的操作,因为filter对象销毁时该方法会被执行
  3. doFilter(ServletRequest,ServletResponse,FilterChain)

    1. 当该filter映射的url-pattern对应的资源被访问了 会执行该方法

    2. 其中的参数

      • ServletRequest/ServletResponse:每次在执行doFilter方法时 web容器负责创建一个request和一个response对象作为doFilter的参数传递进来。该requestresponse就是在访问目标资源的service方法时的requestresponse
      • FilterChain: 过滤器链对象, 通过该对象的doFilter方法可以放行该请求,如果该过滤器上还有过滤器没有过滤该请求,那么转交给它,如果没有则直接到达Servletservice()

过滤器链

​ 在一个 Web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序都可以针对某一个 URL 进行拦截。如果多个 Filter 程序都对同一个 URL 进行拦截,那么这些 Filter 就会组成一个Filter 链(也称过滤器链)。

e7aa5e26bcbc923a1235b5e70b6e938f.png

Filter链

  • 拦截顺序和过滤器web.xml注册顺序(filter-mapping)一致。
  • 由上图可知过滤器链过滤的顺序准许”先进后出”的原则。

过滤器链代码演示

Servlet.java

public class Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("html/text;charset=utf-8");
PrintWriter out = resp.getWriter();
System.out.println("请求已接受");
out.println("请求已接受");
}
}

Filter01.java

public class Filter01 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("请求经过过滤器01");
chain.doFilter(request,response);
System.out.println("响应经过过滤器01");
}
}

Filter02.java

public class Filter02 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("请求经过过滤器02");
chain.doFilter(request,response);
System.out.println("响应经过过滤器02");
}
}

web.xml

    <servlet>
<servlet-name>servlet</servlet-name>
<servlet-class>servlet.Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>/filterServlet</url-pattern>
</servlet-mapping>
<!-- 过滤器链注册-->

<filter>
<filter-name>filter01</filter-name>
<filter-class>filter.Filter01</filter-class>
</filter>
<filter-mapping>
<filter-name>filter01</filter-name>
<url-pattern>/filterServlet</url-pattern>
</filter-mapping>
<filter>
<filter-name>filter02</filter-name>
<filter-class>filter.Filter02</filter-class>
</filter>
<filter-mapping>
<filter-name>filter02</filter-name>
<url-pattern>/filterServlet</url-pattern>
</filter-mapping>

控制台输出(可以看到 先进后出)

image-20220424163848783


Filterurl-pattern配置

  • 匹配单个资源

    <filter>
    <filter-name>filter02</filter-name>
    <filter-class>filter.Filter02</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>filter02</filter-name>
    <url-pattern>/filterServlet</url-pattern>
    </filter-mapping>
  • 统配符匹配(最常使用)

    <filter>
    <filter-name>filter02</filter-name>
    <filter-class>filter.Filter02</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>filter02</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    • 扩展名匹配 (*.abc *.jsp注意不能和统配符混用

      <filter>
      <filter-name>filter02</filter-name>
      <filter-class>filter.Filter02</filter-class>
      </filter>
      <filter-mapping>
      <filter-name>filter02</filter-name>
      <url-pattern>*.jsp</url-pattern>
      </filter-mapping>

-End-