1. 程式人生 > >Listener監聽器筆記1

Listener監聽器筆記1

Language 項目 -- lin lean sessionid next 示例 elong

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,可以看到如下圖的效果:

技術分享圖片

Listener監聽器筆記1