当前位置:   article > 正文

Tomcat 学习之 Filter 过滤器

Tomcat 学习之 Filter 过滤器

目录

1 Filter 介绍

2 Filter 的生命周期

3 Filter 和 FilterChain

4 Filter 拦截过程

5 FilterConfig

6 Filter 使用


1 Filter 介绍

        在 Tomcat 中,Filter 是一种用于拦截请求过滤响应的组件,可以在请求到达 Servlet 之前或响应离开 Servlet 之后对其进行处理。

Filter 的主要应用场景包括:

  1. 权限控制:可以使用 Filter 来检查请求的用户是否具有访问特定资源的权限
  2. 日志记录:可以使用 Filter 来记录请求和响应的信息,以便进行监控和故障排除
  3. 性能监控:可以使用 Filter 来测量请求的处理时间和响应时间,以便进行性能优化
  4. 数据加密和解密:可以使用 Filter 来对请求和响应进行加密和解密,以保护敏感信息的安全

2 Filter 的生命周期

Filter 的生命周期由 Tomcat 容器管理,包含以下几个方法:

  1. 构造器方法,在 web 工程启动的时候执行
  2. init 初始化方法,在 web 工程启动的时候执行
  3. doFilter 过滤方法,每次拦截到请求,就会执行
  4. destroy 销毁,停止 web 工程的时候,就会销毁 Filter 过滤器

3 Filter 和 FilterChain

Filter 接口

  1. public interface Filter {
  2. // 容器创建的时候调用, 即启动 Tomcat 的时候调用
  3. public void init(FilterConfig filterConfig) throws ServletException;
  4. // 由 FilterChain 调用, 并且传入 FilterChain 本身, 最后回调 FilterChain 的 doFilter() 方法
  5. public void doFilter(ServletRequest request, ServletResponse response,
  6. FilterChain chain) throws IOException, ServletException;
  7. // 容器销毁的时候调用, 即关闭 Tomcat 的时候调用
  8. public void destroy();
  9. }

FilterChain 接口

  1. public interface FilterChain {
  2. // 由 Filter.doFilter() 中的 chain.doFilter 调用
  3. public void doFilter(ServletRequest request, ServletResponse response)
  4. throws IOException, ServletException;
  5. }

        当 Tomcat 接收到 URL 请求时,它会根据在 web.xml 文件中配置的过滤器和映射路径来创建 FilterChain。如果某个请求匹配了一些过滤器的映射路径,那么这些过滤器将被添加到 FilterChain。创建了 FilterChain 之后,就开始执行 doFilter,进行请求的链式处理。

过滤器执行顺序:

  • 通过 web.xml 配置的 Filter 过滤器,执行顺序由 <filter-mapping> 标签的配置顺序决定。<filter-mapping> 靠前,则 Filter 先执行,靠后则后执行。通过修改 <filter-mapping> 的顺序便可以修改 Filter 的执行顺序
  • 通过 @WebFilter 注解配置的 Filter 过滤器,无法进行排序,若需要对 Filter 过滤器进行排序,建议使用 web.xml 进行配置

4 Filter 拦截过程

        如图是 Filter 拦截过程示意图。所有 Filter 和 Web 资源都默认执行在同一个线程中(因为Filter 和 Web 资源通常是在 HttpServlet 容器中运行的,而 HttpServlet 容器是基于单线程模型的)。对于 FilterChain 中的 Filter,它们都使用同一 Request 对象。

以下是 Filter 拦截过程的一般步骤:

  1. 客户端发送请求到给 Web 服务器
  2. Web 服务器接收到请求后,将请求传递给 HttpServlet 容器
  3. HttpServlet 容器根据请求的 URL 路径和配置的映射信息,确定应该调用哪些 Filter
  4. Filter 的 doFilter() 方法被调用,该方法将接收请求和响应对象作为参数
  5. 在 doFilter() 方法中,Filter 可以执行各种操作,例如检查请求头、修改请求参数、处理权限验证等
  6. 如果 Filter 决定继续处理请求,它可以通过调用 filterChain.doFilter() 方法将请求传递给下一个 Filter(如果有下一个 Filter)或 Web 资源(没有下一个 Filter)
  7. 下一个 Filter 的 doFilter() 方法被调用,直到请求到达最终的目标资源
  8. 目标资源处理请求并生成响应,响应通过 Filter 链反向传递,每个 Filter 都可以在响应离开之前对其进行修改或处理
  9. 最终,响应被发送回客户端,客户端接收到处理后的结果

