<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    華山論劍

    一心一意做技術!

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      31 Posts :: 0 Stories :: 447 Comments :: 0 Trackbacks
      今年大家都在炒作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;
    }
    ?
      還有表示參加會議的人的信息,包括參會人名稱、IP地址、狀態等,如下面的ChatUser類所示:
    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");//返回會議室不存在的錯誤
    ??chatRoom.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("POST", 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="";
    }
    //接收發言信息
    function doRecive()
    {??
    ?? var reciver=EditForm.reciver.value;??
    ?? var url="/chat.ejf?easyJWebCommand=recive&cid="+roomId+"&lastReadId="+lastReadId;
    ?? executeAjaxCommand(url,"","recive");?
    }
    //處理接收到的發言信息
    function recive(list)
    {
    ??? var id="";??
    ??? for(var oNode=list.firstChild;oNode;oNode=oNode.nextSibling)?// 依次分析每個節點
    ?{
    ??? chatContent.innerHTML+=showMsg(oNode);
    ??? id=oNode.getAttribute("cid");
    ?}
    ??? if(id!="") lastReadId=id;
    ??? chatContent.scrollTop=chatContent.scrollHeight;
    ??? reciveTime=setTimeout("doRecive();",5000);?
    }
    ?

    六、系統演示
    ?
      大家可以到EasyJF開源團隊的官方網站看程序演示效果,地址是:

       http://www.easyjf.com/chatRoom.ejf?easyJWebCommand=show&ejid=2538093638804337

    結束語

      Ajax從技術上講主要就是javascript、dhtml、css、xmldom、xmlhttp等一些我們很早就接觸了的技術。而xmldom及xmlhttp也沒有什么東西,寫程序的時候把參考文檔打開Copy就OK,dhtml及javascript涉及的東西就多了,不能只是看參考文檔,需要把他真正消化,并能靈活動用,這就需要大家都練習了。筆者建議大家不要濫用Ajax。對于高手建議多研究一些業務及系統級算法設計等,對于新手嘛,把基本的技術(客戶端的包括dhtml、css、javascript、xml等,J2EE服務器端的設計模式、UML建模、Servlet、JDBC或ORM系統、XML、EJB及一些框架、工具等)學好才是硬道理。
    ?
      (本文作者:EasyJF開源團隊?  大峽 版權歸EasyJF開源團隊所有,歡迎轉載,轉載請保留作者版權聲明,謝謝!)
    posted on 2006-05-14 16:14 大峽 閱讀(4055) 評論(5)  編輯  收藏

    Feedback

    # re: 用AJAX+J2EE實現一個網上會議室系統 2006-05-14 16:29 大峽
    打算先把文字部分做了,現在是最簡單的模型,主要是服務器端的設計及實現!客戶端那些花哨的表情啊,動作啊........等等,對這個感興趣的一起來完善吧。

      回復  更多評論
      

    # re: 用AJAX+J2EE實現一個網上會議室系統 2006-05-14 18:20 原創專欄 開源學習
    聊天室有一個server一個client。
    通訊模型分為server-push和client-pull兩種。

    可以看看dwr的server-push模式。
    沒必要自己實現。  回復  更多評論
      

    # re: 用AJAX+J2EE實現一個網上會議室系統 2006-05-14 19:11 Xu Jianxiang
    不錯!
    dwr?  回復  更多評論
      

    # re: 用AJAX+J2EE實現一個網上會議室系統 2006-05-14 21:00 大峽
    這個系統沒用dwr。
    本文代碼是我理解的最原始、最純樸的Ajax寫法,客戶端的javascript可與服務器端的asp、php、JSP等交互的!
    本例子中準確的說是:EasyJWeb+javascript+xmlhttp  回復  更多評論
      

    # re: 用AJAX+J2EE實現一個網上會議室系統 2006-05-15 22:08 shooper
    不錯哦  回復  更多評論
      


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲视频一区网站| 亚洲综合色一区二区三区小说| 亚洲精华国产精华精华液好用| 亚洲一级免费毛片| 久久精品国产亚洲AV高清热| 99久久免费观看| 亚洲最大视频网站| 一个人免费高清在线观看| 亚洲娇小性xxxx| 免费视频淫片aa毛片| 福利片免费一区二区三区| 亚洲国产精品无码久久久久久曰| 一本久久免费视频| 亚洲av永久无码精品国产精品 | 亚洲成A人片在线观看中文| 日日摸日日碰夜夜爽亚洲| 亚洲日本韩国在线| 日韩电影免费观看| 亚洲精品影院久久久久久| 无码中文字幕av免费放| 国产午夜亚洲精品不卡免下载| 国产成人精品日本亚洲专区| 毛片在线全部免费观看| 亚洲中文字幕在线无码一区二区| 精品久久久久久久免费人妻| 国产精品高清免费网站| 久久亚洲AV无码精品色午夜| 大地资源在线观看免费高清| 免费看黄网站在线看| 亚洲高清在线播放| 永久中文字幕免费视频网站| 精品久久久久久无码免费| 亚洲国产成人精品无码区在线网站 | 一级全免费视频播放| 亚洲毛片在线观看| 日本xxwwxxww在线视频免费| a毛片成人免费全部播放| 亚洲国产成人超福利久久精品| 亚洲国产一区视频| 丁香花免费高清视频完整版| 一级毛片免费播放视频|