b/s模式下的即时通讯,使用ajax框架dwr实现
b/s模式下的即时通讯,使用ajax框架dwr实现 了解java的发展史可以知道,客户端编程在基于浏览器的编程方面,以前的做法是用applet实现客户端编程,在当时算是流行的做法,但是随着IE的不一致,尤其是微软的不支持, Applet没有发展起来,还有一个原因就是在浏览器中要下载java运行时插件,这几M的大小,对于以前网速就慢的网络,无疑断送了它的性命。现在应用与客户端浏览器的技术主要为一些牛人自己开发的插件,通过下载实现自己的功能。现在最通用最新的做法是利用XmlHttpRequext,异步实现客户端请求,也就是通常所说的ajax(异步的JavaScript和xml)技术,可以使用封装好的dwr框架简化开发,另一种方式就是使用Flex技术,就是Flash脚本编程,只是听说,自己还没有用过。 自己写了一个使用ajax框架dwr实现简易的即时通信程序。 首先什么是dwr呢?DWR是一个框架,简单的说就是能够在javascript直接调用java方法,而不必去写一大堆的javascript代码。它的实现是基于ajax的,可以实现无刷新效果。 一、 dwr配置篇 1.web.xml <servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class> org.directwebremoting.servlet.DwrServlet </servlet-class> <init-param> <description>调试DWR,发布系统时应将其设为false</description> <param-name>debug</param-name> <param-value>true</param-value> </init-param> <init-param> <description>使用服务器推技术(反转AJAX)</description> <param-name>activeReverseAjaxEnabled</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name> initApplicationScopeCreatorsAtStartup </param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>maxWaitAfterWrite</param-name> <param-value>100</param-value> </init-param> <load-on-startup>4</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> 这个参数DWR默认是false。如果选择true,我们可以通过http://localhost:port/app/dwr看到你部署的每个DWR class。并且可以测试java代码的每个方法是否运行正常。为了安全考虑,在正式环境下你一定把这个参数设为false。 2.使用dwr还要由一个dwr.xml配置文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr/dwr20.dtd"> <dwr> <allow> <convert converter="bean" match="com.lhq.User" /> <create creator="new" javascript="ChatManager"> <param name="class" value="com.lhq.ChatManager" /> </create> </allow> </dwr> 二.Dwr使用篇 实例:b/s模式下的即时通讯,使用ajax框架dwr实现 1. 首先把dwr.jar包放在项目lib目录下。 2. 进行上述web.xml相关配置,上述配置就是本实例的配置。 3. 为实现功能写的javabean,可能还有servlet,但本实例没有牵涉到servlet。代码如下: package com.lhq; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import org.directwebremoting.ScriptBuffer; import org.directwebremoting.ScriptSession; import org.directwebremoting.ServerContext; import org.directwebremoting.ServerContextFactory; import org.directwebremoting.WebContextFactory; import org.directwebremoting.proxy.dwr.Util; /** *处理聊天相关 * *@authorlhq * */ publicclass ChatManager { /**保存当前在线用户列表*/ publicstatic List<User> users = new ArrayList<User>(); /** *更新在线用户列表 * *@paramusername * 待添加到列表的用户名 *@paramflag * 是添加用户到列表,还是只获得当前列表 *@paramrequest *@return用户userid */ public String updateUsersList(String username,boolean flag, HttpServletRequest request) { User user = null; if (flag) { // 这里取会话(HttpSession)的id为用户id System.out.println("aauserid:" + request.getSession().getId()); user = new User(request.getSession().getId(),username); // 保存用户到列表 users.add(user); // 将用户id和页面脚本session绑定 this.setScriptSessionFlag(user.getUserid()); } // 获得DWR上下文 ServletContext sc = request.getSession().getServletContext(); ServerContext sctx = ServerContextFactory.get(sc); // 获得当前浏览 index.jsp 页面的所有脚本session Collection sessions = sctx .getScriptSessionsByPage("/BalanceCenter/index.jsp"); System.out.println("session的记录数:" + sessions.size()); // 消除不存在的页面session System.out.println("session的记录数(消除后):" + sessions.size()); Util util = new Util(sessions); // 处理这些页面中的一些元素 util.removeAllOptions("users"); util.addOptions("users",users,"username"); util.removeAllOptions("receiver"); util.addOptions("receiver","userid", "username"); if (!flag) { returnnull; } return user.getUserid(); } /** * *当退出时更新user * * */ publicvoid delUser(HttpServletRequest request) { String userid = request.getSession().getId();// 与userid相等,呵呵 System.out.println("userIdaa:" + userid); Iterator it = users.iterator(); while (it.hasNext()) { User user = (User) it.next(); System.out.println(user.getUsername()); System.out.println("userId:" + user.getUserid()); if (user.getUserid().equals(userid)) { users.remove(user); break; } } updateUsersList(null,false,request) ; } /** *将用户id和页面脚本session绑定 * *@paramuserid */ publicvoid setScriptSessionFlag(String userid) { WebContextFactory.get().getScriptSession().setAttribute("userid", userid); } /** *根据用户id获得指定用户的页面脚本session * *@paramuserid *@paramrequest *@return */ @SuppressWarnings("unchecked") public ScriptSession getScriptSession(String userid, HttpServletRequest request) { ScriptSession scriptSessions = null; Collection<ScriptSession> sessions = new HashSet<ScriptSession>(); sessions.addAll(ServerContextFactory.get( request.getSession().getServletContext()) .getScriptSessionsByPage("/BalanceCenter/index.jsp")); for (ScriptSession session : sessions) { String xuserid = (String) session.getAttribute("userid"); if (xuserid != null && xuserid.equals(userid)) { scriptSessions = session; } } return scriptSessions; } /** *发送消息 * *@paramsender * 发送者 *@paramreceiverid * 接收者id *@parammsg * 消息内容 *@paramrequest */ publicvoid send(String sender,String receiverid,String msg, HttpServletRequest request) { ScriptSession session = this.getScriptSession(receiverid,request); Util util = new Util(session); util.setStyle("showMessage","display", ""); ScriptBuffer script = new ScriptBuffer(); script.appendScript("receiveMessages(").appendData( sender + "说:" + msg + "/n").appendScript(");"); session.addScript(script); } } 4. 进行dwr.xml相对于javabean的相关配置,及提供客户端JavaScript脚本对于java方法的可见性。上述代码及为本实例代码。 5. 客户端javascript中调用 自定义一个chat.js文件,用来跟后台进行交互。代码如下: /** * 注册 */ function register(button) {
if ($('username').value == "" || $('username').value.length <= 0) { alert("请输入昵称"); return; } /*相应按钮处理 */ $('username').disabled = true; button.disabled = true; //$('message').disabled = false; $('send').disabled = false; $('receiver').disabled = false; $('send').disabled = false; $('exit').disabled = false; /*调用后台ChatManager类的updateUsersList方法,并取得返回值元数据放在data中*/ ChatManager.updateUsersList($('username').value,true, function(data) { if (data != null && data.length > 0) { $('userid').value = data; // 把当前sessionId放在隐藏表单 } }); } /** *初始化 */ function init() { dwr.engine.setActiveReverseAjax(true); // 激活反转 ChatManager.updateUsersList(null,false); //和上面那个方法一样 } function delUser(button) { ChatManager.delUser(); //当退出是调用,消除该在线用户 /** *并对相应按钮进行相应处理 */ $('username').disabled = false; $('register').disabled = false; button.disabled=true; $('receiver').disabled = true; $('send').disabled = true; $('areaMessage').innerHTML = ""; } /** * 当发送信息是调用 */ function send() { var sender = dwr.util.getValue('username'); //取得该用户的名字 var receiver = dwr.util.getValue('receiver'); // 取得接收者 var msg = FCKeditorAPI.GetInstance("message").EditorDocument.body.innerHTML; // 取得文本编辑器的文本 ChatManager.send(sender,receiver,msg); //调用后台方法 } /** *这是后台推技术调用的方法,接受信息 */ function receiveMessages(message) { //取得聊天信息中文本 var messages=document.getElementById("areaMessage").innerHTML; document.getElementById("areaMessage").innerHTML=message+"<hr/>"+messages;
} window.onload = init;//页面加载时
6. html代码 需要导入必须的js文件,在文本编辑时,我用了一个fckEditor文本编辑器,上网下一个就可以了,放在根目录下,本人美感欠缺,页面不太好看,请见谅!具体代码如下: <%@ page language="java" pageEncoding="GBK"%> <% String context=request.getContextPath(); pageContext.setAttribute("ctx",context); %> <html> <head> <title>chat</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <script type='text/javascript' src='/BalanceCenter/dwr/interface/ChatManager.js'></script> <script type='text/javascript' src='/BalanceCenter/dwr/engine.js'></script> <script type='text/javascript' src='/BalanceCenter/dwr/util.js'></script> <script type="text/javascript" src="/BalanceCenter/chat.js"></script> <script type="text/javascript" src="${ctx}/fckeditor/fckeditor.js"></script> </head> <body> <input type="hidden" name="userid" /> <br> 昵称: <input type="text" name="username" id="username" /> <input type="button" value="注册" onclick="register(this);" id="register"/> <input type="button" value="退出" onclick="delUser(this);" id="exit"/> <br /> <br /> 我要对 <select name="receiver" id="receiver" disabled=true" > </select> 说: <script type="text/javascript"> var oFCKeditor = new FCKeditor("message"); oFCKeditor.BasePath = '${ctx}/fckeditor/' ; oFCKeditor.Height = 300 ; oFCKeditor.ToolbarSet = 'Default'; oFCKeditor.Create() ; </script>
<input type="button" value="发送" id="send" name="send" disabled="true" onclick="send();" /> <br /> <br /> 在线用户列表:
<ul id="users"> </ul>
<div id="showMessage" style="display: none"> <div id="areaMessage" style="position:absolute; width:600px; height:300px; z-index:1; border:solid; overflow:auto; "> </div> </div>
</body> </html> 好了,终于写完了,首先要说明一下,本程序不是很完善,具体在:用户只有点击“退出”按钮才可以实现把该在线人员删除掉,可能利用js也可以实现关闭页面也可以把该在线人员删除掉,但是如果用户刷新了,怎么办呢???就是怎么记录有效地scriptsession呢?有人说用map保存。本人没有试过,还望高手指点,不胜感激!!! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |