Listener監聽器筆記1

来源:https://www.cnblogs.com/eleven258/archive/2018/01/12/8277523.html
-Advertisement-
Play Games

1.常用的Web事件監聽器介面: 1.ServletContextListener:用於監聽Web應用的啟動和關閉。 2.ServletContextAttributeListener:用於監聽ServletContext(application)範圍內屬性的改變。 3.ServletRequest ...


1.常用的Web事件監聽器介面:

    1.ServletContextListener:用於監聽Web應用的啟動和關閉。

    2.ServletContextAttributeListener:用於監聽ServletContext(application)範圍內屬性的改變。

    3.ServletRequestListener:用於監聽用戶的請求。 

    4.ServletRequestAttributeListener:用於監聽ServletRequest範圍(request)內屬性的改變。

    5.HttpSessionListener:用於監聽用戶session的開始和結束。

    6.HttpSessionAttributeListener:用於監聽HttpSession範圍(session)內屬性的改變。


2.配置Listener
  1.使用@WebListener修飾Listener實現類即可;或者在web.xml中使用<listener.../>元素進行配置。

3.使用HttpSessionListener示例:
  監聽系統的線上用戶:實現HttpSessionListener介面的監聽器,可以監聽每個用戶會話的開始和斷開,因此可以通過該監聽器監聽系統的線上用戶

  後臺監聽器代碼:

/**
 * Description:監聽線上用戶
 * Author: Eleven
 * Date: 2018/1/8 11:17
 */
@WebListener
public class OnlineListener implements HttpSessionListener{

    //當用戶與伺服器之間開始session的時候觸發該方法
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {

        HttpSession session = httpSessionEvent.getSession();
        //設置session有效時間為60秒
        session.setMaxInactiveInterval(60);
        System.out.println("創建"+session.getId()+",當前時間:"+System.currentTimeMillis());
        ServletContext application = session.getServletContext();
        //如果是一次新的會話
        if(session.isNew()){
            //獲取session中的用戶
            String user = (String) session.getAttribute("user");
            user = (user == null) ? "游客":user;

            Map<String,String> online = (Map<String, String>) application.getAttribute("online");
            if(online == null){
                online = new Hashtable<String,String>();
            }
            //將用戶線上信息放入map中
            online.put(session.getId(),user);
            application.setAttribute("online",online);
        }
    }

    //當用戶與伺服器之間session斷開時觸發該方法
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {

        System.out.println("用戶與伺服器之間session結束");

        HttpSession session = httpSessionEvent.getSession();
        System.out.println("銷毀"+session.getId()+",當前時間:"+System.currentTimeMillis());

        ServletContext application = session.getServletContext();

        Map<String,String> online = (Map<String, String>) application.getAttribute("online");
        if(online != null){
            //刪除該用戶線上信息
            online.remove(session.getId());
        }

        application.setAttribute("online",online);

    }
}

 頁面jsp

<%@ page import="java.util.Map" %><%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2018/1/4
  Time: 16:46
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用戶線上信息</title>
</head>
<body>

    線上用戶:
    <table width="400" border="1">
    <%
        //獲取application中的map
        Map<String,String> online = (Map<String, String>) application.getAttribute("online");
        for(String sessionId:online.keySet()){
    %>
        <tr>
            <td><%=sessionId%></td>
            <td><%=online.get(sessionId)%></td>
        </tr>
    <%
        }
    %>
    </table>
</body>
</html>

  接下來,在本機啟動兩個不同的瀏覽器來模擬三個用戶訪問該項目,訪問online.jsp頁面會看到有三個游客線上,如下圖:

  至於為什麼只用一個瀏覽器訪問該項目的不同資源,卻還是只有一個session,而打開不同的瀏覽器,就會創建session?這個問題,就留著之後在session中去解決哦~~

  雖然通過實現HttpSessionListener介面可以做到監聽線上用戶信息,但是這樣比較粗糙,只能監聽到多少人線上,如果要監聽每個用戶停留在哪個頁面,用戶訪問的ip等信息,則應該使用HttpServletRequest來實現。

4.使用ServletRequestListener+ServletContextListener示例:

  具體的做法思路:

  寫一個類實現ServletRequestListener,這個監聽器就負責監聽用戶的每次請求,當用戶請求到達時,將用戶請求的sessionId,用戶名,用戶IP,正在訪問的資源,訪問時間記錄下來。

  寫一個類實現ServletContextListener,隨web應用的啟動而啟動,然後在程式里另開一條線程,這個線程每隔一段時間就去檢查每條線上的記錄,看每條記錄的訪問時間與當前時間的差是否超過了一個指定值,如果超過了,就將這條線上記錄刪掉。

  監聽用戶請求的代碼:

