【Listener教科書】科普JavaWeb中的多種監聽器及用法(知識總結)

一、瞭解監聽器

1.1 什麼是監聽器

監聽器就是一個實現了特定接口的Java類。這個Java類用來監聽另一個Java類的方法調用或者屬性改變。當被監聽的對象的發生上述的事件後。監聽器某個方法就會立即執行。

1.1.1 監聽器的組件

監聽器可以大致分爲四個組件(方便理解)

  • 事件源:事件發生的源頭
  • 監聽器:監聽事件發生
  • 綁定:將監聽器綁定到事件源
  • 事件:能夠觸發監聽器的事

1.2 什麼是Servlet監聽器

在Servlet的規範中定義了多種類型的監聽器。監聽器用來分別監聽 ServletContext、HttpSession、ServletRequest三個域對象的

1.2.1 Servlet監聽器的組件

Servlet監聽器的組件大致分爲四個組件

  • 事件源:request域對象、session域對象、ServletContext域對象
  • 監聽器:Servlet三種監聽器
  • 綁定:配置web.xml
  • 事件:域對象發生改變

1.3 Servlet監聽器的分類

Servlet規範中提供了8個監聽器

按功能進行劃分將其分成三類,如下:

  • 一類:監聽三個域對象的創建和銷燬的監聽器
  • 二類:監聽三個域對象的屬性變更的監聽器。(屬性添加、屬性移除、屬性替換)
  • 三類:監聽HttpSession對象中的JavaBean的狀態的改變。(綁定、解除綁定、鈍化、活化)

二、監聽器的開發步驟

  • 自定義類實現一類監聽器
  • 重寫監聽器中的方法
  • 配置xml配置文件或註解配置
/**
 * 監聽器開發步驟
 */
public class FirstListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        /**
         * 監聽ServletContext域的初始化,隨着服務器的啓動
         */
        System.out.println("ServletContext初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        //監聽ServletContext域的銷燬,隨着服務器的關閉
        System.out.println("ServletContext銷燬");
    }
}

三、監聽器的配置方式

3.1 xml配置

	<listener>
        <listener-class>com.mylifes1110.java.listener.FirstListener</listener-class>
    </listener>

3.2 註解配置

@WebListener,加了該註解默認配置了監聽器

package com.mylifes1110.java.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * 監聽器開發步驟
 */
@WebListener
public class FirstListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        /**
         * 監聽ServletContext域的初始化,隨着服務器的啓動
         */
        System.out.println("ServletContext初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        /**
         * 監聽ServletContext域的銷燬,隨着服務器的關閉
         */
        System.out.println("ServletContext銷燬");
    }
}

四、一類監聽器

監聽三個域對象(ServletContext、Session、Request)的創建與銷燬

4.1 監聽ServletContext域對象

  • 實現ServletContextListener接口並覆蓋方法
    • 監聽服務器啓動的時候創建ServletContext對象時
    • 監聽服務器關閉的時候ServletContext對象被銷燬掉時
package com.mylifes1110.java.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * 監聽ServletContext
 */
@WebListener
public class TestServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        /**
         * 監聽ServletContext域的初始化,隨着服務器的啓動
         */
        System.out.println("ServletContext初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        /**
         * 監聽ServletContext域的銷燬,隨着服務器的關閉
         */
        System.out.println("ServletContext銷燬");
    }
}

4.2 監聽Session域對象

  • 實現HttpSessionListener接口並覆蓋方法
    • 監聽服務器端第一次調用getSession方法時
    • 監聽session過期或調用了invalidate方法
package com.mylifes1110.java.listener;

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

/**
 * 監聽HttpSession
 */
@WebListener
public class TestHttpSessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("Session創建");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("Session銷燬");
    }
}

Servlet測試

package com.mylifes1110.java.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(name = "TestSessionServlet", value = "/tss")
public class TestSessionServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //創建Session對象
        HttpSession session = request.getSession();
        System.out.println(session.getId());
        //銷燬Session對象
        session.invalidate();
    }

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

4.3 監聽Request域對象

  • 實現ServletRequestListener接口並覆蓋方法
    • 監聽客戶的向服務器發送了一次請求而創建這一個request對象
    • 監聽當服務器爲這次請求作出了響應之後的request對象銷燬
package com.mylifes1110.java.listener;

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

/**
 * 監聽ServletRequest
 */
@WebListener
public class TestServletRequestListener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        System.out.println("Request對象創建");
    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        System.out.println("Request對象銷燬");
    }
}

Servlet測試

package com.mylifes1110.java.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 java.io.IOException;

