Filter和Listener

1. Filter 过滤器

1 过滤器简介

  • Filter过滤器是JavaWeb的三大组件(Servlet程序、Listener监听器、Filter过滤器)之一

  • Filter作用:拦截请求、过滤响应

  • 是javaee的规范也是接口

  • 拦截请求常见的应用有

    • 权限检查
    • 日记操作
    • 事务管理

2 Filter 生命周期

Filter的生命周期包含几个方法

  1. 构造器方法
  2. init初始化方法
  3. doFilter过滤方法,每次拦截到请求,就会执行
  4. destory销毁

构造器方法和初始化方法都在web工程启动时执行,停止web工程的时候,只执行销毁方法,销毁Filter过滤器

从Java Servlet 3.0 规范开始,为了简化开发,Filter接口引入了默认方法(default methods),其中包括了默认的initdestroy方法的实现。这意味着,你可以只实现doFilter方法来编写自定义的过滤逻辑,而不需要显式地实现initdestroy方法。

3 拦截路径

在web.xml中配置

xml 复制代码
<filter>
	<filter-name>connectionFilter</filter-name>
    <filter-class>filter.ConnectionFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>connectionFilter</filter-name>
    <url-pattern>/user/*</url-pattern>
</filter-mapping>
  • 精确匹配
xml 复制代码
<url-pattern>/target.jsp</url-pattern>
以上配置的路径,表示请求地址必须为 http://ip:port/工程路径/target.jsp
  • 目录匹配
xml 复制代码
<url-pattern>/admin/*</url-pattern>
以上配置的路径, 表示请求地址必须为: http://ip:port/工程路径/admin/*
  • 后缀匹配
xml 复制代码
<url-pattern>*.html</url-pattern>
以上配置的路径, 表示请求地址必须以.html 结尾才会拦截到
<url-pattern>*.do</url-pattern>
以上配置的路径, 表示请求地址必须以.do 结尾才会拦截到
<url-pattern>*.action</url-pattern>
以上配置的路径, 表示请求地址必须以.action 结尾才会拦截到

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

4 FilterConfig类

是Filter的配置文件类

Tomcat 每次创建 Filter 的时候, 也会同时创建一个 FilterConfig 类, 这里包含了 Filter 配置文件的配置信息。FilterConfig 类的作用是获取 filter 过滤器的配置内容

  • 获取 Filter 的名称 filter-name 的内容

  • 获取在 Filter 中配置的 init-param 初始化参数

  • 获取 ServletContext 对象

web.xml

xml 复制代码
<!--filter 标签用于配置一个 Filter 过滤器-->
<filter>
	<!--给 filter 起一个别名-->
	<filter-name>AdminFilter</filter-name>
	<!--配置 filter 的全类名-->										<filterclass>com.lxs.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>

java

java 复制代码
@Override
public 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());
}

5 Filter Chain过滤器链

工作流程图

过滤器链

  • 多个过滤器执行的特点

    • 所有filter和目标资源默认都执行在同一个线程中
    • 多个filter共同执行时,都使用同一个request对象
  • FilterChain.doFilter()方法的作用:

    • 执行下一个Filter(有Filter)
    • 执行目标资源(没有Filter)

    在多个Filter过滤器执行的时候,执行的优先顺序是由在web.xml中从上到下的顺序决定的

Filter1

java 复制代码
public class Filter1 implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
    	Filter.super.init(filterConfig);
		System.out.println("filter1 初始化方法");
	}
	@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException,ServletException {
        System.out.println("filter1 前置 过滤方法 ");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("filter1 后置 过滤方法 ");
	}
    @Override
    public void destroy() {
    	Filter.super.destroy();
    	System.out.println("销毁方法1");
	}
}

Filter2

java 复制代码
public class Filter1 implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
    	Filter.super.init(filterConfig);
		System.out.println("filter2 初始化方法");
	}
	@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException,ServletException {
        System.out.println("filter2 前置 过滤方法 ");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("filter2 后置 过滤方法 ");
	}
    @Override
    public void destroy() {
    	Filter.super.destroy();
    	System.out.println("销毁方法2");
	}
}

web.xml

xml 复制代码
<filter>
    <filter-name>filter1</filter-name>
    <filter-class>com.lxs.demo.filter.Filter1</filter-class>
</filter>
<filter-mapping>
	<filter-name>filter1</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
    <filter-name>filter2</filter-name>
    <filter-class>com.lxs.demo.filter.Filter2</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

6 Filter登录校验

要求:让在web工程下的所有资源在登录后才能被访问

注:WEB-INF目录下的文件不能被直接访问,只能通过转发访问

Filter过滤器使用步骤

  • 编写一个类去实现啊Filter接口
  • 实现过滤方法doFilter()
  • 到web.xml中去配置filter的拦截路径

Filter

java 复制代码
public class AdminFilter implements Filter {
    /**
    * doFilter 方法, 专门用于拦截请求。 可以做权限检查
    */
    @Override
    public 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

