概述
Filter,即过滤器,是JAVAEE技术规范之一,作用目标资源的请求进行过滤的一套技术规范,是Java Web项目中`最为实用的技术之一
- Filter接口定义了过滤器的开发规范,所有的过滤器都要实现该接口
- Filter的工作位置是项目中所有目标资源之前,容器在创建HttpServletRequest和HttpServletResponse对象后,会先调用Filter的doFilter方法
- Filter的doFilter方法可以控制请求是否继续,如果放行,则请求继续,如果拒绝,则请求到此为止,由过滤器本身做出响应
- Filter不仅可以对请求做出过滤,也可以在目标资源做出响应前,对响应再次进行处理
- Filter是GOF中责任链模式的典型案例
- Filter的常用应用包括但不限于: 登录权限检查,解决网站乱码,过滤敏感字符,日志记录,性能分析… …
实现过滤器的步骤
1.实现Filter接口
2.配置过滤器
通过web.xml配置文件配置
通过注解方式配置
Filter接口中的方法:
| API | 目标 |
|---|---|
| default public void init(FilterConfig filterConfig) | 初始化方法,由容器调用并传入初始配置信息filterConfig对象 |
| public void doFilter(ServletRequest request, response, FilterChain chain) | 过滤方法,核心方法,过滤请求,决定是否放行,响应之前的其他处理等都在该方法中 |
| default public void destroy() | 销毁方法,容器在回收过滤器对象之前调用的方法 |
代码示例:
public class LoggingFilter implements Filter {
private SimpleDateFormat dateFormat =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 参数父转子
HttpServletRequest request =(HttpServletRequest) servletRequest;
HttpServletResponse response =(HttpServletResponse) servletResponse;
// 拼接日志文本
String requestURI = request.getRequestURI();
String time = dateFormat.format(new Date());
String beforeLogging =requestURI+"在"+time+"被请求了";
// 打印日志
System.out.println(beforeLogging);
// 获取系统时间
long t1 = System.currentTimeMillis();
// 放行请求
filterChain.doFilter(request,response);
// 获取系统时间
long t2 = System.currentTimeMillis();
// 拼接日志文本
String afterLogging =requestURI+"在"+time+"的请求耗时:"+(t2-t1)+"毫秒";
// 打印日志
System.out.println(afterLogging);
}
}
- doFilter方法中的请求和响应对象是以父接口的形式声明的,实际传入的实参就是HttpServletRequest和HttpServletResponse子接口级别的,可以安全强转
- filterChain.doFilter(request,response); 这行代码的功能是放行请求,如果没有这一行代码,则请求到此为止
- filterChain.doFilter(request,response);在放行时需要传入request和response,意味着请求和响应对象要继续传递给后续的资源,这里没有产生新的request和response对象
web.xml中配置过滤器:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<!--配置filter,并为filter起别名-->
<filter>
<filter-name>loggingFilter</filter-name>
<filter-class>com.atguigu.filters.LoggingFilter</filter-class>
</filter>
<!--为别名对应的filter配置要过滤的目标资源-->
<filter-mapping>
<filter-name>loggingFilter</filter-name>
<!--通过映射路径确定过滤资源-->
<url-pattern>/servletA</url-pattern>
<!--通过后缀名确定过滤资源-->
<url-pattern>*.html</url-pattern>
<!--通过servlet别名确定过滤资源,@WebServlet注解中的name属性-->
<servlet-name>servletBName</servlet-name>
</filter-mapping>
</web-app>
- filter-mapping标签中定义了过滤器对那些资源进行过滤
- 子标签url-pattern通过映射路径确定过滤范围
- /servletA 精确匹配,表示对servletA资源的请求进行过滤
- *.html 表示对以.action结尾的路径进行过滤
- /* 表示对所有资源进行过滤
- 一个filter-mapping下可以配置多个url-pattern
- 子标签servlet-name通过servlet别名确定对那些servlet进行过滤
- 使用该标签确定目标资源的前提是servlet已经起了别名
- 一个filter-mapping下可以定义多个servlet-name
- 一个filter-mapping下,servlet-name和url-pattern子标签可以同时存在
过滤器的生命周期
过滤器的生命周期分为,创建,初始化,过滤服务,销毁
过滤器作为web项目的组件之一,和Servlet的生命周期类似,略有不同,没有servlet的load-on-startup的配置,默认就是系统启动立刻构造
| 阶段 | 对应方法 | 执行时机 | 执行次数 |
|---|---|---|---|
| 创建对象 | 构造器 | web应用启动时 | 1 |
| 初始化方法 | void init(FilterConfig filterConfig) | 构造完毕 | 1 |
| 过滤请求 | void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) | 每次请求 | 多次 |
| 销毁 | default void destroy() | web应用关闭时 | 1次 |
示例代码:
@WebServlet("/*")
public class LifeCycleFilter implements Filter {
public LifeCycleFilter(){
System.out.println("LifeCycleFilter constructor method invoked");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LifeCycleFilter init method invoked");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("LifeCycleFilter doFilter method invoked");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("LifeCycleFilter destory method invoked");
}
}
过滤器链的使用
一个web项目中,可以同时定义多个过滤器,多个过滤器对同一个资源进行过滤时,工作位置有先后,整体形成一个工作链,称之为过滤器链
- 过滤器链中的过滤器的顺序由filter-mapping顺序决定
- 每个过滤器过滤的范围不同,针对同一个资源来说,过滤器链中的过滤器个数可能是不同的
- 如果某个Filter是使用ServletName进行匹配规则的配置,那么这个Filter执行的优先级要更低
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<filter>
<filter-name>filter1</filter-name>
<filter-class>com.atguigu.filters.Filter1</filter-class>
</filter>
<filter>
<filter-name>filter2</filter-name>
<filter-class>com.atguigu.filters.Filter2</filter-class>
</filter>
<filter>
<filter-name>filter3</filter-name>
<filter-class>com.atguigu.filters.Filter3</filter-class>
</filter>
<!--filter-mapping的顺序决定了过滤器的工作顺序-->
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>/servletC</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern>/servletC</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>filter3</filter-name>
<url-pattern>/servletC</url-pattern>
</filter-mapping>
</web-app>
注解方式配置过滤器
@WebFilter注解的使用
代码示例:
@WebFilter(
filterName = "loggingFilter",
initParams = {@WebInitParam(name="dateTimePattern",value="yyyy-MM-dd HH:mm:ss")},
urlPatterns = {"/servletA","*.html"},
servletNames = {"servletBName"}
)
public class LoggingFilter implements Filter {
private SimpleDateFormat dateFormat ;
/*init初始化方法,通过filterConfig获取初始化参数,类似于servletConfig
* init方法中,可以用于定义一些其他初始化功能代码
* */
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 获取初始参数
String dateTimePattern = filterConfig.getInitParameter("dateTimePattern");
// 初始化成员变量
dateFormat=new SimpleDateFormat(dateTimePattern);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 参数父转子
HttpServletRequest request =(HttpServletRequest) servletRequest;
HttpServletResponse response =(HttpServletResponse) servletResponse;
// 拼接日志文本
String requestURI = request.getRequestURI();
String time = dateFormat.format(new Date());
String beforeLogging =requestURI+"在"+time+"被请求了";
// 打印日志
System.out.println(beforeLogging);
// 获取系统时间
long t1 = System.currentTimeMillis();
// 放行请求
filterChain.doFilter(request,response);
// 获取系统时间
long t2 = System.currentTimeMillis();
String afterLogging =requestURI+"在"+time+"的请求耗时:"+(t2-t1)+"毫秒";
// 打印日志
System.out.println(afterLogging);
}
}

4万+

被折叠的 条评论
为什么被折叠?