@WebServlet(name = "TestRequestServlet", value = "/trs")
public class TestRequestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
    }

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

五、二類監聽器

監聽三個域對象的屬性變更的監聽器(屬性添加、屬性移除、屬性替換)

5.1 監聽ServletContext屬性

  • 實現ServletContextAttributeListener接口並覆蓋方法
    • 監聽ServletContext域中的屬性變更
package com.mylifes1110.java.listener;

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

/**
 * 監聽ServletContext域中的屬性變更
 */
@WebListener
public class TestServletContextAttributeListener implements ServletContextAttributeListener {
    /**
     * 監聽ServletContext域對象中屬性的添加
     */
    @Override
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("ServletContext Added");
    }

    /**
     * 監聽ServletContext域對象中屬性的移除
     */
    @Override
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("ServletContext Removed");
    }

    /**
     * 監聽ServletContext域對象中屬性的替換
     */
    @Override
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("ServletContext Replaced");
    }
}

Servlet測試

package com.mylifes1110.java.servlet;

import javax.servlet.ServletContext;
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 java.io.IOException;

@WebServlet(name = "TestServletContextAttributeServlet", value = "/tscas")
public class TestServletContextAttributeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        //添加
        servletContext.setAttribute("name", "ziph");
        //替換
        servletContext.setAttribute("name", "join");
        //移除
        servletContext.removeAttribute("name");
    }

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

5.2 監聽Session屬性

  • 實現HttpSessionAttributeListener接口並覆蓋方法
    • 監聽HttpSession域中的屬性變更
package com.mylifes1110.java.listener;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

/**
 * 監聽Session域中的屬性變更
 */
@WebListener
public class TestHttpSessionAttributeListener implements HttpSessionAttributeListener {
    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("Session Added");
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("Session Removed");
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("Session Replaced");
    }
}

Servlet測試

package com.mylifes1110.java.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;

/**
 * 注意:銷燬和移除都能觸發監聽器的attributeRemoved方法
 */
@WebServlet(name = "TestSessionAttributeServlet", value = "/tsas")
public class TestSessionAttributeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        StringBuffer buffer = new StringBuffer();
        buffer.append("ziph");
        //添加
        session.setAttribute("name", buffer);
        buffer.append(" is very good!");
        //替換
        session.setAttribute("name", buffer);
        //移除
        session.removeAttribute("name");
        //銷燬
        session.invalidate();
    }

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

5.3 監聽Request屬性

  • 實現ServletRequestAttributeListener接口並覆蓋方法
    • 監聽ServletRequest中的屬性變更

事件分析:

  • 事件源:JavaBean對象
  • 監聽器:HttpSessionBingingListener監聽器
  • 綁定:JavaBean對象實現HttpSessionBingbingListener接口(所以纔不需要配置xml)
  • 時間:JavaBean對象在Session中狀態發生改變
package com.mylifes1110.java.listener;

import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.annotation.WebListener;

/**
 * 監聽Request域中的屬性變更
 */
@WebListener
public class TestServletRequestAttributeListener implements ServletRequestAttributeListener {

    @Override
    public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("Request Added");
    }

    @Override
    public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("Request Removed");
    }

    @Override
    public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("Request Replaced");
    }
}

Servlet測試

package com.mylifes1110.java.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 java.io.IOException;

@WebServlet(name = "TestServletRequestAttributeServlet", value = "/tsras")
public class TestServletRequestAttributeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        StringBuffer buffer = new StringBuffer();
        buffer.append("ziph");
        //添加
        request.setAttribute("name", buffer);
        buffer.append("marry");
        //替換
        request.setAttribute("name", buffer);
        //移除
        request.removeAttribute("name");
    }

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

六、三類監聽器

package com.mylifes1110.java.bean;

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

/**
 * 三類監聽器HttpSessionBingingListener
 */
public class User implements HttpSessionBindingListener {
    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;
    }


    @Override
    public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("User對象綁定");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("User對象解綁");
    }

    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 + '\'' +
                '}';
    }
}

Servlet測試

package com.mylifes1110.java.servlet;

import com.mylifes1110.java.bean.User;

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(name = "TestHttpSessionBingingListenerServlet", value = "/thsbls")
public class TestHttpSessionBingingListenerServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        //綁定
        session.setAttribute("user", new User(1, "ziph", "123456"));
        //解綁
        session.removeAttribute("user");
        //銷燬也是解綁的一種
//        session.invalidate();
    }

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

七、瀏覽器記錄登錄認數綜合案例

