天天看點

使用xmlhttp和Java session監聽改善站内消息系統

這個題目含有許多需要解釋的概念,最容易說明的是“站内消息”,這是很多論壇都有的功能,可以通過web向其他的線上使用者發送消息,很多使用者都使用過。站内消息的第一個好處是大家都不需要安裝用戶端,你不用知道對方的MSN或者QQ,就能與他聯系,稱贊他的觀點或者是給他一頓臭罵。第二個好處是客戶管理友善,利用session來維護線上名單,各種腳本都已經把session操作封裝得很易用了,不用像其他無狀态的即時通信工具(比如使用UDP通信的工具)一樣,要費一些腦細胞來解決線上名單的問題。缺點嘛,就是實時性不好,一般是在使用者跳轉或者重新整理頁面才能探測消息、更新線上名單。

Session監聽嘛,沒什麼好解釋的,java提供了很靈活的事件機制來監聽session,可以監聽session的建立和銷毀,監控 session所攜帶資料的建立、變化和銷毀,可以監聽session的銳化和鈍化(了解對象序列化的兄弟應該知道這個),其他的平台是個什麼情況我不太清楚,估計也差不多吧。如果能夠對所有客戶的session進行監控,就不用再去操作麻煩而危險的Application了。

Xmlhttp是MS推的一項技術,功能很複雜,可以做很多事情,比如用戶端可以在簡單的HTML中打開HTTP連接配接,主動向server請求資料并獲得傳回資料,是DOM技術一個非常重要的應用,利用它來寫無重新整理的動态頁面簡直是so easy,做過web開發的兄弟應該明白它的意義有多麼重大。

一、 session監聽

servlet中對session的監聽有很多接口,功能很靈活,最常用的是監聽Session和Attribute。這裡要澄清一下概念, servlet中的session監聽和Attribute監聽含義有差别,session監聽指的不是我們一般所了解的放置一個session或者銷毀一個session,這是Attribute監聽的功能,因為servlet中放置session的文法是session.setAttribute (“session名”,要放入的對象)。而session監聽,監聽的是HTTP連接配接,隻要有使用者與server連接配接,就算連接配接的是一個空白的jsp頁面,也會觸發session事件,是以此處的session實際上指的是connection,用來統計目前線上使用者數最合适了。不知道我說清楚了沒有。下面分别講解這兩種監聽方式。

1、 session監聽

首先編寫一個session監聽類,實作HttpSessionListener接口,它的作用是計算目前有多少個線上使用者:

代碼:

/*

*@Author bromon

*2004-6-12

*/

package org.bromon.test;

import javax.servlet.*;

import javax.servlet.http.*;

public class SessionCount implements HttpSessionListener

{

private static int count=0;

public void sessionCreated(HttpSessionEvent se)

count++;

System.out.println(“session建立:”+new java.util.Date());

}

public void sessionDestroyed(HttpSessionEvent se)

count--;

System.out.println(“session銷毀:”+new java.util.Date());

public static int getCount()

return(count);

怎麼樣,是不是一目了然?count被定義為static,是因為要保證整個系統隻有這一個count。如果你實在不放心,可以把它寫成一個單例類。

然後在web.xml中聲明這個監聽器:

<listener>

<listener-class>

org.bromon.test.SessionCount

</listener-class>

</listener>

編寫一個測試頁面test.jsp,内容是獲得count:

<%

int count=org.bromon.test.SessionCount.getCount();

out.println(count);

%>

需要注意的是,這裡根本不涉及任何session的操作。重新開機動App server,試着連接配接test.jsp,可以看到監聽器已經開始工作。

2、 Attribute監聽

作為一個站内消息系統,肯定要獲得所有登陸者的ID,才有可能互發消息。這就涉及Attribute監聽。假設我們寫了個使用者登陸的子產品,使用者通過身份驗證之後會産生一個session,儲存它的相關資訊,比如:

//check.jsp

String name=request.getParameter(“name”);

Name=new String(name.getBytes(“ISO8859-1”));

session.setAttribute(“user”,name);

做過jsp的兄弟應該對這段代碼再熟悉不過了,下面寫個監聽器來監聽使用者登陸,把所有使用者的ID儲存到一個List當中,這個監聽器實作HttpSessionAttributeListener接口:

import java.util.*;

public class OnlineList implements HttpSessionAttributeListener

private static List list=new ArrayList();

public void attributeAdded(HttpSessionBindingEvent se)

if(“user”.equals(se.getName()))

list.add(se.getValue());

public void attributeRemoved(HttpSessionBindingEvent se)

list.remove(se.getValue());

public void attributeReplaced(HttpSessionBindingEvent se){}

public static List getList()

return(list);

寫個簡單的jsp來得到使用者清單:

java.util.List list=org.bromon.test.OnlineList.getList();

out.println(“共有”+list.size()+”名使用者已登陸:”);

for(int I=0;I<lise.size();i++)

out.println(list.get(i));

}%>

也許你說,這有什麼神奇呢,監聽session而已,不着急,看看xmlhttp。

二、 XMLHTTP

XMLHTTP的用處很多,這裡隻說我們需要的,就是無重新整理的與server通信,看這段代碼:

<script language="javascript">

xml = new ActiveXObject("Microsoft.XMLHTTP");

var post=" ";//構造要攜帶的資料

xml.open("POST","http://localhost:7001/TestWL/index.jsp",false);//使用POST方法打開一個到伺服器的連接配接,以異步方式通信

xml.setrequestheader("content-length",post.length);

xml.setrequestheader("content-type","application/x-www-form-urlencoded");

xml.send(post);//發送資料

var res = xml.responseText;//接收伺服器傳回的資料

document.write(res);

</script>

豁然開朗,這段代碼就是打開一個HTTP連接配接,以标準的HTTP格式傳遞資料,如果你喜歡,可以用XML的格式來傳遞。更改一下xml對象的構造方式就可以相容Mozilla和Netscape。下面來寫一個輪詢,每隔一段時間重新整理一次使用者清單,當然,是不需要重新整理頁面的:

<html>

<head><title>探測器</title>

function detect()

list.innerText=res;

setTimeout(“detect()”,5000);//每隔5秒鐘輪詢一次

<body onload=”detect()”>

<a id=”list”></a>

</body>

</html>

這樣的通信方式資料量很小,不用重新傳遞整個頁面,5秒鐘輪一次,普通PC也能承受較大的線上數。構造一個探測器來監聽線上清單和消息,效果是很好的,即使你的客戶坐在電腦前袖手旁觀,鍵鼠都不碰一下,也能保證資料即時傳遞,頁面也不會發生跳轉和重新整理。

Session監聽加上XMLHTTP通信,開發一個較為完善的站内消息系統實在易如反掌。'

不允許匿名發表, 請先 注冊

Re: 使用xmlhttp和Java session監聽改善站内消息 作者: fay

日期: Jun 21 @ 11:23:55 CST

如果是mozilla應該如何構造xml對象?如果成為同一的标準就好了!

日期: Jun 21 @ 12:42:13 CST

另外, 用iframe一樣可以解決這個問題, 隻有iframe内的内容會重新整理, 資料量一樣很小, 界面處理上各有千秋.

Re: 使用xmlhttp和Java session監聽改善站内消息 作者: jackey

日期: Jun 21 @ 20:20:35 CST

不錯的文章,可喜還漏了點。

對于J2EE來說,listener還有其他幾種,比如說context listener等,而且這個J2EE平台有不同,weblogic有timer的listener,而Tomcat沒有必須自己寫。我有一個奇怪的問題,使用者驗證如果用的是Realm,你是怎麼處理的。我實作了tomcat下對NT使用者驗證,回頭試試的方法。我也使用了session listener,不過我是向資料庫裡更新使用者的線上情況,比如使用者關閉浏覽器後,觸發session listener登出使用者。

日期: Jun 21 @ 20:24:37 CST

Context Listener的例子,我以前寫的,供大家參考。

public class ContextListener implements ServletContextListener {

//itckTock is a Timer.

private Timer tickTock = null;

/** The method that executes upon startup of the AVRD. This method will

* create a timer to fire off once every 24 hours at 3:00 a.m..

* @param sce Used to get a Servlet Context object and write to the log

* file.

public void contextInitialized(ServletContextEvent sce) {

sce.getServletContext().log("<SysMsg>: AVRD starting ...");

//Startup Task

StartupTask startupTask = new StartupTask(sce.getServletContext());

startupTask.launchTask();

//Schedule Task

try {

final long DAY = 1000 * 60 * 60 * 24;

Calendar cal = Calendar.getInstance();

/**

* If we are at the end of the month (or close to it), role over to

* the next month and set the day to 1.

if ((cal.get(Calendar.DAY_OF_MONTH) >= 28

&& cal.get(Calendar.MONTH) == Calendar.FEBRUARY)

|| cal.get(Calendar.DAY_OF_MONTH) >= 30) {

if (cal.get(Calendar.MONTH) == Calendar.DECEMBER) {

cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + 1);

cal.set(Calendar.MONTH, Calendar.JANUARY);

} else

cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1);

cal.set(Calendar.DAY_OF_MONTH, 1);

} else {

//Otherwise just increment the day by 1.

cal.set(

Calendar.DAY_OF_MONTH,

cal.get(Calendar.DAY_OF_MONTH) + 1);

// Set the time to three a.m.

cal.set(Calendar.HOUR_OF_DAY, 3);

cal.set(Calendar.MINUTE, 0);

cal.set(Calendar.SECOND, 0);

tickTock = new Timer();

sce.getServletContext().log("<SysMsg>: AVRD timer started");

//Create an AOSS timer task to execute at 3:00 a.m. the next day and

//every 24 hours thereafter.

sce.getServletContext().log("<SysMsg>: Remind Task Scheduled");

tickTock.schedule(

new RemindTask(sce.getServletContext()),

cal.getTime(),

DAY);

} catch (Exception e) {

sce.getServletContext().log(

"<SysErrorMsg>: Creating AVRD maintenance Task Failed",

e);

sce.getServletContext().log("<SysMsg>: AVRD start successfully.");

* The method that executes upon shutdown of the AVRD.

public void contextDestroyed(ServletContextEvent sce) {

//Stop the timer

tickTock.cancel();

"<SysMsg>: AVRD maintenance task destroyed");

sce.getServletContext().log("<SysErrorMsg>: destroying maintenance failed", e);

//Shutdown Task

ShutdownTask shutdownTask = new ShutdownTask(sce.getServletContext());

shutdownTask.launchTask();

sce.getServletContext().log("<SysMsg>: AVRD destroy successfully.");

Re: 使用xmlhttp和Java session監聽改善站内消息 作者: bromon

日期: Jun 22 @ 11:14:07 CST

非常感謝幾位朋友的指教.J2EE的确有很多種servlet監聽,如果要一一寫出來,恐怕就太多了,而且容易跑題,

雖然這裡是linuxfans,不過我卻是linux外行,平時從事的很多工作都是針對IE的,唯一接觸linux也隻是在rh下跑跑weblogic而已.