【Listener】利用監聽器Listener以MVC的思想通過JSP+Servlet+JDBC完成線上使用者列表的輸出

來源:互聯網
上載者:User

標籤:listener   監聽器   servlet   容器   線上使用者   

Servlet,監聽器Listener與《【Filter】攔截器Filter》(點擊開啟連結)是JSP的三大核心組件,實際上監聽器Listener相當於資料庫裡面的觸發器,一旦使用者觸發了某種行為,則可以通過相關的Java檔案執行相應的程式。使用者在瀏覽網頁的過程中,主要有開啟瀏覽器的動作,對應的行為是Session的建立,可是,使用者關閉瀏覽器的動作,並不是對應Session的消失,因此對於Session的消失我們意義不大;訪問任意網頁的動作,對應的行為是request請求的建立,request的消失對於我們程式猿來說沒有任何意義;伺服器的自身啟動與關閉。對應的行為是Application的建立與消失。

利用監聽器Listener配合資料庫,可以完成線上使用者列表的統計。


一、基本目標

輸出一個線上使用者列表,設定使用者訪問我們的網站127.0.0.1:8080/Listener則認為其線上,其實就是localhost:8080/Listener,但localhost:8080,IP地址則變成了0::0:1一個IP6地址非常難看,所以還是使用127.0.0.1:8080,由於無法監聽使用者是否關閉瀏覽器,因此設定要是使用者5秒內沒有訪問我們網站的任意一個網頁,則認為其已經離線了,只是為了看到實驗效果,應該設定得更長。

如,開兩個瀏覽器,每一個瀏覽器對應一個Session,認為是兩個使用者在訪問我們的網站。其實你利用監聽器,還可以做得複雜點,通過檢查此使用者名稱是否登陸的方式來判斷其是否登陸。正如此前我在《【php】基於Xajax的線上聊天室、直播間》(點擊開啟連結)做過的那樣。


二、基本準備

首先在資料庫中建立一張線上使用者表,如:


這張表沒有主鍵,因為需要多次被insert與delete擦寫,我也不打算通過主鍵來統計曆史線上人數了,免得主鍵太難看,所以不設定主鍵。

由於不設定主鍵,所以不能通過圖形化建表,如果你是通過MySQLQueryBrowser去建表的話,而不是MySQL Command Line Client的話,應該如:


在查詢語句輸入框輸入:

create table onlineTable(  sessionId varchar(45),  ip varchar(45),  timeonline LONG)

建好表之後,在eclipse建立一個網路工程ListenerTest,把上次《【Servlet】根據MVC思想設計使用者登陸、使用者註冊、修改密碼系統》(點擊開啟連結)的Servlet與JDBC的包放到lib,這兩個lib網上一搜一把,同時把dbDAO.java放到ListenerTest的src檔案夾,並在裡面新增一條與插入、修改完全一模一樣的刪除delete方法,最後整個dbDAO.java如下,幾乎就是完全一模一樣的,什麼都沒有改,這就是MVC的優勢,由於我們用到同樣的一個資料庫test,疼一次寫好資料庫增刪改查的類,以後做到多次複用就幸福了。

