过滤与监听

2023-12-26 13:11:24

过滤与监听

一.过滤器Filter

1.概述

(1)概念

  • 过滤器是一个服务器端的组件,它可以截取客户端的请求和服务端的响应信息,并对这些信息进行过滤。

(2)原理

  • 先过滤,后放行

在这里插入图片描述

(3)应用场景

  • 统一处理中文编码
  • 统一处理登录控制

2.创建Filter过滤器

(1)方式1

  • web.xml注册过滤器
a.创建一个普通类实现Filter接口,并重写Filter接口中的三个方法
package com.lfg.filter;

import javax.servlet.*;
import java.io.IOException;

public class FirstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter");
        //放行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("filter destroy");
    }
}
b.在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_4_0.xsd"
         version="4.0">
    <!--注册过滤器-->
    <filter>
        <filter-name>FirstFilter</filter-name>
        <filter-class>com.lfg.filter.FirstFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FirstFilter</filter-name>
        <!--配置过滤路径-->
        <url-pattern>/index.jsp</url-pattern>
    </filter-mapping>
</web-app>

(2)方式2

  • 注解方式注册过滤器
a.创建一个普通类实现Filter接口,并重写Filter接口中的三个方法,再使用注解注册过滤器
  • @WebFilter(“/index.jsp”)
package com.lfg.filter;

import javax.servlet.*;
import java.io.IOException;
@WebFilter("/index.jsp")
public class FirstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter");
        //放行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("filter destroy");
    }
}

3.常用路径配置格式