/**
 * Description:監聽用戶的每次請求
 * Author: Eleven
 * Date: 2018/1/8 15:33
 */
@WebListener
public class RequestListener implements ServletRequestListener{

    //當用戶請求到達,被初始化時觸發該方法
    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {

        HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
        //session會話被創建
        HttpSession session = request.getSession();
        String sessionId = session.getId();
        //獲取訪問的ip和訪問的頁面
        String ip = request.getRemoteAddr();

        String page = request.getRequestURI();
        System.out.println("當前會話:"+sessionId+",訪問ip:"+ip+",訪問頁面:"+page);
        //獲取用戶
        String user = (String) session.getAttribute("user");
        //未登錄,設為游客
        user = (user == null) ? "游客":user;

        //從資料庫中查詢該sessionId所對應的用戶信息
        try {
            DbDao dd = new DbDao("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/test","root","123456");

            ResultSet rs =  dd.query2("select * from online where sessionId = '"+sessionId+"' ");
            //存在當前sessionId的用戶信息,則表明是舊的會話
            if(rs.next()){
                //修改訪問的page以及當前的時間
                rs.updateString(4,page);
                rs.updateLong(5,System.currentTimeMillis());
                rs.updateRow();
                rs.close();
            }else{
                //不存在,則存進資料庫
                dd.insert("insert into online values(?,?,?,?,?)",sessionId,user,ip,page,System.currentTimeMillis());
            }

            rs.close();


        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //當用戶請求結束,被銷毀時觸發該方法
    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
        String page = request.getRequestURI();
        System.out.println("訪問結束"+page);
    }
}

  隨web應用而啟動,用於檢測每條線上記錄的監聽器代碼:

/**
 * Description: 隨web項目啟動而啟動,然後另開一條線程去判斷用戶是否已經離線
 * Author: Eleven
 * Date: 2018/1/12 16:45
 */
@WebListener
public class TimeListener implements ServletContextListener{

    //超過該時間沒有訪問本站,即認為已經離線
    public final int MAX_MILLIS = 1000*10*2;//2分鐘

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        //每1分鐘檢查一次
        new Timer(1000*60*1,new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    //從資料庫中查詢出所有的用戶信息
                    DbDao dd = new DbDao("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/test","root","123456");
                    ResultSet rs = dd.query("select * from online ");
                    StringBuffer sb = new StringBuffer();
                    sb.append("(");
                    while(rs.next()){
                        if(System.currentTimeMillis()-rs.getLong(5)>MAX_MILLIS){
                            //超過了10分鐘
                            sb.append("'");
                            sb.append(rs.getString(1));
                            sb.append("',");
                        }
                    }
                    System.out.println("aa"+sb.toString());
                    //如果有需要刪除的記錄
                    if(sb.length()>1){
                        sb.setLength(sb.length()-1);
                        sb.append(")");
                        System.out.println(sb.toString());
                        dd.modify("delete from online where sessionId in " +sb.toString());
                        //刪除超時的記錄
                    }
                    System.out.println("需要移除的"+sb.toString());
                    rs.close();
                    dd.closeConn();

                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }).start();
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}

  涉及到的資料庫的操作的DbDao的代碼:

/**
 * Description:資料庫操作
 * Author: Eleven
 * Date: 2018/1/6 9:27
 */
public class DbDao {
    private Connection conn;
    private String driver;
    private String url;
    private String name;
    private String psw;

    public DbDao() {
    }

    public DbDao( String driver, String url, String name, String psw) {
        this.driver = driver;
        this.url = url;
        this.name = name;
        this.psw = psw;
    }

    //獲取資料庫連接
    public Connection getConnection() throws Exception{

        if(conn == null){
            //註冊驅動
            Class.forName(driver);
            //獲取連接
            conn = DriverManager.getConnection(url,name,psw);
        }
        return conn;
    }
    

    //查詢1  動態查詢
    public ResultSet query(String sql,Object... args) throws Exception{

        //創建Statement
        PreparedStatement pstmt = getConnection().prepareStatement(sql);
        //設置參數
        for(int i=0;i<args.length;i++){
             pstmt.setObject(i+1,args[i]);
        }
        return pstmt.executeQuery();
    }

    //查詢2 
    public ResultSet query2(String sql) throws Exception{
        Statement st = getConnection().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);

