Filter

概述

过滤器对象,可以对资源( Servlet 或静态内容)的请求或资源的响应执行过滤任务。过滤器在 doFilter 方法中执行过滤。每个过滤器都可以访问一个 FilterConfig 对象,从中获取初始化参数,一个对 ServletContext 的引用,它可以使用这个引用来加载过滤任务所需的资源。

【注意】当访问服务器的资源时,过滤器可以将请求拦截下来,并根据条件完成一些过滤的操作。

作用

过滤器用于完成一些通用的操作【封装】

1、登录验证

2、编码集处理

3、敏感字符过滤【代理】

4、日志和审核

5、数据转换和压缩

6、加密等…

常用 API

// 过滤器接口,内置三个抽象方法
interface javax.servlet.Filter// 初始化方法
void init(FilterConfig filterConfig);// 【重点】核心方法,过滤器的入口,用来处理过滤逻辑,可通过过滤器链对象的doFilter方法进行放行
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);// 销毁方法
void destroy(ServletRequest request, ServletResponse response, FilterChain chain);// 过滤器配置对象,在初始化期间将信息传递给过滤器
interface FilterConfig// 【重点】过滤器链对象,用来调用下一个过滤器或者访问资源
interface FilterChain

【注意】每次由于浏览器请求链末端的资源而通过链传递请求/响应对象时,容器都会调用过滤器的 doFilter 方法。传入此方法的过滤器链允许过滤器将请求和响应传递给链中的下一个实体

初识

步骤

1、声明一个类实现Filter接口(javax.servlet)
2、重写三个方法
3、声明@WebFilter注解,并添加访问路径:/*

案例代码

// 声明过滤器注解
@WebFilter("/*")
public class FilterTest1 implements Filter {/*** 初始化方法,创建对象后马上被调用,用来对Filter做一些初始化的操作** @param filterConfig 过滤器配置对象* @throws ServletException Servlet异常*/@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("init!!!");}/*** 核心过滤方法,用来完成过滤器主要功能的方法,每次访问目标资源时都会调用。** @param servletRequest 请求对象* @param servletResponse 响应对象* @param filterChain 过滤器链对象,调用doFilter方法进行放行* @throws IOException IO异常* @throws ServletException Servlet异常*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("doFilter");// 放行filterChain.doFilter(servletRequest, servletResponse);System.out.println("after doFilter");}/*** 服务器停止时调用,用来释放资源。*/@Overridepublic void destroy() {System.out.println("destroy");}
}

【注意】

​ 1、实现 Filter 接口时要注意导包

javax.servlet.Filter

​ 2、此注解使用通配符进行URL匹配,用来对整个项目的所有路径进行过滤

@WebFilter("/*")

执行流程【重点】

Filter 不是一个 Servlet,它不能产生一个 Response,但它能够在一个Request 请求对象到达 Servlet 之前进行请求预处理,也可以在 Response 响应对象离开 Servlet 时处理响应

用户浏览器 ==> Filter1 ==> Filter2 ==> HTML/JSP ==> Servlet ==> HTML/JSP ==> Filter2 ==> Filter1 ==> 用户浏览器

生命周期

1、构造方法创建对象

2、init 方法进行初始化

3、doFilter 核心方法进行过滤

4、destory 方法进行销毁

【注意】过滤器会随着服务器的启动直接加载

案例代码

package com.fc.filter.b_life;import javax.servlet.*;
import java.io.IOException;/*** Filter生命周期*/
public class FilterLife implements Filter {// 构造方法public FilterLife() {System.out.println("Filter构造方法");}// 初始化方法@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("Filter初始化方法");}// 核心过滤方法@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("Filter核心过滤方法");// 放行filterChain.doFilter(servletRequest, servletResponse);System.out.println("放行");}// 销毁方法@Overridepublic void destroy() {System.out.println("Filter销毁方法");}
}

两种配置方式【重点】

注解

// 过滤器注解,默认属性为访问路径
@WebFilter("/*")
public class FilterTest1 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("执行 Filter 初始化方法");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {filterChain.doFilter(servletRequest, servletResponse);System.out.println("执行 Filter 过滤方法");}@Overridepublic void destroy() {System.out.println("执行 Filter 销毁方法");}
}

通过 web.xml 文件

案例代码

/*** 通过web.xml文件配置过滤器*/
public class FilterTest2 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("初始化");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("过滤");// 放行filterChain.doFilter(servletRequest, servletResponse);System.out.println("放行");}@Overridepublic void destroy() {System.out.println("销毁");}
}