import java.sql.*;public class dbDAO {private Connection con;// 建構函式,串連資料庫public dbDAO() throws Exception {String dburl = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useOldAliasMetadataBehavior=true";String dbusername = "root";String dbpassword = "root";Class.forName("com.mysql.jdbc.Driver");this.con = DriverManager.getConnection(dburl, dbusername, dbpassword);}// 執行查詢public ResultSet query(String sql, Object... args) throws Exception {PreparedStatement ps = con.prepareStatement(sql);for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}return ps.executeQuery();}// 執行插入public boolean insert(String sql, Object... args) throws Exception {PreparedStatement ps = con.prepareStatement(sql);for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}if (ps.executeUpdate() != 1) {return false;}return true;}// 執行修改public boolean modify(String sql, Object... args) throws Exception {PreparedStatement ps = con.prepareStatement(sql);for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}if (ps.executeUpdate() != 1) {return false;}return true;}// 執行刪除public boolean delete(String sql, Object... args) throws Exception {PreparedStatement ps = con.prepareStatement(sql);for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}if (ps.executeUpdate() != 1) {return false;}return true;}// 解構函式,中斷資料庫的串連protected void finalize() throws Exception {if (!con.isClosed() || con != null) {con.close();}}}

之後配置好web.xml,這樣的片段一般和過濾器一樣放置到最頂端,表示整個網站的行為由根目錄的onlineListener.java監聽,寫上這樣的監聽代碼,之後使用者一旦觸發某種行為,如果在onlineListener.java有相應的代碼,則這些代碼則會被執行:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5"><listener><listener-class>onlineListener</listener-class></listener></web-app>

最後整體的網路結構如:



三、製作過程

1、其實就是寫好一個Listener.java就OK。與《【Filter】攔截器Filter》(點擊開啟連結)中一樣,一旦我們要監聽某一個動作,就必須重寫下這個動作的銷毀與建立實現方法,因為這裡用到了介面,你不寫還真的不行。同時也不要怕一個方法太長記不住,Eclipse for JavaEE會幫你自動產生的。可以被監聽的方法有ServletRequestListener表示使用者訪問任意個網址,每訪問一個網頁則監聽/觸發一次,實際上就是監聽request對象;ServletContextListener伺服器的開始與結束監聽/觸發一次,實際上就是監聽Application對象,通過對Application對象的監聽可以達到《【Servlet】利用load-on-startup創造一條隨伺服器共存亡的線程》(點擊開啟連結)的效果;還有HttpSessionListener,在使用者開啟瀏覽器監聽/觸發一次,實際上監聽Session對象的建立與銷毀,這裡沒有用到。

import java.util.*;import java.sql.*;import javax.servlet.*;import javax.servlet.http.*;public class onlineListener implements ServletRequestListener,ServletContextListener {// request對象的銷毀對我們意義不大@Overridepublic void requestDestroyed(ServletRequestEvent servletRequestEvent) {}// request對象的建立相當於,使用者訪問任意個網頁@Overridepublic void requestInitialized(ServletRequestEvent servletRequestEvent) {// 這個方法的參數可以轉化成request對象HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();// request對象中取session的方法HttpSession session = request.getSession();String sessionId = session.getId();// request對象中取ip的方法String ip = request.getRemoteAddr();// 資料庫的查詢結果ResultSet rs = null;try {// 如果這個sessionID已經在線上使用者列表裡面的// 使用者是線上的// 那麼更新其線上時間dbDAO db = new dbDAO();rs = db.query("select * from onlinetable where sessionId=?",sessionId);if (rs.next()) {db.modify("update onlinetable set timeonline=? where sessionId=?",System.currentTimeMillis(), sessionId);}// 否則插入線上使用者列表else {db.insert("insert into onlinetable values(?,?,?)", sessionId,ip, System.currentTimeMillis());}// 把當前的線上使用者列表放到application裡面rs = db.query("select * from onlinetable");} catch (Exception e) {e.printStackTrace();}// session.getServletContext()相當於application,用application存放線上使用者列表session.getServletContext().setAttribute("onlineTable", rs);}// application的消失對我們的意義不大// 相當於伺服器的關閉,一切都消失了@Overridepublic void contextDestroyed(ServletContextEvent arg0) {// TODO Auto-generated method stub}// application的開始相當於伺服器的啟動@Overridepublic void contextInitialized(ServletContextEvent arg0) {// TODO Auto-generated method stub// 伺服器一旦啟動每5秒執行如下的任務Timer timer = new Timer();timer.schedule(new MyTask(), 0, 5000);}}class MyTask extends TimerTask {public void run() {try {// 對線上使用者列表進行檢查dbDAO db = new dbDAO();ResultSet rs = db.query("select * from onlinetable");while (rs.next()) {// 如果目前時間距離使用者上一次線上時間超過5秒// 那麼則從線上使用者列表刪除這個結果。if (System.currentTimeMillis() - rs.getLong("timeonline") > 5 * 1000) {db.delete("delete from onlinetable where sessionId=?",rs.getString("sessionId"));}}} catch (Exception e) {e.printStackTrace();}}}

這裡,用到了《【Java】有關System.currentTimeMillis()的思考》(點擊開啟連結),取出1970年1月1日到現在的毫秒數的概念產生時間戳記,與《【Java】利用Timer與TimerTask定時執行任務》(點擊開啟連結)的概念,每5秒執行一次任務。


2、之後編寫一個online.jsp用來顯示當前資料庫的線上使用者列表,因為監聽器在每一次監聽request請求的過程中,已經把線上使用者列表放進application容器裡面,並且不斷更新裡面的訊息。application容器是一個所有使用者都能看到的,伺服器上面的大容器。區別於session容器,是使用者每次開啟瀏覽器之後,只是這個瀏覽器所能夠看到的小容器。online.jsp讀取這個application容器中的線上使用者列表查詢結果就可以了。注意取出來的對象,要經過強制類型轉換,不轉換被報錯。

<%@ page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8"%><%@ page import="java.sql.*"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>線上使用者列表</title></head><body>線上使用者列表<%ResultSet rs=(ResultSet)application.getAttribute("onlineTable"); %><table border="1"><tr><td>ip</td><td>sessionId</td></tr><%while(rs.next()){%><tr><td><%=rs.getString(2)%></td><td><%=rs.getString(1)%></td></tr><%} %></table></body></html>

四、總結與展望

其實,整個網路工程的MVC分層如下,MODEL還是之前《【Servlet】根據MVC思想設計使用者登陸、使用者註冊、修改密碼系統》(點擊開啟連結)寫好的MODEL,這裡由於是同一資料庫,完全可以哪裡注意。online.jsp作為view,不直接查詢資料庫,讀出C層監聽器,放入的查詢結果。


雖然利用到《【Java】用JDK1.5之後的新型數組遍曆方法遍曆HashMap、HashMap不應該儲存多元組》(點擊開啟連結)提到的多元組,同樣可以存放線上使用者資訊,但是之所以使用到資料庫存放線上使用者資訊,是因為可以避免設定一個存放類的ArrayList放入Application容器。存放類的ArrayList放入Application容器不比放入資料庫簡單,主要是程式不夠清晰。

【Listener】利用監聽器Listener以MVC的思想通過JSP+Servlet+JDBC完成線上使用者列表的輸出

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.