        return st.executeQuery(sql);
    }



    //插入
    public boolean insert(String sql,Object... args) throws Exception{
        PreparedStatement pstmt = getConnection().prepareStatement(sql);
        for(int i=0;i<args.length;i++){
            pstmt.setObject(i+1,args[i]);
        }

        if(pstmt.executeUpdate() != 1){
            return false;
        }
        return true;
    }

    //修改或刪除
    public void modify(String sql,Object... args) throws Exception{
        PreparedStatement pstmt = getConnection().prepareStatement(sql);
        for(int i=0;i<args.length;i++){
            pstmt.setObject(i+1,args[i]);
        }
        pstmt.executeUpdate();
        pstmt.close();
    }

    //關閉資料庫連接
    public void closeConn() throws Exception{
        if(conn != null && !conn.isClosed()){
            conn.close();
        }
    }

    public Connection getConn() {
        return conn;
    }

    public void setConn(Connection conn) {
        this.conn = conn;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getName() {
        return name;
    }

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

    public String getPsw() {
        return psw;
    }

    public void setPsw(String psw) {
        this.psw = psw;
    }
}

  頁面jsp代碼:

<%@ page import="java.sql.ResultSet" %>
<%@ page import="servlet.DbDao" %><%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2018/1/4
  Time: 16:46
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用戶線上信息</title>
</head>
<body>

    線上用戶:
    <table width="400" border="1">
    <%
        //從資料庫總查詢出所有的記錄
        DbDao dd = new DbDao("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/test","root","123456");
        ResultSet rs = dd.query("select * from online");
        while(rs.next()){
    %>
        <tr>
            <td><%=rs.getString(1)%></td>
            <td><%=rs.getString(2)%></td>
            <td><%=rs.getString(3)%></td>
            <td><%=rs.getString(4)%></td>
        </tr>
    <%
        }
    %>
    </table>
</body>
</html>

  最後打開不同的瀏覽器去訪問該項目的不同頁面,然後再去訪問online2.jsp,可以看到如下圖的效果:

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • (一)返回指針值的函數的一般形式 類型名 * 函數名(參數表列) 如:int *a(int x,int y) 調用a函數返回的指針指向整型變數 (二)指針型函數小例子 例子,輸入一個學生序號,然後輸出該學生的所有成績 註意比較*(pointer+n)和(*pointer+n)的區別*(p+n)是某一 ...
  • 吐槽 這個演算法。。 怎麼說........ 學來也就是裝裝13吧。。。。 長得比EK醜 跑的比EK慢 寫著比EK難 思想 大家先來猜一下這個演算法的思想吧:joy: 看看人家的名字——最高標號預留推進 多麼高端大氣上檔次2333333咳咳 從它的名字中我們可以看出,它的核心思想是—推進,而不是找增廣路 ...
  • 子類繼承了父類的各種屬性,而構造方法則相當於把父類給實例化出來,如果你子類實例化的時候不調用父類的構造方法,相當於子類壓根就沒有父親 ...
  • JAVA工作方式 源程式(myProgram.java) – > 編譯(javac myProgram.java) -> JAVA位元組碼(myProgram.class) ->運行(java myProgram) 指令: 編譯時:javac(compiler) + 文件名 運行時:java +文件名 ...
  • 1月中旬,阿裡云云棲社區 聯合 博文視點 為大家帶來十本技術書籍(機器學習、Java、大數據等)。以下為書籍詳情,文末還有福利哦! 書籍名稱:Oracle資料庫問題解決方案和故障排除手冊 內容簡介 《Oracle資料庫問題解決方案和故障排除手冊》提供了全面、實用的建議,以保證在複雜的生產環境中,能可 ...
  • 上面是繼承Thread的方法 這種方法較為簡單,只要繼承後覆寫run方法即可,缺點是已經繼承別的類就不能在繼承了,有局限性。對單一對象中成員進行操作的多線程需要靜態static關鍵字 下麵是實現implements Runnable方法 鎖可以在方法上,也可以用同步代碼塊,同步代碼塊較好,可以局部鎖 ...
  • Infi-chu: http://www.cnblogs.com/Infi-chu/ NoSQL(NoSQL=Not Only SQL),中文意思是非關係型資料庫。 隨著互聯網Web2.0網站的興起,傳統的關係型資料庫在應付web2.0網站,特別是超大規模和高併發的SNS類型的web2.0純動態網站 ...
  • 上傳文件 Browse for a file to upload: 1、使用webdriver的send_keys方法上傳文件 #!usr/bin/env python #-*- coding:utf-8 -*- """ @author: sleeping_cat... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...