web.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><!--过滤器核心配置--><filter><!--过滤器名--><filter-name>FilterTest2</filter-name><!--完整的包名.类名--><filter-class>com.fc.filter.a_create.FilterTest2</filter-class></filter><!--过滤器映射--><filter-mapping><!--过滤器名--><filter-name>FilterTest2</filter-name><!--访问路径--><url-pattern>/*</url-pattern></filter-mapping><!--过滤器第二个映射--><filter-mapping><!--过滤器名--><filter-name>FilterTest2</filter-name><!--访问路径--><url-pattern>/index.jsp</url-pattern></filter-mapping>
</web-app>

【注意】

  1. 关注的重点是需要过滤的资源,即哪些资源需要进行过滤操作
  2. 允许多个 Filter 同时过滤一个路径,例如机场需要进行多次安检

常用配置项

属性 描述
urlPatterns 配置要拦截的资源路径
initParams 过滤器配置初始化参数,和 Servlet 中一样
dispatcherTypes 配置拦截的类型,可配置多个,默认为DispatcherType.REQUEST

【注意】拦截路径和URL匹配原则相同

​ 1、以指定资源匹配,例如"/index.jsp"
​ 2、以目录匹配,例如"/servlet/"
​ 3、以后缀名匹配,例如".jsp"
​ 4、通配符,拦截所有web资源。“/*”

DispatcherType 是个数组,可以过滤有多种过滤类型,包含以下值

过滤类型 描述
REQUEST 默认值。浏览器直接请求资源
FORWARD 过滤转发访问资源
INCLUDE 过滤包含访问资源
ERROR 过滤错误资源
ASYNC 过滤异步访问资源

【注意】通过 web.xml 中的 dispatcher 标签也可以配置

<dispatcher></dispatcher>

过滤路径

// 过滤以 .do 结尾的路径
// @WebFilter("*.do")
// 过滤 c_urlfilter 文件下所有
// @WebFilter("/c_urlfilter/*")
// 过滤指定文件
@WebFilter("/TestServlet.do")
public class UrlFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException,IOException {//chain.doFilter(req, resp);System.out.println("执行 doFilter 方法");}public void init(FilterConfig config) throws ServletException {}
}

过滤转发

过滤器

/*** 过滤类型为转发*/
@WebFilter(dispatcherTypes = DispatcherType.FORWARD, urlPatterns = {"/*"})
public class FilterConfig2 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("FilterConfig执行转发");
//        filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {}
}

转发 Servlet

@WebServlet("/forward")
public class ForwardServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("测试转发");// 放行,因为是重定向,URL 改变
//        resp.sendRedirect("http://www.baidu.com");// 过滤,因为是转发req.getRequestDispatcher("index.jsp").forward(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

【注意】Filter 过滤的是 URL,重定向的 URL 会一直改变,所以 DispatcherType.FORWORD 无法过滤重定向

过滤器链

请求到达 Servlet 之间是可以经过多个过滤器的

【注意】过滤器执行顺序

​ 1、在 web.xml 中,Filter 执行顺序跟 的顺序有关,先声明的先执行
​ 2、使用注解配置的话,Filter 的执行顺序跟名称的字母顺序有关,例如 AFilter 会比 BFilter 先执行
​ 3、如果既有在 web.xml 中声明的 Filter,也有通过注解配置的Filter,那么会优先执行 web.xml 中配置的 Filter

过滤器一

public class FilterA implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("FilterA过滤前");filterChain.doFilter(servletRequest, servletResponse);System.out.println("FilterA过滤后");}@Overridepublic void destroy() {}
}

过滤器二

public class FilterB implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("FilterB过滤前");filterChain.doFilter(servletRequest, servletResponse);System.out.println("FilterB过滤后");}@Overridepublic void destroy() {}
}

过滤器三

public class FilterC implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("FilterC过滤前");filterChain.doFilter(servletRequest, servletResponse);System.out.println("FilterC过滤后");}@Overridepublic void destroy() {}
}

web.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><filter><filter-name>FilterA</filter-name><filter-class>com.fc.filter.d_filterchain.FilterA</filter-class></filter><filter><filter-name>FilterB</filter-name><filter-class>com.fc.filter.d_filterchain.FilterB</filter-class></filter><filter><filter-name>FilterC</filter-name><filter-class>com.fc.filter.d_filterchain.FilterC</filter-class></filter><filter-mapping><filter-name>FilterC</filter-name><url-pattern>/*</url-pattern></filter-mapping><filter-mapping><filter-name>FilterB</filter-name><url-pattern>/*</url-pattern></filter-mapping><filter-mapping><filter-name>FilterA</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>

【注意】DispatcherType.REQUEST 比 DispatcherType.FORWORD 优先级高,又因为默认带有 REQUEST,所以 /* 的优先级是最高的

字符集编码过滤器【重点】

/*** 请求响应字符编码集过滤器*/
@WebFilter(urlPatterns = {"/*"},initParams = {@WebInitParam(name = "characterEncoding", value = "UTF8"),@WebInitParam(name = "contextType", value = "text/html; charset=UTF-8")})
public class EncodingFilter implements Filter {// 声明编码集和文本内容private String characterEncoding;private String contextType;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 通过过滤器配置对象中的初始化参数获取编码集和文本内容characterEncoding = filterConfig.getInitParameter("characterEncoding");contextType = filterConfig.getInitParameter("contextType");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 将请求和响应对象强转为支持HTTP协议的请求和响应对象HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;// 设置请求和响应对象的编码集request.setCharacterEncoding(characterEncoding);response.setContentType(contextType);// 放行filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {}
}

