Servlet中Listener监听器工作原理和应用详解

1. Listener过滤器原理

1.1 Listener 基本信息

概念:监听器就是一个实现了特定接口的Java类。
分类:

  • 一类监听器:监听域对象的创建、销毁
  • 二类监听器:监听域对象中的属性变更(属性设置、属性替换、属性移除)
  • 三类监听器:监听域对象中的java对象的绑定

Servlet监听器:
事件源:request、session、servletContext三大域对象
监听器:Servlet对象(三种监听器)
绑定:web.xml配置 或 @WebListener注解
事件:域对象发生改变

1.2 Listener 工作原理

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

1.3 Listener 基本使用

一类接口:
ServletContextListener 监听ServletContext域对象的创建、销毁

// 服务器启动,ServletContext域对象创建,该监听器方法则执行
public void contextInitialized(ServletContextEvent servletContextEvent)
// 服务器关闭,ServletContext域对象销毁,该监听器方法则执行
public void contextDestroyed(ServletContextEvent servletContextEvent)

HttpSessionListener 监听HttpSession域对象的创建、销毁

// 服务器第一次调用getSession方法时,该监听器方法被执行
public void sessionCreated(HttpSessionEvent httpSessionEvent)
// session过期/调用了invalidate方法销毁session时,该监听器方法被执行
public void sessionDestroyed(HttpSessionEvent httpSessionEvent)

ServletRequestListener 监听ServletRequest域对象的创建、销毁

// 客户端向服务器发送了一个请求,服务器就会为该请求创建一个request对象,该监听器方法就被执行
public void requestInitialized(ServletRequestEvent servletRequestEvent)
// 当服务器为这次请求做出了响应后,将request对象销毁,该监听器方法就被执行
public void requestDestroyed(ServletRequestEvent servletRequestEvent)

二类接口:
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener

// 监听ServletContext域对象中属性的【添加】
void attributeAdded(ServletContextAttributeEvent var1);
// 监听ServletContext域对象中属性的【替换】
void attributeReplaced(ServletContextAttributeEvent var1);
// 监听ServletContext域对象中属性的【移除】
void attributeRemoved(ServletContextAttributeEvent var1);

三类接口:
HttpSessionBindingListener
监听session域对象中的java对象的状态(绑定和解绑)
绑定:将java对象存储到session域对象
解绑:将java对象从session域对象移除

  • 该监听器不需要在web.xml中配置
/**
 * 事件源:Java对象
 * 监听器:HttpSessionBindingListener
 * 绑定:java对象实现监听器接口
 * 事件:java对象在Session中的状态发生改变
 */
public class User implements HttpSessionBindingListener {
    private int id;
    private String username;
    private String password;

    /*构造、get/set、toString*/

    @Override
    public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("HttpSession 与 User 绑定");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("HttpSession 与 User 解绑");
    }
}

1.4 Listener 开发步骤

① 定义类实现监听器接口
② 重写方法
③ 配置 web.xml

<listener>
    <listener-class>Listener的全限定名</listener-class>
</listener>

1.5 Listener 使用示例

/**
 * 事件源:ServletContext
 * 监听器:TestServletContextListener
 * 绑定:web.xml配置
 * 事件:ServletContext对象的创建、销毁
 */
public class TestServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // 监听初始化
        System.out.println("ServletContext 初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        // 监听销毁
        System.out.println("ServletContext 销毁");
    }
}

2. Listener 过滤器应用

2.1 案例:Listener 过滤器实现统计在线人数(流程图+核心逻辑)

流程图:
在这里插入图片描述

核心逻辑:
login.html

<form action="/demo/login" method="post">
    账户:<input type="text" name="username" id=""> <br>
    密码:<input type="password" name="password" id=""> <br>
    <input type="submit" value="登陆">
</form>

User.java

/**
 * 事件源:Java对象
 * 监听器:HttpSessionBindingListener
 * 绑定:java对象实现监听器接口
 * 事件:java对象在Session中的状态发生改变
 */
public class User implements HttpSessionBindingListener {
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("HttpSession 与 User 绑定");
        // 有用户登陆成功
        // 判断是否是第一个登陆的人
        ServletContext servletContext = event.getSession().getServletContext();
        Integer count = (Integer) servletContext.getAttribute("count");
        // 第一个登陆为1,非第一个则++
        count = null == count ? 1 : (count += 1);
        servletContext.setAttribute("count", count);
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("HttpSession 与 User 解绑");
        // 有用户注销登陆
        ServletContext servletContext = event.getSession().getServletContext();
        Integer count = (Integer) servletContext.getAttribute("count");
        // count--是因为在同浏览器下重复登陆时session.setAttribute(name, value)
        // 每次会覆盖value值进而触发监听器valueBound()的count++
        count--;
        servletContext.setAttribute("count", count);
    }

    private int id;
    private String username;
    private String password;

    public User() {
    }

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

LoginServlet.java

@WebServlet(name = "LoginServlet", urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("root".equals(username) && "1234".equals(password)) {
            // 登陆成功,修改登陆状态,转发到showIndex页
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            request.getSession().setAttribute("existUser", user);
            // 转发会导致每次刷新页面都会重新登陆,然后被统计新新用户中
            //request.getRequestDispatcher("/showIndex").forward(request, response);
            response.sendRedirect("/demo/showIndex");
        } else {
            // 登陆失败,转发到login.html
            request.getRequestDispatcher("/demo/login.html").forward(request, response);
        }
    }

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

LogoutServlet.java

@WebServlet(name = "LogoutServlet", urlPatterns = "/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 注销登陆:将existUser从session域中移除 或 销毁session
        //request.getSession().removeAttribute("existUser");
        request.getSession().invalidate();
        // 注销成功
        request.getRequestDispatcher("/showIndex").forward(request, response);
    }

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

ShowIndexServlet.java

@WebServlet(name = "ShowIndexServlet", urlPatterns = "/showIndex")
public class ShowIndexServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        User existUser = (User) request.getSession().getAttribute("existUser");
        StringBuffer responseBody = new StringBuffer();
        if (null == existUser) {
            // 不在登陆状态
            responseBody.append("您还没有登陆,<a href='/demo/login.html'>请登录</a>");
        } else {
            // 在登陆状态
            responseBody.append("欢迎回来,").append(existUser.getUsername()).append("  <a href='/demo/logout'>注销</a>");
        }

        // 获取在线人数
        ServletContext servletContext = getServletContext();
        Integer count = (Integer) servletContext.getAttribute("count");
        System.out.println("在线人数:" + count);
        if (null == count) {
            // 没有人登陆时,0人
            count = 0;
        }
        responseBody.append("<br>在线人数为:").append(count).append("人");

        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write(responseBody.toString());
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
发布了327 篇原创文章 · 获赞 312 · 访问量 67万+

猜你喜欢

转载自blog.csdn.net/sinat_36184075/article/details/105718100
今日推荐