xml 复制代码
<!--filter 标签用于配置一个 Filter 过滤器-->
<filter>
    <!--给 filter 起一个别名-->
    <filter-name>AdminFilter</filter-name>
    <!--配置 filter 的全类名-->
    <filter-class>com.lxs.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>

login.jsp 登录表单

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

java 复制代码
public class LoginServlet extends HttpServlet {
    @Override
    protected 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);
        }
    }
}

7 HttpServletRequestWrapper

HttpServletRequestWrapper是Servlet中的一个包装器类,用于对原始的HttpServletRequest对象进行包装和增强。它继承自ServletRequestWrapper类,并实现了HttpServletRequest接口。

通过使用HttpServletRequestWrapper,可以在HttpServletRequest对象的基础上添加自定义的功能或修改请求的参数、头部信息等内容,同时也能保持对原始HttpServletRequest方法的支持。

HttpServletRequestWrapper的使用通常包括以下几个步骤:

  1. 创建一个自定义的HttpServletRequestWrapper类,该类需要继承HttpServletRequestWrapper,并实现HttpServletRequest接口的所有抽象方法。

  2. 在自定义HttpServletRequestWrapper类中重写需要增强或修改的方法。例如,可以重写getParameter()方法来修改请求参数的值,或重写getHeader()方法来添加额外的头部信息。

  3. 在自定义HttpServletRequestWrapper类的构造函数中调用父类的构造函数,将原始的HttpServletRequest对象传递进去。

  4. 在Servlet中使用自定义的HttpServletRequestWrapper类来处理请求。可以通过在Servlet中获取到的HttpServletRequest对象创建自定义的HttpServletRequestWrapper对象,然后将其传递给其他的方法进行处理。

通过HttpServletRequestWrapper,我们可以在不修改原始ServletRequest对象的情况下,对请求进行定制化的处理,实现自定义需求。例如,可以用于实现请求参数的过滤、修改请求头、添加额外的请求验证等操作。

实现敏感词过滤

java 复制代码
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class SensitiveWordFilterWrapper extends HttpServletRequestWrapper {

    public SensitiveWordFilterWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (value != null) {
            // 进行敏感词过滤处理
            value = sensitiveWordFilter(value);
        }
        return value;
    }

    private String sensitiveWordFilter(String value) {
        // 在这里编写敏感词过滤的逻辑,可以使用正则表达式或其他算法进行匹配和替换操作
        // 示例代码只是简单替换了一些敏感词为*
        value = value.replaceAll("敏感词1", "*");
        value = value.replaceAll("敏感词2", "*");
        /* // 对获取到的参数进行处理或修改
            if (name.equals("key")) {
                if ("敏感词".equals(value)) {
                    return "XXX(和谐)";
                }
            }*/
        // ...
        return value;
    }
}

在上面的示例中,我们创建了一个名为SensitiveWordFilterWrapper的类,继承自HttpServletRequestWrapper,并重写了其中的getParameter()方法。在重写的方法中,首先调用父类的getParameter()方法获取原始的请求参数值,然后对该值进行敏感词过滤处理,最后返回处理后的值。

敏感词过滤的具体实现逻辑可以根据需求来定制,可以使用正则表达式、Trie树等算法来匹配和替换敏感词。上述示例代码只是一个简单的示例,将敏感词替换为了*,实际情况中可能需要更复杂的处理逻辑。

在使用该包装器类时,需要在Servlet中将原始的HttpServletRequest对象替换为自定义的SensitiveWordFilterWrapper对象,示例如下:

java 复制代码
public class MyServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpServletRequest wrappedRequest = new SensitiveWordFilterWrapper(req);
        // 使用包装后的请求对象进行处理
        // ...
    }
}

2. Listener 监听器

1 什么是监听器

监听器就是监听某个域对象的的状态变化的组件

监听器的相关概念:

  • 事件源:被监听的对象(三个域对象 request、session、servletContext)

  • 监听器:监听事件源对象事件源对象的状态的变化都会触发监听器

  • 注册监听器:将监听器与事件源进行绑定

  • 响应行为:监听器监听到事件源的状态变化时所涉及的功能代码(程序员编写代码)

2 监听器分类

第一维度是按被监听的对象划分:ServletRequest域,HttpSession域,ServletContext域

第二维度按照监听的内容分:监听域对象的创建与销毁的,监听域对象的属性变化的

java 复制代码
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent){
    	System.out.println("contextInitialized");
    }
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
    	System.out.println("contextDestroyed");
    }
}

web.xml

xml 复制代码
<listener>
	<listener-class>com.filter.MyListener</listener-class>
</listener>
相关推荐
xlsw_2 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹3 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭3 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
南宫生3 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石4 小时前
12/21java基础
java
李小白664 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp4 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶4 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb