DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> AJAX入門 >> AJAX詳解 >> 用AJAX J2EE實現一個網上會議室系統
用AJAX J2EE實現一個網上會議室系統
編輯:AJAX詳解     

今年大家都在炒作Web2.0,其中的一門技術Ajax也是跟著火了起來,因此前面我寫了一篇名為《忽悠一下AJAX》的文章,簡單地分析了一下Ajax的技術的實質。雖然筆者不太喜歡跟風,但Ajax有一些地方還是比較有用的。前段時間做了EasyJF開源團隊的網上會議系統,就用到了AJax技術,下面把設計思路發出來跟大家分享一下。

  一、系統實現的功能

  本會議室系統主要用於EasyJF開源團隊的成員網上會議使用,會議系統模擬傳統的會議形式,可以同時開設多個不同主題的會議室,每個會議室需要提供訪問權限控制功能,會議中能夠指定會議發言模式(分為排隊發言、自由發言兩種),系統能自動記錄每個會議室的發言信息,可以供參會人員長期查閱。

  會議系統的用戶支持游客帳號參加會議,同時也提供跟其它用戶系統的接口,比如EasyJF官網中的開源論壇系統。

  會議系統暫時使用文字聊天的方式,並提供語音及視頻的接口。

  二、技術體系

  服務器端使用Java語言,MVC使用EasyJWeb框架;
  客戶端使用AJax技術與服務器端交互數據;
  會議歷史信息儲存格式使用文本格式,方便系統安裝運行,也便於管理。

  三、會議室服務器端設計

  會議室服務器端是整個會議系統的核心部分,服務器端程序設計的好壞影響到整個系統的質量。

  首先,根據會議室要實現的功能進行抽象分析。一個會議室對象,應該包括會議主題、會議簡介、參會人數限制、公告、會議室類型、訪問權限設定、房間密碼、當前參會的人員、當前發言的人員、排隊等待發言的人員等參數信息。我們把他封裝一個Java對象當中。如下面的ChatRoom代碼所示:
public class ChatRoom{
private String cid;//主鍵
private String title;//聊天室主題
private String intro;//聊天室簡介
private String announce;//聊天室公告
private String owner;//聊天室創建人
private Integer maxUser;//最大在線人數
private Integer intervals;//最大刷新時間間隔
private String vrtype;//訪問權限
private String vrvalue;//訪問值
private Integer status;//聊天室狀態
private Date inputTime;
}

需要一個管理會議室的類,與會議有關的操作(如啟動會議、關閉會議)等都直接找他。該類還應該即有自動定時檢測用戶在線情況(防止用戶意外退出)、把內存中的會議歷史發言信息保存到文本文件中等功能。這裡可以考慮使用一個ChatService類提供這些功能:
 public class ChatService implements Runnable {
private static final Map service=new HashMap();//會議室服務,系統中的當前會議室存放到該表集合中
private static final int maxServices=10;//可以同時開的最大會議室數
private static final SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
private final List msgs;//聊天信息Chat
private final List users;//在線用戶,ChatUser
private final List talkers;//排隊發言人數Talker
private final List manager;//會議室管理員
private Talker currentTalker;//當前發言人
public ChatService()
{
this.msgs=new ArrayList();
this.users=new ArrayList();
this.talkers=new ArrayList();
this.manager=new ArrayList();
this.maxUser=1000;//最大1000人同時
this.interval=1000*60*5;//5分鐘以前的信息
}
}

 會議發言信息也需要封裝成一個類,表示發言人、接收人、內容、發言時間、類型等,大致如下面的Chat類:
public class Chat {
private String cid;
private String sender;
private String reciver;
private String content;
private Date vdate;
private Integer types;
private Integer status;
}
public class Chat {
private String cid;
private String sender;
private String reciver;
private String content;
private Date vdate;
private Integer types;
private Integer status;
}
  還有表示參加會議的人的信息,包括參會人名稱、IP地址、狀態等,如下面的ChatUser類所示:

public class ChatUser {
private String ip;
private String port;
private String userName;
private Date lastAccessTime;
private Integer status;
}public class ChatUser {
private String ip;
private String port;
private String userName;
private Date lastAccessTime;
private Integer status;
}
  另外還需要一個表示當前發言人的Talker類,表示當前的發言人,發言開始時間,發言預計結束時間等。

  在服務器端的設計中,會議室信息服務器應該能以多線程的方式運行,即啟動一個會議就新開一個線程,每個會議線程維護自己的會議狀態,如參會人、發言人,保存會議歷史發言信息以及清空內存中的數據等操作。

  四、客戶端設計

  會議室客戶端包括兩個部分,一個部分是會議室的管理界面,主要包會議室的“添刪改查”及“啟動”或“關閉”會議服務的操作。這部分我們直接使用EasyJWeb Tools中的添刪改查業務引擎AbstractCrudAction可以快速實現。界面也比較簡單,直接使用EasyJWeb Tools代碼生成工具引擎生成即可。會議室管理的客戶端是傳統的Java Web技術,因此沒有什麼要考慮的。

  客戶端的第二個部分也即會議系統的主要部分,該部分主要有兩個界面,第一個頁面是會議室進入的選擇頁面。也即把已經啟動的會議室列出來,用戶選擇一個會議室進入,這個頁面也是使用傳統的Java Web技術。第二個頁面是進入會議室後的主界面,這個界面是整個會議系統的主要界面,所有參與會議的操作都在這裡運行的。這個界面需要不斷的與服務器端交互傳輸數據,傳輸的內容包括用戶的發言、其它人給用戶的發言、會議室的狀態等。有的傳輸信息需要即時響應(如用戶發言),有的信息可以設置成定時響應(如會議室狀態)。

Java Web程序中與服務器端交互數據主要有兩種方式,一種是直接刷新頁面,另外一種是使用Socket直接跟Web服務器端口通訊。由於Socket編程相對復雜,我們選擇第一種直接刷新頁面的方式,這種方式又可以分為幾種,包括傳統的Form提交,傳統的自動刷新網頁取得數據以及使用ActiveXObject對象(如XMLhttp)直接與服務器交互數據,也即AJAX方式。由於使用AJAX方式用戶感覺不到頁面在刷新,表現起來好於手動或自動刷新頁面的方式,因此我們決定選擇AJax方式實現客戶端與服務器端進行數據交互。

  用戶發言的時候,直接使用xmlhttp對象Post數據到服務器。為了能不斷接收到別人的發言信息,需要定時不斷的從服務器端讀取數據,因此,需要在客戶端啟動一個定時器,每隔一定的時候自動使用xmlhttp對象到服務器端下載別人的發言信息,並顯示到會議室信息主界面中。另外還要定時刷新參會的人數、會議室當前發言人、會議室的公告等會議狀態信息,這也可以通過從客戶端啟動一個定時器,通過XMLhttp對象與服務器交互得到。

  另外還有一些操作,鎖定會議室、踢人、指定發言人的發言時間、給會議室加密碼等功能,也通過XMLhttp的方式與服務器傳輸命令實現。

  五、核心代碼說明

  1、服務器端核心代碼

  在EasyJF開源團隊的會議系統中,由於是以EasyJF官網的論壇系統、後台管理等是集成一起的。服務器ChatService與ChatRoom共同合並到了一個ChatService.Java類中,實現會議室管理及會議服務功能。ChatService類的部分主要代碼如下:

package com.easyjf.chat.business;
public class ChatService implements Runnable {
 private static final Map service=new HashMap();//會議室服務,系統中的當前會議室存放到該表集合中
 private static final int maxServices=10;//可以同時開的最大會議室數
 private static final SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
 private final List msgs;//聊天信息Chat
 private final List users;//在線用戶,ChatUser
 private final List talkers;//排隊發言人數Talker
 private final List manager;//會議室管理員
 private Talker currentTalker;//當前發言人
 private String cid;//會議室id
 private String title;//會議室主題
 private String intro;//會議室簡介
 private String owner;//會議室創建人
 private int maxUser;//最大在線人數
 private int interval;//最大刷新時間間隔
 private String vrtype;//訪問權限
 private String vrvalue;//訪問值
 private String announce;
 private String passWord;//房間進入密碼
 private int status;//會議室狀態
 private String filePath;
 //private Thread thread;
 private boolean isStop=false;
 public ChatService()
 {
  this.msgs=new ArrayList();
  this.users=new ArrayList();
  this.talkers=new ArrayList();
  this.manager=new ArrayList();
  this.maxUser=1000;//最大1000人同時
  this.interval=1000*60*5;//5分鐘以前的信息
 }
 /**
 * 停止所有會議室
 *
 */
 public static void clear()
 {
  if(!service.isEmpty())
  {
   Iterator it=service.values().iterator();
   while(it.hasNext())
   {
    ChatService chat=(ChatService)it.next();
    chat.stop();
   }
  }
  service.clear();
 }
 /**
 * 創建一個會議室
 * @param name 會議室ID
 * @return
 */
 public static ChatService create(String name)
 {
  ChatService ret=null;
   if(service.containsKey(name))
   {
    ChatService s=(ChatService)service.get(name);
    s.stop();
    service.remove(name);
   }
   if(service.size()<maxServices)
   {
    ret=new ChatService();
    service.put(name,ret);
   }
   return ret;
 }
                                   /**
 * 停止某個會議室
 * @param name 會議室ID
 * @return
 */
 public static boolean close(String name)
 {
  ChatService chatRoom=ChatService.get(name);
  if(chatRoom!=null)
  {
   chatRoom.stop();
   service.remove(name);
  }
   return true;
 }
 /**
 * 獲得一個會議室信息
 * @param name 會議室ID
 * @return
 */
 public static ChatService get(String name)
 {
  if(service.containsKey(name))return (ChatService)service.get(name);
  else return null;
 }
 public void run() {
  // TODO Auto-generated method stub
  //this.thread=Thread.currentThread();
  while(!isStop)
  {
   //System.out.println("開始監控一個會議室!" this.title);
   this.Flash();
   try{
    Thread.sleep(5000);
   }
   catch(Exception e)
   {
   e.printStackTrace();
  }
 }
 //System.out.println("結束!");
}
 public void stop()
 { 
   this.FlashAll();
   isStop=true;
 }
 //會議室中有人發言
 public boolean talk(Chat chat)
 {
  boolean ret=false;
  if(canTalk(chat.getSender()))
  {
   this.msgs.add(chat);
   ret=true;
  }
  return ret;
 }
 public boolean exit(ChatUser user)
 {
  talk(geneSystemMsg(user.getUserName() "退出了會議室!"));
  return this.users.remove(user);
 }
}

//刷新信息,保存會議信息
public void Flash()
{
 FlashChatMsg();
 FlashChatUser();
}
}
  2、MVC處理部分的Action代碼

  在EasyJF的會議系統中,由於使用EasyJWeb作為MVC框架,因此處理AJax比較簡單,下面是會議室系統的核心Action主要代碼。
package com.easyjf.chat.action;
public class ChatAction extends AbstractCmdAction {
 private ChatService chatRoom;
 public Object doBefore(WebForm form, Module module) {
  // TODO Auto-generated method stub
  if(chatRoom==null)chatRoom=ChatService.get((String)form.get("cid"));
   return super.doBefore(form, module);
 }
 public Page doInit(WebForm form, Module module) {
  // TODO Auto-generated method stub
   return doMain(form,module);
 }
 //用戶登錄進入會議室
 public Page doMain(WebForm form, Module module) {
  if(chatRoom!=null){
   ChatUser user=getChatUser();
   if(!chatRoom.join(user))form.addResult("msg","不能加入房間,可能是權限不夠!");
   form.addResult("chatRoom",chatRoom);
   form.addResult("user",user);
  }
  else
  {
   form.addResult("msg","會議未啟動或者會議室不存在!");
  }
  return module.findPage("main");
 }
 //處理用戶發言信息
 public Page DOSend(WebForm form, Module module) {
  if(chatRoom==null)return new Page("err","/err.Html","thml");//返回會議室不存在的錯誤
  Chat chat=(Chat)form.toPo(Chat.class);
  chat.setCid(chatRoom.geneId());
  chatRoom.talk(chat);
  return doRecive(form,module);
 }
 //用戶接收發言信息
 public Page doRecive(WebForm form, Module module) {
   if(chatRoom==null)return new Page("err","/err.Html","thml");//返回會議室不存在的錯誤
   String lastReadId=CommUtil.null2String(form.get("lastReadId"));
   //System.out.println(lastReadId);
   form.addResult("list", chatRoom.getNewestMsg(getChatUser(),lastReadId));
   return module.findPage("msgList");
 }
 //用戶刷新會議狀態信息
 public Page doLoadConfig(WebForm form, Module module) {
  if(chatRoom==null)return new Page("err","/err.Html","thml");//返回會議室不存在的錯誤
  form.addResult("userList", chatRoom.getUsers());
  form.addResult("talkerList", chatRoom.getTalkers());
  return module.findPage("config");
 }
 //用戶退出
 public Page doExit(WebForm form, Module module) {
 if(chatRoom==null)return new Page("err","/err.Html","thml");//返回會議室不存在的錯誤
 hatRoom.exit(getChatUser());
 form.addResult("msg","退出成功");
 ActionContext.getContext().getSession().removeAttribute("chatUser");
 return new Page("msg","/chat/xmlMsg.XML",Globals.PAGE_TEMPLATE_TYPE);
}       

3、客戶端AJax部分核心代碼

