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