Listener

概述

监听器是 Servlet 中一种特殊的类,它们能帮助开发者监听 Web 中的特定事件,比如 ServletContext,HttpSession,ServletRequest 的创建和销毁;属性键值对的创建、销毁和修改等。可以在某些动作前后增加处理和操作。

作用

1、统计在线人数,利用 HttpSessionLisener 或 HttpSessionAttributeListener

2、加载初始化信息:利用 ServletContextListener

3、统计网站访问量

4、实现访问监控

常见 API【了解】

// 监听上下文对象的初始化和销毁
interface ServletContextListener

// 通知上下文对象正在被初始化
void contextInitialized(ServletContextEvent sce); 

// 通知上下文对象即将被关闭
void contextDestroyed(ServletContextEvent sce);

// 监听上下文对象对属性的增删改操作
interface ServletContextAttributeListener
    
// 通知添加了属性
void attributeAdded(ServletContextAttributeEvent var1);

// 通知移除了属性
void attributeRemoved(ServletContextAttributeEvent var1);

// 通知修改了属性
void attributeReplaced(ServletContextAttributeEvent var1);

// 监听Session对象的创建和销毁
interface HttpSessionListener
  
// session已创建
void sessionCreated(HttpSessionEvent var1);

// session已销毁
void sessionDestroyed(HttpSessionEvent var1);

// 监听session的属性增删改操作
interface HttpSessionAttributeListener
    
// 通知session中添加了属性
void attributeAdded(HttpSessionBindingEvent var1);

// 通知session中移除了属性
void attributeRemoved(HttpSessionBindingEvent var1);

// 通知session中修改了属性
void attributeReplaced(HttpSessionBindingEvent var1);

// 监听请求的初始化和销毁
interface ServletRequestListener
    
// 通知请求对象被销毁
void requestDestroyed(ServletRequestEvent var1);

// 通知请求对象正在初始化
void requestInitialized(ServletRequestEvent var1);

// 监听请求的属性的增删改操作
interface ServletRequestAttributeListener

// 通知请求对象添加了属性
void attributeAdded(ServletRequestAttributeEvent var1);

// 通知请求对象移除了属性
void attributeRemoved(ServletRequestAttributeEvent var1);

// 通知请求对象修改了属性
void attributeReplaced(ServletRequestAttributeEvent var1);

两种配置方式

注解

步骤

1、实现监听器接口
2、重写抽象方法
3、声明@WebListener注解

案例代码

/**
 * 通过注解配置监听器
 */
// 声明监听器注解
@WebListener
public class CreateListener implements ServletContextListener {
    // 重写contextInitialized方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("Servlet be initialized!!");
    }

    // 重写contextDestroyed方法
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("Servlet be destroyed!!");
    }
}

通过 web.xml 配置文件

监听器

/**
 * 通过web.xml方式配置监听器
 */
public class XMLListener implements HttpSessionListener {
    // 重写sessionCreated方法
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("Session be created: " + httpSessionEvent.getSession().getId());
    }
    
    // 重写sessionDestroyed方法
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("Session be destroyed!!");
    }
}

Servlet

@WebServlet("/xml")
public class XMLServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession(true);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

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">

    <!--声明监听器所在的位置-->
    <listener>
        <listener-class>com.fc.listener.createByXml.XMLListener</listener-class>
    </listener>
</web-app>

获取当前的在线人数【重点】

登录页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<form action="login" method="post">
    <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;
                <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: deeppink"><a href="logout">退出登录</a></h1>
    <h1 align="center" style="color: aqua">在线人数:${sessionCount}</h1>
</body>
</html>

登录业务逻辑

/**
 * 登录操作,并且注册Session信息
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置请求编码集
        req.setCharacterEncoding("utf-8");

        // 从前端获取参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        // 判断数据合法性
        if ("张三".equals(username) && "123456".equals(password)) {
            // 登录成功,创建session
            HttpSession session = req.getSession(true);

            // 设置过期时间
            session.setMaxInactiveInterval(60 * 60);

            // 设置登录到的用户名为参数
            session.setAttribute("username", username);

            // 创建Cookie并存入JSESSIONID
            Cookie cookie = new Cookie("JSESSIONID", session.getId());

            // 设置Cookie过期时间
            cookie.setMaxAge(60 * 60);

            // 通过响应对象将Cookie发送到浏览器
            resp.addCookie(cookie);

            // 重定向至主页
            resp.sendRedirect("index.jsp");
        } else {
            // 登录失败,返回登录页重新登录
            resp.sendRedirect("login.html");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

退出登录业务逻辑

/**
 * 退出登录,销毁Session
 */
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取当前已存在的session,注意要用false
        HttpSession session = req.getSession(false);

        // 判断session是否为空
        if (session != null) {

            // 移除对应键值对
            session.removeAttribute("username");

            // 销毁session
            session.invalidate();
        }

        // 通过 JSESSIONID 获取 cookie 对象
        Cookie cookie = new Cookie("JSESSIONID", "");

        // 设置 cookie 的有效期为 0
        cookie.setMaxAge(0);

        // 发送Cookie数据至浏览器
        resp.addCookie(cookie);

        resp.sendRedirect("index.jsp");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

【注意】这里需要把 Session 中的属性键值对进行移除,否则监听器中无法获取对应信息

监听器

// 声明监听器注解
@WebListener
public class OnlineListener implements HttpSessionAttributeListener {
    // 当前session的数量
    private static int count = 0;

    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        // 当session中添加了属性键值对时,说明有人登录成功,当前在线人数+1
        count++;

        // 将当前session的总数存入上下文对象中
        httpSessionBindingEvent.getSession().getServletContext().setAttribute("sessionCount", count);
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        // 当退出登录时说明当前在线人数-1,session的数量-1
        count--;

        // 将当前session的总数存入上下文对象中
        httpSessionBindingEvent.getSession().getServletContext().setAttribute("sessionCount", count);
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {

    }
}

【注意】如果使用 HttpSessionListener 会造成人未登录但在线人数却增加的 bug

最后修改:2021 年 01 月 24 日 12 : 03 PM
如果觉得此文章有用,请随意打赏