  EasyJF會議系統中,服務器發送給客戶端的都是格式化的XML文檔數據。下面是核心的AJax函數及發送接收會議信息的客戶端代碼。
function newXMLHttpRequest() {
 var XMLreq = false;
 if (window.XMLHttpRequest) {
  xmlreq = new XMLHttpRequest();
 } else if (window.ActiveXObject) {
  try {
   xmlreq = new ActiveXObject("Msxml2.XMLHTTP");
 } catch (e1) {
 try {
   xmlreq = new ActiveXObject("Microsoft.XMLHTTP");
 } catch (e2) {
 }
 }
}
return XMLreq;
}
//處理返回信息
//XMLHttp返回值,
//method:方法名 方法必須帶一個參數如doRecive(xNode);
function handleAJaxResult(req,method) {
 return function () {
  if (req.readyState == 4) {
   if (req.status == 200) {
    // 將載有響應信息的XML傳遞到處理函數
    var objXMLDoc=new ActiveXObject("Microsoft.XMLDOM");
    objXMLDoc.loadXML(req.responseText);
    eval("if(objXMLDoc.firstChild)" method "(objXMLDoc.firstChild.nextSibling);");
   } else {
    //alert("HTTP error: " req.status);
                                                }
   }
  }
 }
 //執行客戶端AJax命令
 //url 數據post地址
 //postData 發送的數據包
 //handleMethod 處理返回的方法
 function executeAJaxCommand(url,postData,handleMethod)
 {
  var req = newXMLHttpRequest();
  req.onreadystatechange =handleAJaxResult(req,handleMethod);
  req.open("PO   ST", url, true);
  req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
  req.setRequestHeader("charset","utf-8");
  req.send(postData);
 }
 //用戶發言
unction DOSend()
{
 if(!check())return false;
 var msg=EditForm.content.value;
 var reciver=EditForm.reciver.value;
 var url="/chat.ejf?easyJWebCommand=send&cid=" roomId "&lastReadId=" lastReadId;
 var postData="sender=" myName "&reciver=" reciver "&content=" msg;
 clearTimeout(reciveTime);
 executeAJaxCommand(url,postData,"recive");
 EditForm.content.value="";
}

public class ChatService implements Runnable {
private static final Map service=new HashMap();//會議室服務,系統中的當前會議室存放到該表集合中
private static final int maxServices=10;//可以同時開的最大會議室數
private static final SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
private final List msgs;//聊天信息Chat
private final List users;//在線用戶,ChatUser
private final List talkers;//排隊發言人數Talker
private final List manager;//會議室管理員
private Talker currentTalker;//當前發言人
public ChatService()
{
this.msgs=new ArrayList();
this.users=new ArrayList();
this.talkers=new ArrayList();
this.manager=new ArrayList();
this.maxUser=1000;//最大1000人同時
this.interval=1000*60*5;//5分鐘以前的信息
}
}

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved