一系统实现的功能
本会议室系统主要用于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=;//可以同时开的最大会议室数private static final SimpleDateFormat df=new SimpleDateFormat(yyyyMMdd);private final List msgs;//聊天信息Chatprivate final List users;//在线用户ChatUserprivate final List talkers;//排队发言人数Talkerprivate final List manager;//会议室管理员private Talker currentTalker;//当前发言人public ChatService(){thismsgs=new ArrayList();thisusers=new ArrayList();thistalkers=new ArrayList();thismanager=new ArrayList();thismaxUser=;//最大人同时thisinterval=**;//分钟以前的信息}}
会议发言信息也需要封装成一个类表示发言人接收人内容发言时间类型等大致如下面的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的方式与服务器传输命令实现
五核心代码说明
服务器端核心代码
在EasyJF开源团队的会议系统中由于是以EasyJF官网的论坛系统后台管理等是集成一起的服务器ChatService与ChatRoom共同合并到了一个ChatServicejava类中实现会议室管理及会议服务功能ChatService类的部分主要代码如下
package comeasyjfchatbusiness;public class ChatService implements Runnable {private static final Map service=new HashMap();//会议室服务系统中的当前会议室
存放到该表集合中private static final int maxServices=;//可以同时开的最大会议室数private static final SimpleDateFormat df=new SimpleDateFormat(yyyyMMdd);private final List msgs;//聊天信息Chatprivate final List users;//在线用户ChatUserprivate final List talkers;//排队发言人数Talkerprivate final List manager;//会议室管理员 private Talker currentTalker;//当前发言人private String cid;//会议室idprivate 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(){thismsgs=new ArrayList();thisusers=new ArrayList();thistalkers=new ArrayList();thismanager=new ArrayList();thismaxUser=;//最大人同时thisinterval=**;//分钟以前的信息}/*** 停止所有会议室**/public static void clear(){if(!serviceisEmpty()){Iterator it=servicevalues(erator();while(ithasNext()){ChatService chat=(ChatService)itnext();chatstop();}}serviceclear();}/*** 创建一个会议室* @param name 会议室ID* @return*/public static ChatService create(String name){ChatService ret=null;if(ntainsKey(name)){ChatService s=(ChatService)serviceget(name);sstop();serviceremove(name);} if(servicesize()
2、MVC处理部分的Action代码
在EasyJF的会议系统中,由于使用EasyJWeb作为MVC框架,因此处理Ajax比较简单,下面是会议室系统的核心Action主要代码。tW.WinGWit.cOm
package com.easyjf.chat.action;public class ChatAction extends AbstractCmdAction {private ChatService chatRoom;public Object doBefore(WebForm form, Module module) {// TODO Auto-generated method stubif(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","/l","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","/l","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","/l","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","/l","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("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=ntent.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");ntent.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开源团队的官方网站看程序演示效果,地址是:
?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及一些框架、工具等)学好才是硬道理。