【注意】后面直接复制粘贴即可

自动登录过滤器【重点】

登录页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录页面</title>
</head>
<body><form method="post" action="login"><table align="center"><tr><td>账号</td><td><input type="text" name="username"></td></tr><tr><td>密码</td><td><input type="password" name="password"></td></tr><tr><td colspan="2" align="center"><input type="reset" value="重置">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="submit" value="登录"></td></tr></table></form>
</body>
</html>

主页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>主页</title>
</head>
<body><h1 align="right" style="color: blue"><a href="logout">退出登录</a></h1><h1 align="center" style="color: aqua">欢迎${user.nickname}登录成功!!</h1>
</body>
</html>

登录失败页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录失败页</title>
</head>
<body><h1 align="center" style="color: deeppink"><a href="login.html">重新登录</a></h1>
</body>
</html>

登录业务逻辑

/*** 登录*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取参数String username = req.getParameter("username");String password = req.getParameter("password");// 获取核心类对象QueryRunner queryRunner = new QueryRunner();// 获取数据库连接Connection connection = JdbcUtilsOnC3P0.getConnection();// 准备SQL语句String sql = "select * from user where username = ? and password = ?";// 准备参数Object[] params = {username, password};// 提取实体类对象User user = null;try {// 执行SQL语句并获取实体类对象user = queryRunner.query(connection, sql, new BeanHandler<>(User.class), params);} catch (SQLException e) {e.printStackTrace();}// 如果实体类对象不为null,说明查询到数据if (user != null) {// 登录成功,创建sessionHttpSession session = req.getSession(true);// 将实体类对象作为值添加到session中session.setAttribute("user", user);// 设置session过期时间session.setMaxInactiveInterval(60 * 60);// 获取session的idString id = session.getId();// 使用JSESSIONID和session的id作为键值对创建cookie对象Cookie cookie = new Cookie("JSESSIONID", id);// 设置cookie过期时间cookie.setMaxAge(60 * 60);// 将cookie发送到浏览器resp.addCookie(cookie);// 转发转至主页req.getRequestDispatcher("index.jsp").forward(req, resp);} else {// 登录失败,重定向至登录失败页面resp.sendRedirect("loginFail.html");}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

退出登录业务逻辑


/*** 退出登录*/
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取session,参数要使用falseHttpSession session = req.getSession(false);// 判断session是否为空if (session != null) {// session不为空,销毁sessionsession.invalidate();// 根据JSESSIONID获取cookieCookie cookie = new Cookie("JSESSIONID", session.getId());// 设置cookie过期时间为0cookie.setMaxAge(0);// 将cookie发送到浏览器resp.addCookie(cookie);}// 跳转至登录页面resp.sendRedirect("login.html");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

自动登录过滤器

/*** 自动登录过滤器** 如果没有登录则自动跳到登录页面*/
@WebFilter("/*")
public class AutoLoginFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 将请求和响应对象强转为支持HTTP协议的对象HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;// 通过请求对象获取session对象,注意参数要用falseHttpSession session = request.getSession(false);// 获取请求URIString uri = request.getRequestURI();// 判断请求URI是否以指定登录路径结尾if (uri.endsWith("/login.html") || uri.endsWith("/login")) {// 放行filterChain.doFilter(request, response);// 如果session为空,说明没有登录} else if (session == null) {// 跳转至登录页面response.sendRedirect("login.html");// session不为空,并且user参数也不为空} else if (session.getAttribute("user") != null) {// 放行filterChain.doFilter(request, response);} else {// 跳转至登录页面response.sendRedirect("login.html");}}@Overridepublic void destroy() {}
}

【注意】

​ 1、如果没有设置字符集编码过滤器就需要手动设置

RequestURI();

    // 判断请求URI是否以指定登录路径结尾if (uri.endsWith("/login.html") || uri.endsWith("/login")) {// 放行filterChain.doFilter(request, response);// 如果session为空,说明没有登录} else if (session == null) {// 跳转至登录页面response.sendRedirect("login.html");// session不为空,并且user参数也不为空} else if (session.getAttribute("user") != null) {// 放行filterChain.doFilter(request, response);} else {// 跳转至登录页面response.sendRedirect("login.html");}
}@Override
public void destroy() {}

}


