Filter过滤器
Servlet规范包含了三大组件:
Servlet:实例化,初始化,服务,销毁
Filter:过滤器
Listener:监听器
JavaWeb基本工作过程:当请求到来时,执行顺序。
API
Filter接口
包名:javax.servlet.Filter;
核心 方法
// 初始化方法
init(FilterConfig filterConfig)
public void init(FilterConfig filterConfig) throws ServletException
// 作用:在过滤器创建时执行一次,用于完成初始化操作,例如读取配置参数、建立资源连接等。
// 相当于 Servlet 的 init() 方法。
// 过滤器方法
doFilter(ServletRequest req,ServletRespon resp,FilterChain chain)
// 销毁方法
destory()
init()
作用:在过滤器创建时执行一次,用于完成初始化操作,例如读取配置参数、建立资源连接等
参数:FilterConfig filterConfig
由容器传入,包含当前 Filter 的配置信息,可以通过它读取
在 web.xml 中配置的初始化参数;
当前 Filter 的名称;
ServletContext 对象
返回值:无(void)
示例:
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter 初始化...");
String encoding = filterConfig.getInitParameter("encoding");
System.out.println("初始化参数 encoding = " + encoding);
}
doFilter()
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
作用:是过滤器的核心方法,在每次请求到达目标资源(如 Servlet、JSP)之前都会执行;
你可以在这里:
拦截请求(如登录校验、权限控制);
修改请求或响应;
实现日志、编码统一处理;
或在调用目标资源前后添加逻辑。
参数:
ServletRequest request:请求对象。
ServletResponse response:响应对象。
FilterChain chain:过滤器链对象,用于将请求传递给下一个过滤器或目标资源。
返回值:无(void)
示例:
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
System.out.println("请求进入过滤器...");
// 设置编码(常见示例)
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
// 放行请求,交给下一个过滤器或目标 Servlet
chain.doFilter(req, resp);
System.out.println("响应返回过滤器...");
}
注意:如果不调用 chain.doFilter(req, resp),请求就不会继续传递,相当于被当前 Filter 拦截了
destory()
作用:在过滤器销毁前调用一次,通常用于资源清理,如关闭连接、释放内存等
参数:无。
返回值:无(void)。
示例:
@Override
public void destroy() {
System.out.println("Filter 被销毁,释放资源...");
}
Filter配置方式
两种方式:
// 第一种可以使用注解 @WebFilter,推荐使用XML配置(因为过滤器链的执行顺序问题)
// 第二种可以使用XML配置
方式一:注解(简便写法)
import javax.servlet.annotation.WebFilter;
import javax.servlet.*;
@WebFilter("/*") // 过滤所有请求
public class EncodingFilter implements Filter {
// 实现上面三个方法
}
方式二:web.xml
配置(推荐)
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.example.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
FilterConfig
包名:javax.servlet.FilterConfig
类似于 ServletConfig
,用于读取过滤器的初始化参数和获取 ServletContext
对象。
常用方法
// 获取过滤器的名称
String getFilterName()
// 获取指定的初始化参数值
String getInitParameter(String name)
// 获取所有初始化参数的名称
Enumeration<String> getInitParameterNames()
// 获取 ServletContext 对象
ServletContext getServletContext()
方法 | 作用 | 参数 | 返回值 |
---|---|---|---|
getFilterName() | 获取过滤器名称 | 无 | 过滤器名(字符串) |
getInitParameter(String name) | 根据参数名获取初始化参数值 | 参数名 | 参数值 |
getInitParameterNames() | 获取所有初始化参数名称 | 无 | 枚举对象 |
getServletContext() | 获取全局上下文对象 | 无 | ServletContext 对象 |
示例:
@WebFilter("/demo")
public class DemoFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
System.out.println("Filter名称:" + config.getFilterName());
String value = config.getInitParameter("encoding");
System.out.println("初始化参数 encoding:" + value);
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(req, resp);
}
@Override
public void destroy() {}
}
FilterChain
作用:用于控制过滤器链的调用流程。通过 chain.doFilter(request, response)
将请求交给下 一个过滤器或目标资源(Servlet)。
常用方法
doFilter()
void doFilter(ServletRequest request, ServletResponse response)
作用:用于控制过滤器链的调用流程。
参数:请求与响应对象
返回值:无
示例:
@WebFilter("/*")
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
System.out.println("进入过滤器 A");
chain.doFilter(req, resp); // 放行
System.out.println("离开过滤器 A");
}
}
ThreadLocal类
**作用:**为每个线程提供独立的变量副本,避免多线程间共享变量导致的冲突。常用于在过滤器或拦截器中保存用户信息、数据库连接等。
常用方法:
set(T value)
作用:为当前线程设置一个线程独立的变量值。
每个线程都有自己的 ThreadLocal 存储副本,互不影响。
参数:value —— 要为当前线程存储的值。
返回值:无(void)。
示例:
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("Hello Thread A"); // 当前线程独有的值
get()
作用:获取当前线程在 ThreadLocal 中存储的值。
如果当前线程从未设置过值,则返回 null。
参数:无。
返回值:当前线程对应的值(类型为 T)。
示例:
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("Data for current thread");
System.out.println(threadLocal.get()); // 输出:Data for current thread
remove()
作用:移除当前线程在 ThreadLocal 中存储的值,防止内存泄漏。
通常在线程使用完 ThreadLocal 后调用。
参数:无。
返回值:无。
示例:
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("Temporary data");
threadLocal.remove(); // 删除当前线程的数据
System.out.println(threadLocal.get()); // 输出:null
生命周期
当Tomcat启动时:
Filter初始化init执行
当请求到来时:
Servlet初始化init -> Filter过滤doFilter执行 -> 拦截了请求请求到来执行 -> 放行 -> servlet服务执行Service方法 -> 响应到来时执行
当Tomcat结束时:
Servlet销毁 -> Filter销毁
匹配规则
四种匹配规则
精确匹配
指定被拦截资源的完整路径:
<!-- 配置Filter要拦截的目标资源 -->
<filter-mapping>
<!-- 指定这个mapping对应的Filter名称 -->
<filter-name>FilterDemo01</filter-name>
<!-- 通过请求地址模式来设置要拦截的资源 -->
<url-pattern>/demo01</url-pattern>
</filter-mapping>
上述例子表示要拦截映射路径为/demo01
的这个资源
模糊匹配
相比较精确匹配,使用模糊匹配可以让我们创建一个Filter就能够覆盖很多目标资源,不必专门为每一个目标资源都创建Filter,提高开发效率。
在我们配置了url-pattern为/user/*之后,请求地址只要是/user开头的那么就会被匹配。
<filter-mapping>
<filter-name>Target02Filter</filter-name>
<!-- 模糊匹配:前杠后星 -->
<!--
/user/demo01
/user/demo02
/user/demo03
/demo04
-->
<url-pattern>/user/*</url-pattern>
</filter-mapping>
极端情况:/*匹配所有请求
扩展名匹配
<filter>
<filter-name>Target04Filter</filter-name>
<filter-class>com.atguigu.filter.filter.Target04Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>Target04Filter</filter-name>
<url-pattern>*.png</url-pattern>
</filter-mapping>
上述例子表示拦截所有以.png
结尾的请求
匹配Servlet名称
<filter-mapping>
<filter-name>Target05Filter</filter-name>
<!-- 根据Servlet名称匹配 -->
<servlet-name>Target01Servlet</servlet-name>
</filter-mapping>
过滤器链
初始化时:过滤器链的执行顺序:
不是按照严格的顺序执行的。
请求到来时:过滤器链的执行顺序:
过滤器链的顺序
过滤器链中每一个Filter执行的顺序是由web.xml中filter-mapping配置的顺序决定的。
<filter-mapping>
<filter-name>TargetChain03Filter</filter-name>
<url-pattern>/Target05Servlet</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>TargetChain02Filter</filter-name>
<url-pattern>/Target05Servlet</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>TargetChain01Filter</filter-name>
<url-pattern>/Target05Servlet</url-pattern>
</filter-mapping>
事务管理
事务管理动作,应该基于业务方法,事务应该建立在业务层
,而不是数据访问层
。
JDBC中默认情况下,执行一个SQL会自动提交。
但是,在实际情况下,我们应该以业务功能为单位进行事务管理。
注册是一个业务功能,其中包含了多个Dao方法;
-查询用户名是否可被注册-select操作;
-向用户表添加一条记录-insert操作;
-向系统日志表添加一条记录-insert操作;
我们应该发现,事务应该建立在注册这个方法上,而不是在其中的三个方法分别建立事务,
也就是说,这三步操作应该要么都成功要么都失败。
传动带 ThreadLocal 的理解:
1、当一个客户端发一个请求过来的时候,http协议,底层是tcp/ip协议,发来一个请求实则就是发来一个Socket;
2、Tomcat服务器接受到这个Socket,会专门开辟一个线程,用来接待你,对你做响应,是一个新的线程,所以后续的组件都是由这一个线程调用执行的。
3、只要这几个组件是由同一个线程执行的,就可以获取到 ThreadLocal 对象,这个ThreadLocal(传送带上带有属性也就是工具)可以被同一个线程上的组件获取到。
4、我们可以把这个工具箱(Connection对象)放在传送带上(ThreadLocal),
5、这样我们就可以在Filter层获取Dao层的对象数据了。
过滤器 OpenSessionInViewFilter 的理解和作用:
当客户端发来一个请求,Filter过滤器拦截到,执行开启事务,然后doFilter放行,然后执行DispatcherServlet中的方法,执行控制层,执行服务层,执行DAO层,成功了,然后返回到,提交事务,如果不成功则返回到 回滚事务。用来做事务管理(调用TransactionManager中的方法)。
TransactionManager 类的理解和作用:
作用:用于管理事务