格式描述
/*过滤所有的服务器端资源
*.jsp过滤所有以.jsp结尾的服务器端资源
/studentServlet只能过滤studentServlet这个路径的服务器端资源

4.过滤器的生命周期

生命周期描述
init()调用init()方法初始化实例,在服务器启动时只调用一次
doFilter()每次访问请求,如果被访问的请求符合过滤条件都会调用doFilter()方法进行真正的过滤处理
destroy()停止服务器调用destroy()方法,销毁实例,释放资源,只执行一次

5.过滤器特点

(1)一个过滤器可以过滤多个servlet或者请求路径

a.web.xml
 <filter>
     <filter-name>FirstFilter</filter-name>
     <filter-class>com.lfg.filter.FirstFilter</filter-class>
 </filter>
 <filter-mapping>
     <filter-name>FirstFilter</filter-name>
     <!--配置过滤路径-->
     <url-pattern>/index.jsp</url-pattern>
 </filter-mapping>
 <filter-mapping>
     <filter-name>FirstFilter</filter-name>
     <!--配置过滤路径-->
     <url-pattern>/studentServlet</url-pattern>
 </filter-mapping>
b.注解
@WebFilter(filterName = "FirstFilter",urlPatterns = {"/index.jsp","/studentServlet"})

(2)过滤器默认情况下只过滤重定向的路径(地址栏中的路径),不过滤转发路径

  • 配置过滤转发路径
a.web.xml
 <filter-mapping>
     <filter-name>FirstFilter</filter-name>
     <!--配置过滤路径-->
     <url-pattern>/test.jsp</url-pattern>
     <dispatcher>FORWARD</dispatcher>
 </filter-mapping>
b.注解
@WebFilter(filterName = "FirstFilter",urlPatterns = "/test.jsp",dispatcherTypes = DispatcherType.FORWARD)

6.过滤器实现统一编码

package com.lfg.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class EncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=utf-8");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("filter destroy");
    }
}

7.登录控制

(1)login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="loginServlet" method="post">
    账号:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>

(2)LoginServlet.java

package com.lfg.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //默认登录成功
        boolean res = true;
        if (res) {
            HttpSession session = req.getSession();
            session.setAttribute("username",username);
            resp.sendRedirect("index.jsp");
        } else {
            resp.sendRedirect("login.jsp");
        }
    }
}

(3)LoginFilter.java

package com.lfg.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter("/index.jsp")
public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)servletRequest;
        HttpServletResponse resp = (HttpServletResponse)servletResponse;
        HttpSession session = req.getSession();
        Object username = session.getAttribute("username");
        if (username == null) {
            resp.sendRedirect("login.jsp");
        } else {
            filterChain.doFilter(req, resp);
        }
    }

    @Override
    public void destroy() {

    }
}

(4)index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    欢迎您${sessionScope.username}
</body>
</html>

二.监听器Listener

1.概述

(1)概念

  • 监听器就是一个实现了特定接口的Java类,主要用于监听某个对象的状态变化的组件

(2)分类

依据(域对象)ServletContext域HttpSession域ServletRequest域
创建与销毁ServletContextListenerHttpSessionListenerServletRequestListener
属性变化ServletContextAttributeListenerHttpSessionAttributeListenerServletRequestAttributeListener
绑定到HttpSession域中某个对象的状态HttpSessionBindingListener
HttpSessionActivationListener

(3)原理

  • 实现了特定接口的类为监听器,用来监听另一个Java类的方法调用或者属性改变;
  • 当被监听的对象发生了方法调用或者属性改变后,监听器的对应方法就会立即执行

在这里插入图片描述

(4)涉及组成部分

a.事件源
  • 被监听的对象,即:request、session、servletContext三大域对象。
b.监听器
  • 监听事件源对象,事件源对象状态的变化都会触发监听器。
c.注册监听器
  • 将监听器与事件源进行绑定,有两种注册方式:web.xml 或 @WebListener注解
d.时间
  • 域对象发生改变

(5)应用场景

  • 统计网站在线人数
  • 实现任务调度,启动定时程序

(6)创建方法

(1)定义一个普通类实现监听器接口;
(2)重写监听器接口方法;
(3)注册监听器:配置 web.xml 或 @WebListener注解;

2.监听域对象的创建与销毁

2.1.ServletContextListener

(1)概述
  • ServletContextListener监听器,用来监听ServletContext域对象的创建域销毁
  • ServletContext域对象:代表全局唯一对象,每个web工程会产生一个ServletContext对象。
    • 创建:服务器启动时
    • 销毁:服务器关闭时
(2)创建ServletContextListener监听器
a.创建一个普通类
  • 实现ServletContextListener接口
  • 重写内部的两个方法
package com.lfg.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ApplicationListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext init");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext Destroyed");
    }
}
b.注册监听器(web.xml)
    <listener>
        <listener-class>com.lfg.listener.ApplicationListener</listener-class>
    </listener>
c.测试监听器

当tomcat服务器开启时执行被创建的方法contextInitialized,服务器被关闭时执行被销毁的方法contextDestroyed

2.2.HttpSessionListener

(1)概述
  • HttpSessionListener监听器:用来监听HttpSesssion域对象的创建域销毁
  • HttpSesssion域对象:
    • Session创建:Servlet中是request.getSession() ,JSP页面中自带Session
    • Session销毁:非正常关闭服务器,Session过期,session.invalidate()
(2)HttpSessionListenerHttpSessionListener监听器
a.创建一个普通类
  • 实现HttpSessionListener接口
  • 重写内部的两个方法
package com.lfg.listener;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

@WebListener
public class SessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("session create");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("session destroy");
    }
}
b.注册监听器(注解)
@WebListener
c.测试监听器

测试创建:

  • 创建一个jsp页面test.jsp

  • 直接访问index.jsp页面,由于session是jsp的内置对象,意味着在访问index.jsp页面时创建了session对象,因此会触发监听器的创建方法

测试销毁:

  • 执行session.invalidate()方法强制销毁session
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>Title</title>
</head>
<body>
 <%
     session.invalidate();
 %>
</body>
</html>

2.3.ServletRequestListener

(1)概述
  • ServletRequestListener监听器:用来监听ServletRequest域对象的创建和销毁
  • Request创建:请求发起时创建
  • Request销毁:响应结束时销毁
(2)创建ServletRequestListener监听器
a.创建一个普通类
  • 实现ServletRequestListener接口
  • 重写内部的两个方法
package com.lfg.listener;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class RequestListener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("request destroy");
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("request init");
    }
}
b.注册监听器
@WebListener
c.测试监听器

运行JSP文件即可

3.监听域对象属性改变

  • 对域对象添加数据、修改数据、移除数据

(1)分类

监听器描述
ServletContextAttributeListener监听ServletContext中属性的变化
HttpSessionAttributeListener监听HttpSession中属性的变化
ServletRequestAttributeListener监听ServletRequest中属性的变化

(2)不同操作触发的方法

操作描述
attributeAdded监听属性添加-当数据范围对象没有该属性,第一次添加时会自动触发调用执行
attributeRemoved监听属性移除- 从一个数据范围对象删除一个已经存在的属性时会自动触发执行
ttributeReplaced监听属性替换 -当一个数据范围已经存在一个属性,向数据范围添加相同名称属性时自动触发替换方法

(3)以ServletContextAttributeListener为例

a.创建ServletContextAttributeListener监听器
  • 实现ServletContextAttributeListener接口
  • 重写内部的三个方法
package com.lfg.listener;

import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class AttributeListener implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext add attribute");
    }

    @Override
    public void attributeRemoved(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext removed attribute");
    }

    @Override
    public void attributeReplaced(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext replaced attribute");
    }
}
b.注册监听器
WebListener
c.测试监听器
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        application.setAttribute("color","red");
        application.setAttribute("color","green");
        application.removeAttribute("color");
    %>
</body>WebListener
</html>

4.监听绑定到HttpSession域中某个对象状态

(1)概述

  • 监听器是Servlet中比较特殊的监听器, 主要用来监听绑定到Session域中特定对象的状态
  • 绑定:将Java对象绑定到session中。
  • 解除绑定:将Java对象从session中解除绑定

(2)HttpSessionBindingListener

  • 实现HttpSessionBindingListener接口的Java对象,可以感知自身被绑定到Session或者从Session中解除绑定
a.创建HttpSessionBindingListener监听器
  • 创建一个学生类Student实现HttpSessionBindingListener接口
  • 重写内部两个方法
  • 注意:这个监听器不需要注册
package com.lfg.entity;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

public class Student implements HttpSessionBindingListener {
 private int id;
 private String name;

 public Student() {
 }

 public Student(int id, String name) {
     this.id = id;
     this.name = name;
 }

 public int getId() {
     return id;
 }

 public void setId(int id) {
     this.id = id;
 }

 public String getName() {
     return name;
 }

 public void setName(String name) {
     this.name = name;
 }

 @Override
 public void valueBound(HttpSessionBindingEvent event) {
     System.out.println("学生对象被绑定到session中了");
 }

 @Override
 public void valueUnbound(HttpSessionBindingEvent event) {
     System.out.println("学生对象被从session中移除了");
 }
}
b.测试
  • 创建一个jsp页面,创建学生对象并分别绑定和移除Session进行测试
<%@ page import="com.lfg.entity.Student" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        Student student = new Student(1,"mary");
        session.setAttribute("stu",student);
        session.removeAttribute("stu");
    %>
</body>
</html>

(3)HttpSessionActivationListener

  • 实现HttpSessionActivationListener接口的Java对象,可以感知从内存被钝化到硬盘,从硬盘活化到内存中
  • 钝化时机:服务器关闭或重启,指定时间内(长时间)不操作服务器。
  • 活化时机:服务器再次开启。
a.创建HttpSessionActivationListener监听器
  • 创建一个老师类实现HttpSessionActivationListener接口
  • 重写内部两个方法
  • 注意:这个监听器不需要注册
package com.lfg.entity;

import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import java.io.Serializable;

public class Teacher implements HttpSessionActivationListener, Serializable {
 private int id;
 private String name;

 public Teacher() {
 }

 public Teacher(int id, String name) {
     this.id = id;
     this.name = name;
 }

 public int getId() {
     return id;
 }

 public void setId(int id) {
     this.id = id;
 }

 public String getName() {
     return name;
 }

 public void setName(String name) {
     this.name = name;
 }

 @Override
 public void sessionWillPassivate(HttpSessionEvent se) {
     System.out.println("数据钝化到磁盘中了");
 }

 @Override
 public void sessionDidActivate(HttpSessionEvent se) {
     System.out.println("数据活化到内存中了");
 }
}
b.配置Tomcat conf中context.xml文件
directory="d:\test"表示自定义钝化文件的存储路径,maxIdleSwap="1"表示超过1分钟未操作服务器会自动钝化。
<Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="d:\test"/>
</Manager>
c. 测试
  • 创建一个test1.jsp页面,向session中保存一个老师对象
<%@ page import="com.etime.lfg.Student" %>
<%@ page import="com.etime.lfg.Teacher" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>Title</title>
</head>
<body>
 <%
     Teacher teacher = new Teacher(1,"mary");
     session.setAttribute("teacher",teacher);
 %>
</body>
</html>
  • 创建一个test2.jsp页面获取活化后session中的数据是否存在
<%@ page import="com.etime.lfg.Teacher" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>Title</title>
</head>
<body>
 <%
     Teacher teacher = (Teacher)session.getAttribute("teacher");
     out.print(teacher.getName());
 %>
</body>
</html>
  • 测试步骤
    • 首先运行test1.jsp页面,向session中存入老师信息
    • 然后关闭服务器或通过设置maxIdleSwap="1"等待1分钟不操作服务器或者关闭服务器, 都会触发钝化方法执行
    • 同时在指定的路径d:\test下会看到一个.session文件,将session中的数据钝化到该文件中

(4)特别注意

  • 实现这两个接口的类不需要有 web.xml 文件或注解中进行注册监听器,都是由Session自主完成的

三.综合案列

1.分析

通过ServletContextListener监听,当Web应用上下文启动时,在ServletContext中添加一个List集合,用来准备存放在线的用户名;然后,可以通过HttpSessionAttributeListener监听器,当用户登录成功,把用户名设置到Session中时,同时将用户名存放到ServletContext中的List列表中;最后通过HttpSessionListener监听,当用户注销会话时,将用户名从应用上下文范围中的List列表中删除。

2.步骤

(1)创建登录页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>Title</title>
</head>
<body>
<form action="loginServlet" method="post">
 账号:<input type="text" name="username"><br>
 密码:<input type="password" name="password"><br>
 <input type="submit" value="登录">
</form>
</body>
</html>

(2)创建用户登录的Servlet

package com.lfg.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     String username = req.getParameter("username");
     String password = req.getParameter("password");
     //默认登录成功
     boolean res = true;
     if (res) {
         HttpSession session = req.getSession();
         session.setAttribute("username",username);
         resp.sendRedirect("index.jsp");
     } else {
         resp.sendRedirect("login.jsp");
     }
 }
}

(3)创建用户退出登录的Servlet

package com.lfg.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/logoutServlet")
public class LogoutServlet extends HttpServlet {
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
         throws ServletException, IOException {
     HttpSession session = req.getSession();
     session.invalidate();
     resp.sendRedirect("login.jsp");
 }
}

(4)创建监听器

package com.lfg.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.*;
import java.util.ArrayList;
import java.util.List;

@WebListener
public class UserListener implements ServletContextListener, HttpSessionAttributeListener, HttpSessionListener {

 ServletContext servletContext = null;

 @Override
 public void contextInitialized(ServletContextEvent sce) {
     //监听ServletContext对象的创建
     //创建集合放入ServletContext对象中
     List<String> list = new ArrayList<>();
     servletContext = sce.getServletContext();
     servletContext.setAttribute("users",list);
 }

 @Override
 public void attributeAdded(HttpSessionBindingEvent se) {
     //监听session中放入数据
     //getName获取当前放入session中数据的key
     String name = se.getName();
     if ("username".equals(name)) {
         //getValue获取当前放入session中数据的value
         String value = (String)se.getValue();
         List<String> list = (List<String>)servletContext.getAttribute("users");
         list.add(value);
         servletContext.setAttribute("users",list);
     }
 }

 @Override
 public void sessionDestroyed(HttpSessionEvent se) {
     //监听session的销毁
     //退出登录时,将登录信息从ServletContext中的list里面移除掉
     HttpSession session = se.getSession();
     String username = (String)session.getAttribute("username");
     List<String> list = (List<String>)servletContext.getAttribute("users");
     list.remove(username);
     servletContext.setAttribute("users",list);
 }
}

(5)创建显示在线用户页面index.jsp

<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>Title</title>
</head>
<body>
 欢迎您${sessionScope.username}<a href="logoutServlet">退出登录</a><br>
 当前登录的用户有:
 <%
     List<String> users = (List<String>)application.getAttribute("users");
     for (String user:users) {
         out.print(user+"<br>");
     }
 %>
</body>
</html>

文章来源:https://blog.csdn.net/weixin_53903929/article/details/135218357
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。