>【注意】
>
>​       1、如果没有设置字符集编码过滤器就需要手动设置
>
>​       2、自动登录过滤器以后用到了直接复制粘贴,并且更改 session 中的属性键名即可

Filter_过滤器相关推荐

  1. Filter_细节_过滤器链(多个过滤器)

    过滤器链(配置多个过滤器)     * 执行顺序:如果有两个过滤器:过滤器1和过滤器2         1. 过滤器1         2. 过滤器2         3. 资源执行          ...

  2. Filter_细节_过滤器拦截方式配置

    * 拦截方式配置:资源被访问的方式     * 注解配置:         * 设置dispatcherTypes属性             1. REQUEST:默认值.浏览器直接请求资源    ...

  3. Filter_细节_过滤器拦截路径配置

    过滤器配置详解     * 拦截路径配置:         1. 具体资源路径: /index.jsp   只有访问index.jsp资源时,过滤器才会被执行         2. 拦截目录: /us ...

  4. java stream 多个filter_如何在Java Stream上应用多个过滤器?

    我必须通过一个映射过滤一个对象集合,该映射包含对象字段名称和字段值的键值对.我试图通过stream().filter()应用所有过滤器. 对象实际上是JSON,因此Map保留了其变量的名称以及它们必须 ...

  5. Redis 预防缓存穿透“神器” — 布隆过滤器

    1. 布隆过滤器 1.1 概念 在架构设计时有一种最常见的设计被称为布隆过滤器,它可以有效减少缓存穿透的情况.其主旨是采用一个很长的二进制数组,通过一系列的 Hash 函数来确定该数据是否存在. 布隆 ...

  6. SpringBoot2.3 修改响应头、添加更新token、解决在过滤器中修改失败

    前言 使用Spring Boot开发项目的过程中,难免会遇到向响应头中写入一些信息,例如更新了的token,用户详情等信息.在请求头中添加,请求时就可以通过过滤器,拦截器等验证或者获得请求头传递的信息 ...

  7. [JAVA EE] Filter过滤器

    Filter过滤器 ◼ 过滤器(Filter)可以动态地拦截请求和响应. ◼ 应用场景:过滤敏感词汇.防止SQL注入.设置字符编码.进行URL级 别的权限访问控制.压缩响应信息等. 启动文件DemoA ...

  8. java 过滤器Filter

    Filter简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件 ...

  9. 一维卷积filter_从零开始学Pytorch(七)之卷积神经网络

    卷积神经网络基础 我们介绍卷积神经网络的卷积层和池化层,并解释填充.步幅.输入通道和输出通道的含义. import torch from torch.autograd import Variable ...

最新文章

  1. Python九十天学习框架,从1到90,从0基础到IQ100
  2. WPF将Ui保存为图片和保存位图
  3. IOS 集成支付宝和邮件发送
  4. 论定期修改电脑密码的重要性
  5. Oracle 日期加减运算
  6. html5白话解释,HTML5这个词到底是什么意思?
  7. 不用看数学公式!图解谷歌神经机器翻译核心部分:注意力机制
  8. Express 常用中间件 body-parser 实现解析
  9. Android wifi carlife,carlife可以无线连接吗?carlife蓝牙连接流程
  10. (HDOJ 2034)人见人爱A-B
  11. 扫雷游戏计算机版,扫雷经典版电脑版
  12. 3D模型欣赏:斯巴达女将军 长枪圆盾战士 性感美女
  13. 微信小程序超级占内存_微信小程序占内存吗?
  14. 【最优估计学习笔记】概率密度函数
  15. 采访了12位中年程序员,听听他们的故事和人生!
  16. PHP工程师是个让我很心疼的职业
  17. CRM客户细分的价值
  18. 全球及中国燃气轮机行业产量规模预测及发展态势研究报告2021-2027年版
  19. 【计算机毕业设计】092二手闲置交易市场系统
  20. 大数据处理系统都有哪些?(批处理系统与迭代计算系统)

热门文章

  1. 应用在智能触摸遥控器中的触摸芯片
  2. Win11 OneDrive登录遇到问题0x8004de40
  3. 制作坦克大战,坦克移动代码
  4. WPA渗透-pyrit:batch-table加速attack_db模块加速_“attack_db”模块加速
  5. CSS综合案例——淘宝轮播图/焦点图布局的制作
  6. Oracle数据库视频教程 28讲高清视频
  7. 你是开发工程师、程序员还是码农?
  8. python秒表_Python 秒表
  9. tomcat重启命令操作
  10. java获取当前时间戳