當一個用戶登錄成功後,將這個用戶記錄到在線人數中;同時,如果這個用戶註銷登錄就從在線 人數中移除。遵循網頁站點瀏覽器訪問原則。

原理: 使用三類監聽器來監聽User實體類對象在Session中的綁定域解綁來控制在線人數

  • 綁定:在線認數+1(登錄)
  • 解綁:在線人數-1(註銷)
  • 注意: 在登錄成功後我們需要使用重定向來跳轉登錄頁面。因爲我們使用轉發的話,在登錄後重新發起請求則請求轉發內部處理會重新登錄一次,所以會增加在線人數(+1)。爲了避免此問題,在跳轉登錄頁面的時候我們使用重定向技術!
login.html登錄頁面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陸頁面</title>
</head>
<body>
<form action="/firstlistener/login" method="post">
    賬號:<input type="text" name="username"><br>
    密碼:<input type="password" name="password"><br>
    <button type="submit">登錄</button>
</form>
</body>
</html>
EncodingFilter過濾器解決亂碼問題的xml配置信息
	<filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>com.mylifes1110.java.onlinenumbersdemo.filter.EncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
EncodingFilter過濾器解決亂碼問題代碼
package com.mylifes1110.java.onlinenumbersdemo.filter;

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

/**
 * 通用Filter解決亂碼問題
 */
public class EncodingFilter implements Filter {
    private String encoding = null;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        encoding = filterConfig.getInitParameter("encoding");
    }

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

    @Override
    public void destroy() {

    }
}
User實體類對象(三類監聽器監聽,控制在線人數)
package com.mylifes1110.java.onlinenumbersdemo.bean;

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

/**
 * 監聽器監聽JavaBean對象
 */
public class User implements HttpSessionBindingListener {
    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;
    }


    /**
     * 處理統計登錄人數
     */
    @Override
    public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
        ServletContext servletContext = httpSessionBindingEvent.getSession().getServletContext();
        Integer count = (Integer) servletContext.getAttribute("count");
        if (count == null) {
            count = 1;
        } else {
            count++;
        }
        servletContext.setAttribute("count", count);
    }

    /**
     * 處理統計註銷人數
     */
    @Override
    public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
        ServletContext servletContext = httpSessionBindingEvent.getSession().getServletContext();
        Integer count = (Integer) servletContext.getAttribute("count");
        count--;
        servletContext.setAttribute("count", count);
    }

    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登錄處理
package com.mylifes1110.java.onlinenumbersdemo.servlet;

import com.mylifes1110.java.onlinenumbersdemo.bean.User;

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 java.io.IOException;

/**
 * 登錄處理
 */
@WebServlet(name = "LoginServlet", value = "/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("ziph".equals(username) && "123456".equals(password)) {
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            request.getSession().setAttribute("user", user);
            response.sendRedirect("/firstlistener/show");
        } else {
            request.getRequestDispatcher("/login.html").forward(request, response);
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
ShowServlet響應展示頁面
package com.mylifes1110.java.onlinenumbersdemo.servlet;

import com.mylifes1110.java.onlinenumbersdemo.bean.User;

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 java.io.IOException;

/**
 * 展示頁面
 */
@WebServlet(name = "ShowServlet", value = "/show")
public class ShowServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        User user = (User) request.getSession().getAttribute("user");
        StringBuffer buffer = new StringBuffer();
        if (user == null) {
            buffer.append("對不起,您還沒有登錄!  <a href='/firstlistener/login.html'>請登錄</a><br>");

        } else {
            buffer.append("歡迎" + user.getUsername() + "回家!  <a href='/firstlistener/logout'>註銷</a><br>");
        }
        Integer count = (Integer) getServletContext().getAttribute("count");
        if (count == null) {
            buffer.append("在線人數爲:0");
        } else {
            buffer.append("在線人數爲:" + count);
        }
        response.getWriter().println(buffer.toString());
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
LogoutServlet註銷功能
package com.mylifes1110.java.onlinenumbersdemo.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 java.io.IOException;

/**
 * 註銷功能
 */
@WebServlet(name = "LogoutServlet", value = "/logout")
public class LogoutServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getSession().removeAttribute("user");
        request.getRequestDispatcher("/show").forward(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
LogoutServlet註銷功能
package com.mylifes1110.java.onlinenumbersdemo.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 java.io.IOException;

/**
 * 註銷功能
 */
@WebServlet(name = "LogoutServlet", value = "/logout")
public class LogoutServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getSession().removeAttribute("user");
        request.getRequestDispatcher("/show").forward(request, response);
    }

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

還請客官多多點贊支持!👍持續分享中…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章