Filter 过滤器

article/2025/9/6 14:12:46

一、Filter 过滤器概念

① Filter 过滤器它是 JavaWeb 的三大组件之一

     三大组件分别是:Servlet 程序、

                                 Listener 监听器、

                                 Filter 过滤器

② 他是 JavaEE 的规范,也就是接口

③ 作用:拦截请求,过滤响应

拦截请求常见的应用场景有:

① 权限检查

② 日记操作

③ 事务管理

...

二、Filter 的初体验

在  web 工程下,有一个 admin 目录,这个
admin 目录下的所有资源(html 页面、 jpg 图片、
jsp 文件、等等)都必须是用户登录之后才允许
访问
用户登录之后都会把用户登录的信息保存到
Session 域中。所以要检查用户是否登录,
可以判断 Session 中否包含有用户登录的信息
即可
<%Object user = session.getAttribute("user");// 如果等于 null,说明还没有登录if (user == null) {request.getRequestDispatcher("/login.jsp").forward(request,response);return;}
%>

2. Filter 的工作流程图

3. Filter 的代码:

让程序继续往下访问用户的目标资源
filterChain.doFilter(servletRequest,servletResponse);

public class AdminFilter implements Filter {/*** doFilter 方法,专门用于拦截请求。可以做权限检查*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain
filterChain) throws IOException, ServletException {HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;HttpSession session = httpServletRequest.getSession();Object user = session.getAttribute("user");// 如果等于 null,说明还没有登录if (user == null) {servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);return;} else {// 让程序继续往下访问用户的目标资源filterChain.doFilter(servletRequest,servletResponse);}}
}

 web.xml 中的配置:

<!--filter 标签用于配置一个 Filter 过滤器-->
<filter><!--给 filter 起一个别名--><filter-name>AdminFilter</filter-name><!--配置 filter 的全类名-->
<filter-class>com.zh.filter.AdminFilter</filter-class>
</filter>
<!--filter-mapping 配置 Filter 过滤器的拦截路径-->
<filter-mapping><!--filter-name 表示当前的拦截路径给哪个 filter 使用--><filter-name>AdminFilter</filter-name><!--url-pattern 配置拦截路径/ 表示请求地址为:http://ip:port/工程路径/ 映射到 IDEA 的 web 目录/admin/* 表示请求地址为:http://ip:port/工程路径/admin/*--><url-pattern>/admin/*</url-pattern>
</filter-mapping>

4. Filter 过滤器的使用步骤:

① 编写一个实现 Filter 接口

② 实现过滤方法 doFilter()

③ 到 web.xml 中去配置 Filter 的拦截路径

5. 完整的用户登录

login.jsp 页面 == 登录表单

这是登录页面。login.jsp 页面 <br>
<form action="http://localhost:8080/15_filter/loginServlet" method="get">用户名:<input type="text" name="username"/> <br>密 码:<input type="password" name="password"/> <br><input type="submit" />
</form>

LoginServlet 程序

public class LoginServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {resp.setContentType("text/html; charset=UTF-8");String username = req.getParameter("username");String password = req.getParameter("password");if ("wzg168".equals(username) && "123456".equals(password)) {req.getSession().setAttribute("user",username);resp.getWriter().write("登录 成功!!!");} else {req.getRequestDispatcher("/login.jsp").forward(req,resp);}}
}

三、Filter 的生命周期

Filter 的生命周期包含几个方法:
1、 构造器 方法
2、 init 初始化 方法
第 1,2 步,在 web 工程启动的时候执行
(Filter 已经创建)
3、 doFilter 过滤 方法
第 3 步,每次拦截到请求,就会执行
4、 destroy 销毁
第 4 步,停止 web 工程的时候,就会执行
(停止 web 工程,也会销毁 Filter 过滤器)

四、FilterConfig 类

FilterConfig 类是 Filter 过滤器的配置文件类

Tomcat 每次创建 Filter 的时候,也会同时创建

一个 FilterConfig,这里包含了 Filter 配置文

件的配置信息

作用:

① 获取 Filter 的名称 filter-name 的内容
② 获取在 Filter 中配置的 init-param 初始化参数
③ 获取 ServletContext 对象

2. 代码

java 代码

    @Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("2.Filter 的 init(FilterConfig filterConfig)初始化");//         1、获取 Filter 的名称 filter-name 的内容System.out.println("filter-name 的值是:" + filterConfig.getFilterName());
//         2、获取在 web.xml 中配置的 init-param 初始化参数System.out.println("初始化参数 username 的值是:" +         filterConfig.getInitParameter("username"));System.out.println("初始化参数 url 的值是:" + filterConfig.getInitParameter("url"));
//         3、获取 ServletContext 对象System.out.println(filterConfig.getServletContext());
}

web.xml 配置:

<!--filter 标签用于配置一个 Filter 过滤器-->
<filter><!--给 filter 起一个别名--><filter-name>AdminFilter</filter-name><!--配置 filter 的全类名--><filter-class>com.zh.filter.AdminFilter</filter-class><init-param><param-name>username</param-name><param-value>root</param-value></init-param><init-param><param-name>url</param-name><param-value>jdbc:mysql://localhost3306/test</param-value></init-param>
</filter>

五、FilterChain 过滤器链

Filter              过滤器
Chain           链,链条
FilterChain   就是 过滤器链
                  (多个过滤器如何一起工作)

六、Filter 的拦截路径

1. 精确匹配

<url-pattern>/target.jsp</url-pattern>

表示请求地址必须为:

http://ip:port/工程路径/target.jsp

2. 目录匹配

<url-pattern>/admin/*</url-pattern>

表示请求地址必须为:

http://ip:port/工程路径/admin/*

3. 后缀名匹配

后缀名不能以斜杠 / 打头

<url-pattern>*.html</url-pattern>

表示请求地址必须以 .html 结尾才会拦截到

<url-pattern>*.do</url-pattern>

表示请求地址必须以 .do 结尾才会拦截到

<url-pattern>*.action</url-pattern>

表示请求地址必须以 .action 结尾才会拦截到

Filter 过滤器它只关心请求的地址是否匹配,
不关心请求的资源是否存在

七、使用 Filter 过滤器

1. 使用 Filter 过滤器拦截 /pages/manager/所有内容

    实现权限检查

Filter 代码:

public class ManagerFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain
filterChain) throws IOException, ServletException {HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;Object user = httpServletRequest.getSession().getAttribute("user");if (user == null) {httpServletRequest.getRequestDispatcher("/pages/user/login.jsp").forward(servletRequest,servletRes
ponse);} else {filterChain.doFilter(servletRequest,servletResponse);}}@Overridepublic void destroy() {}
}

web.xml 中的配置:

<filter><filter-name>ManagerFilter</filter-name><filter-class>com.atguigu.filter.ManagerFilter</filter-class>
</filter>
<filter-mapping><filter-name>ManagerFilter</filter-name><url-pattern>/pages/manager/*</url-pattern><url-pattern>/manager/bookServlet</url-pattern>
</filter-mapping>

2. ThreadLocal 的使用

(1) ThreadLocal 的作用:

ThreadLocal 可以解决多线程数据安全问题

ThreadLocal 可以给当前线程关联一个数据 (可

以是普通变量,可以是对象,也可以是数组

集合)

(2) ThreadLocal 的特点:

① ThreadLocal 可以为当前线程 关联一个数据
(它可以像 Map 一样存取数据, key 当前线程 )
② 每一个 ThreadLocal 对象,只能为当前线程
关联一个数据,如果要为当前线程关联多个 数据,
就需要使用多个 ThreadLocal 对象实例。
③ 每个 ThreadLocal 对象实例定义的时候,一般
都是 static 类型
④ ThreadLocal 中 保存数据 ,在 线程销毁 后,会
JVM 虚拟 自动释放

测试类:

public class OrderService {public void createOrder(){String name = Thread.currentThread().getName();System.out.println("OrderService 当前线程[" + name + "]中保存的数据是:" +
ThreadLocalTest.threadLocal.get());new OrderDao().saveOrder();}
}public class OrderDao {public void saveOrder(){String name = Thread.currentThread().getName();System.out.println("OrderDao 当前线程[" + name + "]中保存的数据是:" +
ThreadLocalTest.threadLocal.get());}
}public class ThreadLocalTest {// public static Map<String,Object> data = new Hashtable<String,Object>();public static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();private static Random random = new Random();public static class Task implements Runnable {@Overridepublic void run() {// 在 Run 方法中,随机生成一个变量(线程要关联的数据),然后以当前线程名为 key 保存到 map 中Integer i = random.nextInt(1000);// 获取当前线程名String name = Thread.currentThread().getName();System.out.println("线程["+name+"]生成的随机数是:" + i);
//             data.put(name,i);threadLocal.set(i);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}new OrderService().createOrder();// 在 Run 方法结束之前,以当前线程名获取出数据并打印。查看是否可以取出操作
//             Object o = data.get(name);Object o = threadLocal.get();System.out.println("在线程["+name+"]快结束时取出关联的数据是:" + o);}}public static void main(String[] args) {for (int i = 0; i < 3; i++){new Thread(new Task()).start();}}
}

3. 使用 Filter ThreadLocal 组合管理事务

(1) 使用 ThreadLocal 来确保所有 dao 操作都在

     同一个 Connection 连接对象中完成

JdbcUtils 工具类的修改:

public class JdbcUtils {private static DruidDataSource dataSource;private static ThreadLocal<Connection> conns = new ThreadLocal<Connection>();static {try {Properties properties = new Properties();// 读取 jdbc.properties 属性配置文件InputStream inputStream =
JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");// 从流中加载数据properties.load(inputStream);// 创建 数据库连接 池dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);} catch (Exception e) {e.printStackTrace();}}/*** 获取数据库连接池中的连接* @return 如果返回 null,说明获取连接失败<br/>有值就是获取连接成功*/public static Connection getConnection(){Connection conn = conns.get();if (conn == null) {try {conn = dataSource.getConnection();//从数据库连接池中获取连接conns.set(conn); // 保存到 ThreadLocal 对象中,供后面的 jdbc 操作使用conn.setAutoCommit(false); // 设置为手动管理事务} catch (SQLException e) {e.printStackTrace();}}return conn;}/*** 提交事务,并关闭释放连接*/public static void commitAndClose(){Connection connection = conns.get();if (connection != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库try {connection.commit(); // 提交 事务} catch (SQLException e) {e.printStackTrace();} finally {try {connection.close(); // 关闭连接,资源资源} catch (SQLException e) {e.printStackTrace();}}}// 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术)conns.remove();}/*** 回滚事务,并关闭释放连接*/public static void rollbackAndClose(){Connection connection = conns.get();if (connection != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库try {connection.rollback();//回滚事务} catch (SQLException e) {e.printStackTrace();} finally {try {connection.close(); // 关闭连接,资源资源} catch (SQLException e) {e.printStackTrace();}}}// 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术)conns.remove();}/*** 关闭连接,放回数据库连接池* @param connpublic static void close(Connection conn){if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}} */
}

修改 BaseDao

public abstract class BaseDao {//使用 DbUtils 操作数据库private QueryRunner queryRunner = new QueryRunner();/*** update() 方法用来执行:Insert\Update\Delete 语句** @return 如果返回-1,说明执行失败<br/>返回其他表示影响的行数*/public int update(String sql, Object... args) {System.out.println(" BaseDao 程序在[" +Thread.currentThread().getName() + "]中");Connection connection = JdbcUtils.getConnection();try {return queryRunner.update(connection, sql, args);} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}/*** 查询返回一个 javaBean 的 sql 语句** @param type 返回的对象类型* @param sql 执行的 sql 语句* @param args sql 对应的参数值* @param <T> 返回的类型的泛型* @return*/public <T> T queryForOne(Class<T> type, String sql, Object... args) {Connection con = JdbcUtils.getConnection();try {return queryRunner.query(con, sql, new BeanHandler<T>(type), args);} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}/*** 查询返回多个 javaBean 的 sql 语句** @param type 返回的对象类型* @param sql 执行的 sql 语句* @param args sql 对应的参数值* @param <T> 返回的类型的泛型* @return*/public <T> List<T> queryForList(Class<T> type, String sql, Object... args) {Connection con = JdbcUtils.getConnection();try {return queryRunner.query(con, sql, new BeanListHandler<T>(type), args);} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}/*** 执行返回一行一列的 sql 语句* @param sql 执行的 sql 语句* @param args sql 对应的参数值* @return*/public Object queryForSingleValue(String sql, Object... args){Connection conn = JdbcUtils.getConnection();try {return queryRunner.query(conn, sql, new ScalarHandler(), args);} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}
}

(2) 使用 Filter 过滤器统一给所有的 Service

    方法都加上 try-catch,来进行实现的管理

 Filter 类代码:

public class TransactionFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain
filterChain) throws IOException, ServletException {try {filterChain.doFilter(servletRequest,servletResponse);JdbcUtils.commitAndClose();// 提交事务} catch (Exception e) {JdbcUtils.rollbackAndClose();//回滚事务e.printStackTrace();}}
}

web.xml 中的配置:

<filter><filter-name>TransactionFilter</filter-name><filter-class>com.atguigu.filter.TransactionFilter</filter-class>
</filter>
<filter-mapping><filter-name>TransactionFilter</filter-name><!-- /* 表示当前工程下所有请求 --><url-pattern>/*</url-pattern>
</filter-mapping>

一定记得把 BaseServlet 中的异常往外抛给

Filter 过滤器

public abstract class BaseServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {doPost(req, resp);}protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {// 解决 post 请求中文乱码问题// 一定要在获取请求参数之前调用才有效req.setCharacterEncoding("UTF-8");String action = req.getParameter("action");try {// 获取 action 业务鉴别字符串,获取相应的业务 方法反射对象Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class,
HttpServletResponse.class);
//             System.out.println(method);// 调用目标业务 方法method.invoke(this, req, resp);} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);// 把异常抛给 Filter 过滤器}}
}

(3) 将所有异常都统一交给 Tomcat,让 Tomcat

     展示友好的错误信息页面

web.xml 中我们可以通过错误页面配置来进行管理

<!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page><!--error-code 是错误类型--><error-code>500</error-code><!--location 标签表示。要跳转去的页面路径--><location>/pages/error/error500.jsp</location>
</error-page><!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page><!--error-code 是错误类型--><error-code>404</error-code><!--location 标签表示。要跳转去的页面路径--><location>/pages/error/error404.jsp</location>
</error-page>


http://chatgpt.dhexx.cn/article/09W9MWB3.shtml

相关文章

filter过滤器的概念

文章目录 1. 图示2. 什么是Filter3. 代码演示4. 使用场景&#xff1a;事务处理 1. 图示 2. 什么是Filter Filter也属于Servlet规范Filter开发步骤&#xff1a;新建类实现Filter接口&#xff0c;然后实现其中的三个方法&#xff1a;init、doFilter、destroy 配置Filter&#xf…

Filter 过滤器使用

一、什么是Filter过滤器 Filter 过滤器它是 JavaWeb 的三大组件之一。 三大组件分别是&#xff1a;Servlet 程序、Listener 监听器、Filter 过滤器 Filter 过滤器它是 JavaEE 的规范。也就是接口 Filter 过滤器它的作用是&#xff1a;拦截请求&#xff0c;过滤响应。 拦截…

Filter过滤器(超详细)

声明&#xff1a;本文是根据博主学习内容所整理得的笔记&#xff0c;仅作为交流学习使用&#xff0c;需要观看视频的请移步&#xff1a;http://www.atguigu.com/ 1.Filter &#xff1f;什么是过滤器 Filter 过滤器它是 JavaWeb 的三大组件之一。 三大组件分别是&#xff1a;S…

GitHub使用教程(完整教程)

第一步&#xff1a;进入官网 &#xff08;https://github.com/&#xff09; 第二步&#xff1a;新建账号——输入用户名&#xff0c;邮箱&#xff0c; 密码——邮箱确认——登录GitHub 第三步&#xff1a;创建仓库 第三步&#xff1a;查看仓库 第四步&#xff1a;实现本地项目…

Git和Github详细入门教程(别再跟我说你不会Git和Github)

前言&#xff1a;基础差建议先观看B站视频&#xff08;关键字&#xff1a;GitHub&#xff09;&#xff0c;该教程是根据视频教程而制。 文章目录 01.Git概述02.Git的本地仓库操作 Git的版本回退操作 03.远程仓库05.Git的分支操作06.冲突的产生与解决07.Git实用功能08.忽略文件0…

GitHub Actions 入门教程

https://jiangren.com.au/blog/github-actions 一、GitHub Actions 是什么&#xff1f; 大家知道&#xff0c;持续集成由很多操作组成&#xff0c;比如抓取代码、运行测试、登录远程服务器&#xff0c;发布到第三方服务等等。GitHub 把这些操作就称为 actions。 很多操作在不…

小白入门~ GitHub和Git超详细使用教程

https://github.com/ 这是GitHub的官方网站&#xff0c;在官网上可以注册属于自己的GitHub账号&#xff0c;网上是全英文的&#xff0c;对于英语不好的同学建议使用谷歌浏览器&#xff0c;谷歌浏览器可以翻译网页变为中文使用起来十分方便。 通过简单的步骤之后你就会有一个属于…

GitHub使用教程(项目下载)

1.登录GitHub后选择左上角搜索框&#xff08;以点餐系统为例&#xff09; 2.选择合适的项目进入 3.选择合适的项目进入后&#xff0c;点击Code 4.点击Download ZIP即可下载项目代码压缩包

github使用教程图文详解(一)[入门]

git的使用和踩坑 Git的注册下载本地github工具绑定ssh秘钥获取ssh秘钥官网绑定ssh秘钥 创建远程库初始化仓库设置全局签名和单仓库签名的作用单仓库签名全局用户签名 提交到本地仓库git区域的划分提交到缓存区提交本地仓库和备注提交总结注意: 提交到远程仓库克隆远程仓库总结 …

GitHub 的 10 分钟快速入门教程

Hello World 这一篇是 GitHub 的 10 分钟快速入门教程&#xff0c;因为找不到中文版&#xff0c;大橙子自己给大家翻译了一下。 Hello World 项目是计算机编程的一个历史悠久的传统。这一篇我们也通过这个简单的练习让你学习到新的知识。那么就让我们开始 GitHub 的学习旅程吧…

【Github教程】史上最全github使用方法:github入门到精通

【初识Github】 首先让我们大家一起喊一句“Hello Github”。YEAH!就是这样。 Git是一个分布式的版本控制系统,最初由Linus Torvalds编写,用作Linux内核代码的管理。在推出后,Git在其它项目中也取得了很大成功,尤其是在Ruby社区中。目前,包括Rubinius和Merb在内的很多知名…

Github和Git的基本教程,适合新手

借鉴了这个博主的笔记 观看了b站up主的视频 Github和Git的基本使用 Github一.基本概念二 .创建账号三.创建仓库四&#xff1a;仓库管理五.仓库主页英文介绍 Git一. Git优势二.下载地址三.基本信息设置四.工作区域&#xff08;上传文件到Github&#xff09;五.删除文件六. 修改…

github入门教程最全中文版(官方)

该的Hello World项目是计算机编程历史悠久的传统。这是一个简单的练习&#xff0c;可以让你在学习新东西时开始学习。让我们开始使用GitHub&#xff01; 您将学习如何&#xff1a; 创建和使用存储库启动并管理新分支对文件进行更改并将其作为提交推送到GitHub打开并合并拉取请…

github注册以及安装教程

github注册以及安装教程 首先&#xff0c;我们了解一下github.gitHub 是一个面向开源及私有软件项目的托管平台&#xff0c;因为只支持 git 作为唯一的版本库格式进行托管&#xff0c;故名 gitHub。github 于 2008 年 4 月 10 日正式上线&#xff0c;除了 git 代码仓库托管及基…

GitHub快速上手--GitHub高效操作教程

一、前言 如果你正在看我的这篇文章&#xff0c;说明你已经对GitHub有了一些基础的了解&#xff0c;下面我们将详细叙述每一步的操作&#xff0c;以保证你能够快速上手GitHub&#xff0c;完成对代码的管理。 二、创建仓库 登录GitHub账号&#xff0c;点击页面右上角的加号&am…

GitHub使用教程-官网指南

此文为GitHub官网操作示例&#xff0c;英文原版见下文或访问地址&#xff1a;Hello World GitHub Guides Hello World 十分钟教学指南 Hello World项目在计算机编程领域是一个历史悠久的传统。当你学习一些新的东西的时候&#xff0c;它是你开始学习的一个简单的练习。让我…

GitHub注册教程(图文详解)

一、注册github流程 1.首先进入github官网 https://github.com/ 2.点击绿色框Sign up for GitHub进行注册 3.注册页面第一栏email&#xff08;邮箱&#xff09;&#xff0c;第二栏password&#xff08;密码&#xff09;&#xff0c;第三栏username&#xff08;用户名&#xff…

手把手教你简易上手GitHub(教程)

1.创建仓库 仓库是存储想法、资源甚至与他人共享和讨论的地方。&#xff08;记笔记的地方&#xff09; 在任何页面的右上角&#xff0c;使用 下拉菜单选择 New repository&#xff08;新建仓库&#xff09;。 在 Repository name&#xff08;存储库名称&#xff09;框中&am…

Github注册教程

GitHub注册教程 目录 一&#xff0e; 认识GitHub二&#xff0e; 注册GitHub三&#xff0e; 使用GitHub 一&#xff0e; 认识GitHub GitHub是一个托管代码的网站&#xff0c;只支持Git作为唯一的版本库格式进行托管。2018年6月4日&#xff0c;微软收购GitHub。 二&#xff0e; 注…

GitHub教程 Git Bash详细教程

文章目录 1 下载安装2 设置用户3 本地文件夹的操作 3.1 进入文件夹3.2 查看3.3 退出文件夹3.4 新建、删除 4 仓库设置 4.1 初始化本地仓库4.2 新建远程仓库4.3 建立连接4.4 文件上传4.5 文件下拉4.5 文件克隆 这个主要介绍Git Bash的使用教程。 1 下载安装 首先抛一个Win…