过滤器(Filter)概念总结
什么是过滤器
过滤器(Filter)是Java Web应用中用于统一拦截和处理请求的组件,类似于现实生活中的空气净化器或安检。它通过对请求进行前置处理,确保请求符合特定要求。
过滤器的执行机制
- 当请求从浏览器发送到Tomcat时,首先会经过过滤器,而不是直接到达Servlet。
- 请求会依次经过各个过滤器进行处理。每个过滤器可以对请求进行检查、修改等操作。
- 处理完请求后,最终请求会到达Servlet进行业务逻辑处理。
- 响应则会按照原始路径逆向通过过滤器返回给浏览器。
过滤链
过滤器处理请求的过程称为过滤链。请求在过滤链中依次被处理,确保只有符合要求的请求才能到达Servlet。
过滤器的基本概念
- 过滤器是用来对请求和响应进行处理的组件,可以在请求到达Servlet之前或响应返回给客户端之前进行拦截。
开发步骤
-
实现Filter接口
- 任何过滤器都需要实现
javax.servlet.Filter
接口。
- 任何过滤器都需要实现
-
实现doFilter方法
-
doFilter
方法是过滤器的核心,定义了过滤器的具体功能。 - 方法参数包括:
-
ServletRequest request
:请求对象 -
ServletResponse response
:响应对象 -
FilterChain chain
:过滤链,用于将请求和响应传递给下一个过滤器或目标Servlet。
-
-
-
配置过滤器
- 在
web.xml
文件中进行配置,定义过滤器及其作用的URI。 - 使用
<filter>
标签定义过滤器,使用<filter-mapping>
标签指定过滤器拦截的请求URI。
- 在
示例代码
- 创建项目和包结构
- 实现过滤器
FirstFilter
package com.imooc.filter;
import javax.servlet.*;
import java.io.IOException;
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.printf("过滤器已生效");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
package com.imooc.servlet;
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("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("<h1>hello servlet</h1>");
}
}
过滤器的特性
- 过滤器对象在Web应用启动时被创建且全局唯一。
- 唯一的过滤器对象在并发环境中采用“单例多线程”提供服务。
过滤器的配置形式
在web.xml
中配置过滤器的基本形式如下:
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>com.imooc.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置与注解的选择总结
本节课探讨了过滤器的配置形式与注解形式各自的优劣,并提供了一些使用建议。
注解形式的优势
- 注解形式的开发体验更好,配置和源代码放在一起,减少在源代码和配置文件之间来回切换的麻烦。
- 更适合小型敏捷项目,可以快速开发和迭代。
- 更适合局部功能的设置,如特定的Servlet,因为Servlet的映射地址通常较为稳定,职责单一,注解可以让开发更灵活。
配置形式的优势
- 配置形式更适合大型系统,尤其是需要全局过滤的场景,如全局的字符集过滤器等。
- 维护性更强,配置在
web.xml
中可以灵活修改,无需重新编译代码。 - 更适合全局应用过滤,在真实项目中,过滤器常用于全局性的请求处理。
使用建议
-
全局过滤器(如字符集过滤器):推荐使用配置形式,放在
web.xml
中。 - 局部功能或小范围设置(如Servlet):推荐使用注解形式,让开发更灵活,增强开发体验。
注解形式虽然开发体验好,但在全局性应用场景下,配置文件形式更具优势。而在局部、单一职责的场景下,注解则显得更加适合。
过滤链的概念与使用
本节我们来学习一个重要的概念——过滤链。过滤链顾名思义,就是由过滤器所形成的调用链条。在真实的项目中,过滤器往往不只有一个,当一个请求被发出后由 Tomcat 接收,再转而由 Web APP 来进行处理时,首先会经过过滤器所形成的执行链条,依次对请求进行过滤处理,最终送达到 Servlet。在 Servlet 处理后,相应的响应也会按照原始的路径反向返回给客户端。这就是过滤链的处理过程。
过滤链并不是一个复杂的概念,只是一种消息传递的机制。但是对于过滤链来说,也有一些需要考虑的细节,比如说哪个过滤器先执行,哪个过滤器后执行,以及过滤器和过滤器之间该如何设计。下面我们来看一下关于过滤链的一些开发注意事项,主要有以下三点:
开发注意事项
1. 单一职责原则
每个过滤器应该都有单独的职责。比如字符集过滤器的职责非常单一,就是进行请求和响应的字符集设置。如果在这个过滤器中额外增加关于用户身份的前置过滤,显然是不合适的。正确的做法是应该把这个额外的工作交给一个专用的用户认证过滤器来进行。在软件开发时,具体的类都要有明确的职责,不要把各种功能混在一起。这样做可以提高程序的维护性和可读性。
2. 过滤器的执行顺序
过滤器在执行过程中,执行顺序是以 filter-mapping
前后书写顺序来决定的。对于一个请求,如果被多个过滤器进行拦截,那么这些过滤器的执行顺序将以 filter-mapping
在配置文件中的前后顺序依次执行。
3. 过滤器链的传递
如果没有特殊原因,不要中断过滤链。在过滤器的 doFilter
方法最后要增加 chain.doFilter
,让请求向后进行传递,最终送达给 Servlet 进行处理。如果没有调用这句话,将意味着过滤链在当前就被处理完,请求会立即返回。
监听器与过滤器的区别及实现
监听器(Listener)
-
概念:
- 监听器是标准 J2EE Servlet 模块下的组件,用于监控外部应用中的内置对象,如
ServletContext
、HttpSession
和ServletRequest
。 - 监听器可以自动触发指定的功能代码,对 Web 对象进行监听,属于被动触发。
- 监听器是标准 J2EE Servlet 模块下的组件,用于监控外部应用中的内置对象,如
-
实现与配置:
- 通过实现特定的接口(如
ServletContextListener
、HttpSessionListener
、ServletRequestListener
)来定义监听逻辑。 - 每个接口都包含多个必须实现的方法,这些方法对应于不同对象的创建和销毁事件。
- 在
web.xml
文件中配置监听器时,需要添加<listener>
标签,并指定监听器的全类名。
- 通过实现特定的接口(如
过滤器(Filter)
-
概念:
- 过滤器是 Servlet 规范中的一个组件,用于拦截客户端的请求和服务器的响应。
- 它属于主动行为,可以对请求和响应进行预处理或后处理。
-
主要用途:
- 进行请求和响应的内容检查和处理。
- 实现认证、日志记录、字符编码转换等功能。
监听器与过滤器的区别
-
触发机制:
- 监听器是被动触发,当特定事件(如对象的创建或销毁)发生时自动执行相应的代码。
- 过滤器是主动行为,可以对请求和响应进行拦截和处理。
-
应用场景:
- 监听器适用于在对象状态改变时(如对象创建或销毁)执行特定操作。
- 过滤器适用于对请求和响应内容进行检查和处理。
-
配置方式:
- 监听器需要在
web.xml
文件中配置<listener>
标签。 - 过滤器需要在
web.xml
文件中配置<filter>
标签,并指定拦截的 URL 模式。
- 监听器需要在
过滤器(Filter)和监听器(Listener)的区别
1. 过滤器(Filter):主动检查
过滤器就像一个门卫,每当有人进出时,它都会主动检查每个人的证件和包裹。它负责对每一次进出的请求进行拦截和处理,不管你进来做什么,它都会主动检查。
生活中的例子:
- 门口安检:在进入一个活动场所之前,安检人员会主动检查你的背包和身份。这就是一个典型的过滤器例子。无论你是参观还是工作,每个人都要先经过安检。
- 水过滤器:当自来水流过水过滤器时,它会主动将水中的杂质过滤掉,不管水是从哪来,最终流向哪里,只要经过水过滤器,它都会主动过滤。
编程中的应用:
- 在每次网页请求时,过滤器可以检查用户是否登录。如果没有登录,就会将用户重定向到登录页面。
- 它可以在用户提交数据时,检查数据是否合法(比如是否包含敏感词汇),然后再决定是否继续处理请求。
总结:过滤器总是会主动在每一次请求到达服务器之前拦截并处理,所有请求都要经过它的“检查”。
2. 监听器(Listener):被动反应
监听器就像一个在教室后面坐着的老师,他会观察学生的状态变化,比如谁进教室了、谁出去了,但他不会主动干涉每个学生的行为,只有当学生做出某些动作(比如举手提问、出教室)时,老师才会有反应。
生活中的例子:
- 运动感应灯:当你走进房间时,感应灯会亮起。灯不会主动找你,而是等着你进入感应范围,它才会被动地亮起。
- 火警报警器:当房间里有烟雾时,报警器会被动地响起。它平时不会主动检查每一个角落,而是等烟雾出现时才会被触发。
编程中的应用:
- 当用户第一次访问网站时,
HttpSessionListener
会记录用户的会话信息。 - 当用户退出登录时,
HttpSessionListener
会被触发来清理用户的会话信息。 - 当应用启动时,
ServletContextListener
会被触发,用来初始化一些资源。
总结:监听器不会主动干涉每一个请求或动作,它只在某些特定事件发生时(如对象的创建、销毁)被动地反应。
3. 两者的根本区别:
-
作用对象不同:过滤器作用于“请求和响应”的流转过程,而监听器作用于“对象的生命周期”。
- 过滤器:对所有的请求和响应进行处理,主动决定是否放行、修改请求/响应内容。
- 监听器:监听特定事件的发生,被动响应这些事件,如会话创建、销毁等。
-
触发时机不同:
- 过滤器在每次请求到来时都会被主动调用处理。
- 监听器在特定事件(如会话创建、销毁、上下文初始化等)发生时才会被动触发。