1、过滤器概述

过滤器(Filter)就是在源数据和目的数据之间起过滤作用的中间组件。其主要作用是:过滤请求和响应。

我们可以将一些多个(或所有)Servlet中都需要解决的问题放在过滤器中处理。如:

  • 户请求进行统一认证

  • 对用户的访问请求进行记录和审核(登录验证)

  • 对用户发送的数据进行过滤或者替换

  • 对响应内容进行压缩,减少传输容量

  • 对请求和响应进行加解密处理

2、工作原理

过滤器的工作原理如下图所示:

过滤器原理
  • web容器接收到对一个资源的请求时,它将判断是否有过滤器与这个资源相关联。如果有,那么容器将会把这个请求先交给过滤器进行处理。此时我们便可以在过滤器中对请求进行处理(如:改变请求的内容或者重新设置请求的报头信息等)。待过滤完成后,web容器再将请求发送给目标资源。

  • 当目标资源对请求作出响应时,容器同样会将响应先转发给过滤器。在过滤器中,我们可以对响应的内容进行转换。待过滤完成后,web容器再将响应发送给客户端。

注:

  • 生命周期:过滤器在服务器启动时创建,在服务器关闭时被销毁。

  • web应用中,我们可以部署多个过滤器,这些过滤器组成过滤器链(FilterChain

  • 过滤器链中的每一个过滤器负责特定的操作和任务。

  • web服务器会根据web.xml文件中过滤器的注册顺序依次调用。当第一个过滤器的doFilter方法被调用时,web服务器会创建一个过滤器链的FilterChain对象传递给该方法。

  • 在请求资源时,过滤器链中的过滤器将依次对请求进行处理,将请求传递给下一个过滤器,直到目标资源;在发送响应时,则按照相反的顺序依次对响应进行处理,直到客户端。

3、使用步骤

使用过滤器与创建Servlet类似,主要分为以下两个步骤:

(1)编写一个Java类实现Filter接口。

(2)在web.xml文件中配置(注册)Filter。

注:Servlet不同的是,Filter并没有类似于HttpServlet的实现类可供继承,要使用过滤器,我们只能实现javax.servlet中的Filter接口。

4、应用示例:使用过滤器解决请求和响应中文乱码问题

4.1、创建测试项目

(1)使用Maven模板创建一个MavenWeb项目(具体步骤参考《Maven详解》),项目名称为javaweb-filter

(2)同样地,填写项目名称和Maven项目GAV

(3)同样地,配置该MavenWeb项目的安装目录、配置文件和本地仓库。点击Finish按钮完成项目创建,等待Maven依赖包导入完毕。

(4)同样地,为了避免以后出现兼容性问题,建议我们先将该项目中的web.xml文件替换成“web-app_4_0”版本(具体步骤参考《Servlet详解》)。

(5)同样地,在该项目的main文件夹下新建一个java文件夹和一个resource文件夹,并将它们分别标记为“源码根目录”和“资源根目录”。

(6)同样地,配置Tomcat服务器,deploy(发布)javaweb-filter:war exploded包,并为该项目添加虚拟路径映射:/filter(具体步骤参考《Tomcat详解》)。

(7)在项目的pom.xml文件中添加项目依赖,并重新加载Maven项目。

pom.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
</dependencies>

(8)同样地,在该项目的java目录下新建一个com.atangbiji.servlet包,并在该包下新建一个ShowServlet类,用于在页面上输出中文字符。同样地,让ShowServlet类继承(extends)HttpServlet类,以实现Servlet接口。然后,在ShowServlet类中重写doGetdoPost方法。

ShowServlet.java文件:

1
2
3
4
5
6
7
8
9
10
11
public class ShowServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("你好,过滤器!");//中文乱码输出测试
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp); //因为get和post只是不同的Http请求方式,所以它们之间可以相互调用。
}
}

(9)同样地,在该项目的Web配置文件(web.xml)中注册(映射)我们自己编写的Servlet,并为它提供一个浏览器可以访问的路径。

web.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<servlet>
<servlet-name>showServlet</servlet-name>
<servlet-class>com.atangbiji.servlet.ShowServlet</servlet-class>
</servlet>
<!-- 映射路径1 -->
<servlet-mapping>
<servlet-name>showServlet</servlet-name>
<url-pattern>/show/test</url-pattern>
</servlet-mapping>
<!-- 映射路径2 -->
<servlet-mapping>
<servlet-name>showServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>

注:一个Servlet程序可以指定一个或者多个映射路径

(10)在IDEA中启动Tomcat。在浏览器中输入http://localhost:8080/filter/show/testhttp://localhost:8080/filter/test,访问结果均出现中文乱码现象。如下图所示:

中文乱码现象

中文乱码现象2

4.2、创建过滤器,实现Filter接口

(11)在该项目的java目录下新建一个com.atangbiji.filter包,并在该包下新建一个CharacterEncodingFilter类,用于处理请求和响应中文乱码问题。类似地,让CharacterEncodingFilter类实现(implements)javax.servlet中的Filter接口。然后,在CharacterEncodingFilter类中重写initdoFilterdestroy方法。

**注:**此处,我们创建的过滤器实现的是javax.servlet包中的Filter接口,不是其它包中的Filter接口。

实现Filter接口

CharacterEncodingFilter.java文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class CharacterEncodingFilter implements Filter {
//初始化
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterEncodingFilter过滤器初始化完毕!");
}

//过滤请求和响应
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//设置请求和响应的编码集
servletResponse.setContentType("text/html;charset=utf-8");
servletRequest.setCharacterEncoding("utf-8");

System.out.println("CharacterEncodingFilter执行前……");
//依次调用过滤器链中的所有过滤器,让消息继续通行(如果不写,程序运行至此便停止了!)
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("CharacterEncodingFilter执行后……");
}

//销毁
@Override
public void destroy() {
System.out.println("CharacterEncodingFilter过滤器被销毁!");
}
}

4.3、配置(注册)过滤器,添加过滤路径

(12)类似地,在该项目的Web配置文件(web.xml)中注册(映射)我们自己编写的Filter,并根据实现需要为它添加过滤路径。

web.xml文件:

1
2
3
4
5
6
7
8
9
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.atangbiji.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<!--只要是/show下的任何请求,都会被该过滤器过滤-->
<url-pattern>/show/*</url-pattern>
</filter-mapping>

**注:**过滤器过滤路径的规则与Servlet映射(访问)路径的规则完全相同。

4.4、测试结果

(13)重启Tomcat。若在浏览器中输入http://localhost:8080/filter/show/test,则页面会被过滤器过滤,访问结果不会出现中文乱码现象。

中文乱码现象已解决

若在浏览器中输入http://localhost:8080/filter/test,则页面不会被过滤器过滤,访问结果仍然会出现中文乱码现象。

中文乱码现象未解决

(本讲完,系列博文持续更新中…… )

阿汤笔迹微信公众平台

关注**“阿汤笔迹”** 微信公众号,获取更多学习笔记。
原文地址:http://www.atangbiji.com/2022/10/18/filter
博主最新文章在个人博客 http://www.atangbiji.com/ 发布。