FilterConfig

        FilterConfig 是 Filter 过滤器的配置文件类。Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,它包含了 Filter 配置文件的配置信息。
FilterConfig 类的作用是获取 filter 过滤器的配置内容
  • 获取 Filter 的名称 filter-name 的内容
  • 获取在 Filter 中配置的 init-param 初始化参数
  • 获取 ServletContext 对象
  1. @Override
  2. public void init(FilterConfig filterConfig) throws ServletException {
  3. // 1、获取 Filter 的名称 filter-name 的内容
  4. System.out.println("filter-name 的值是:" + filterConfig.getFilterName());
  5. // 2、获取在 web.xml 中配置的 init-param 初始化参数
  6. System.out.println("初始化参数 username 的值是:" + filterConfig.getInitParameter("username"));
  7. System.out.println("初始化参数 url 的值是:" + filterConfig.getInitParameter("url"));
  8. // 3、获取 ServletContext 对象
  9. System.out.println(filterConfig.getServletContext());
  10. }

6 Filter 使用

工程目录

web.xml 配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  5. version="4.0">
  6. <!-- <display-name> 元素常用于配置 servlet、过滤器或其他 Web 组件的显示名称。
  7. 这个显示名称主要用于在管理界面或日志中标识该组件,以方便识别和管理。 -->
  8. <!-- 标识项目名 -->
  9. <display-name>ServletTest</display-name>
  10. <!-- 定义首页文件,也就是用户直接输入域名时跳转的页面(如http://localhost:8080/)-->
  11. <welcome-file-list>
  12. <welcome-file>login.jsp</welcome-file>
  13. </welcome-file-list>
  14. <!--filter 标签用于配置一个 Filter 过滤器-->
  15. <filter>
  16. <!--给 filter 起一个别名-->
  17. <filter-name>AdminFilter1</filter-name>
  18. <!--配置 filter 的全类名-->
  19. <filter-class>com.test.AdminFilter1</filter-class>
  20. <!-- 设置 Servlet 初始化参数
  21. 可以通过 FilterConfig.getInitParamenter(String name) 方法访问初始化参数 -->
  22. <init-param>
  23. <param-name>username</param-name>
  24. <param-value>root</param-value>
  25. </init-param>
  26. <init-param>
  27. <param-name>url</param-name>
  28. <param-value>jdbc:mysql://localhost3306/test</param-value>
  29. </init-param>
  30. </filter>
  31. <!-- 设置 filter 映射 -->
  32. <filter-mapping>
  33. <!-- 和 filter 标签中的 filter-name 对应 -->
  34. <filter-name>AdminFilter1</filter-name>
  35. <!-- 设置匹配的路径,这里设置为 /img/* 表示访问 img 目录下的图片都会调用该 filter(AdminFilter) -->
  36. <url-pattern>/img/*</url-pattern>
  37. </filter-mapping>
  38. <filter>
  39. <filter-name>AdminFilter2</filter-name>
  40. <filter-class>com.test.AdminFilter2</filter-class>
  41. </filter>
  42. <filter-mapping>
  43. <filter-name>AdminFilter2</filter-name>
  44. <url-pattern>/img/*</url-pattern>
  45. </filter-mapping>
  46. </web-app>

login.jsp 

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>登录</title>
  5. </head>
  6. <body>
  7. <form action="http://localhost:8080/servlettest/loginServlet" method="get">
  8. 用户名: <input type="text" name="username"/> <br>
  9. 密 码: <input type="password" name="password"/> <br>
  10. <input type="submit" />
  11. </form>
  12. </body>
  13. </html>

LoginServlet 类

  1. package com.test;
  2. import javax.servlet.ServletException;
  3. import javax.servlet.annotation.WebServlet;
  4. import javax.servlet.http.HttpServlet;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import java.io.IOException;
  8. @WebServlet("/loginServlet")
  9. public class LoginServlet extends HttpServlet {
  10. @Override
  11. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
  12. IOException {
  13. resp.setContentType("text/html; charset=UTF-8");
  14. String username = req.getParameter("username");
  15. String password = req.getParameter("password");
  16. if ("root".equals(username) && "123456".equals(password)) {
  17. System.out.println("设置 Seesion: {user : " + username + " }");
  18. req.getSession().setAttribute("user",username);
  19. System.out.println("登录成功!");
  20. resp.getWriter().write("登录 成功!!!");
  21. } else {
  22. System.out.println("登录失败!");
  23. req.getRequestDispatcher("/login.jsp").forward(req,resp);
  24. }
  25. }
  26. }

AdminFilter1 类

  1. package com.test;
  2. import javax.servlet.*;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpSession;
  5. import java.io.IOException;
  6. public class AdminFilter1 implements Filter {
  7. // doFilter 方法,专门用于拦截请求。可以做权限检查
  8. @Override
  9. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain
  10. filterChain) throws IOException, ServletException {
  11. System.out.println("过滤器 AdminFilter1");
  12. HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
  13. HttpSession session = httpServletRequest.getSession();
  14. Object user = session.getAttribute("user");
  15. // System.out.println("登录用户: " + user);
  16. // 如果等于 null,说明还没有登录
  17. if (user == null) {
  18. System.out.println("未登录,跳转到登录页面");
  19. servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
  20. return;
  21. } else {
  22. // 让程序继续往下访问用户的目标资源
  23. System.out.println("AdminFilter1 调用 doFilter 方法");
  24. filterChain.doFilter(servletRequest,servletResponse);
  25. System.out.println("AdminFilter1 结束了 doFilter 方法的调用");
  26. }
  27. }
  28. @Override
  29. public void init(FilterConfig filterConfig) throws ServletException {
  30. // 1、获取 Filter 的名称 filter-name 的内容
  31. System.out.println("filter-name 的值是:" + filterConfig.getFilterName());
  32. // 2、获取在 web.xml 中配置的 init-param 初始化参数
  33. System.out.println("初始化参数 username 的值是:" + filterConfig.getInitParameter("username"));
  34. System.out.println("初始化参数 url 的值是:" + filterConfig.getInitParameter("url"));
  35. // 3、获取 ServletContext 对象
  36. System.out.println(filterConfig.getServletContext());
  37. }
  38. }

AdminFilter2 类

  1. package com.test;
  2. import javax.servlet.*;
  3. import java.io.IOException;
  4. public class AdminFilter2 implements Filter {
  5. // doFilter 方法,专门用于拦截请求。可以做权限检查
  6. @Override
  7. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain
  8. filterChain) throws IOException, ServletException {
  9. System.out.println("过滤器 AdminFilter2");
  10. System.out.println("AdminFilter2 调用 doFilter 方法");
  11. filterChain.doFilter(servletRequest,servletResponse);
  12. System.out.println("AdminFilter2 结束了 doFilter 方法的调用");
  13. }
  14. }

运行演示图

运行流程:

  1. 启动服务器 Tomcat,创建 AdminFilter1 和 AdminFilter2 对象,获取 FilterConfig 配置并初始化,创建 LoginServlet 对象,获取 ServletConfig 配置并初始化,进入首页文件 login.jsp
  2. 客户端尝试请求访问 http://localhost:8080/servlettest/img/2.jpg,由过滤器 AdminFilter1 处理,输出“过滤器 AdminFilter1”和“未登录,跳转到登录页面”,之后跳转到 login.jsp 进行登录
  3. 输入账号:root,密码:123456,由 LoginServlet 的 doGet() 方法处理,设置 Seesion: {user : root },输出“登录成功!”
  4. 客户端再次请求访问 http://localhost:8080/servlettest/img/2.jpg,由过滤器 AdminFilter1 和 AdminFilter2 依次处理(调用 filterChain.doFilter 方法后可以对响应结果进行处理),之后返回响应结果给客户端
  5. 客户端得到响应结果,显示图片
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/146912
推荐阅读
相关标签
  

闽ICP备14008679号