DWR+EXT在线聊天
嗯,么想到这么快就过了123456hits,没有截图到囧。大概是因为这几天开始校园招聘了吧,发现关键字里面很多都是XX 笔试……
那么放送一个半年前搞的Ext+DWR实现聊天的段落、、
玩这个是因为毕业设计里面有一个需要教师在线指导学生的模块,类似于聊天室,界面如下图(中的在线指导子页面)所示:
Ext用的是Ext JS Library 2.0.2,DWR则使用2.0,因为支持Server Push。
贴一段技术手册里的介绍^^:
系统中教师指导学生模块可以通过在线聊天的方式进行,该模块的实现采用了Server Push(服务器推送)技术,实时发送消息,优于现在浏览器通过AJAX轮询服务端的策略。基于Java开发的DWR框架从2.0开始提供了push功能,通过它建立的应用可以大大节省服务器的资源消耗。
DWR 2中提供的push功能是一种Comet方式,即长连接机制(long live http)。浏览器向服务器请求时,服务器一直保持着这个连接,在关闭之前都可以主动地推送数据给浏览器。下面是本系统中聊天模块的实现示例图:
图1-2 聊天模块实现
那么贴一下实验代码,即还没整合到该系统里面时先测试的程式。
首先是DWR这边的model:
package org.yoyo.chat; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; public class Message { private static DateFormat format = new SimpleDateFormat("HH:mm:ss"); private String sender; private Date sendTime; private String content; public Message(String sender, String content) { this.sender = sender; this.sendTime = new Date(); this.content = content; } public String getSender() { return sender; } public void setSender(String sender) { this.sender = sender; } public Date getSendTime() { return sendTime; } public void setSendTime(Date sendTime) { this.sendTime = sendTime; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getText() { return sender + " " + format.format(sendTime) + "<br />" + content + "<br/>"; } @Override public String toString() { return getText(); } }
package org.yoyo.chat; public class User { private String userId; private String username; public User(String id, String username) { this.userId = id; this.username = username; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
然后是业务处理:
package org.yoyo.chat; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.servlet.http.HttpServletRequest; import org.directwebremoting.ScriptSession; import org.directwebremoting.WebContext; import org.directwebremoting.WebContextFactory; import org.directwebremoting.proxy.dwr.Util; public class ChatManager { public static List<User> users = new ArrayList<User>(); private static List<Message> messages = new ArrayList<Message>(); private static Message newMessage; @SuppressWarnings("unchecked") public String updateUsersList(String newUserName, HttpServletRequest request) { User user = null; if (newUserName != null) { user = new User(request.getSession().getId(), newUserName); users.add(user); } WebContext wctx = WebContextFactory.get(); Collection sessions = wctx.getScriptSessionsByPage(wctx .getCurrentPage()); Util util = new Util(sessions); util.removeAllOptions("users"); util.addOptions("users", users, "username"); return newUserName == null ? null : user.getUserId(); } /** * 将用户id和页面脚本session绑定 * * @param userid */ public void setScriptSessionFlag(String userid) { WebContextFactory.get().getScriptSession().setAttribute("userid", userid); } /** * 根据用户id获得指定用户的页面脚本session * * @param userid * @return */ @SuppressWarnings("unchecked") public ScriptSession getScriptSession(String userid) { WebContext wctx = WebContextFactory.get(); ScriptSession scriptSessions = null; Collection<ScriptSession> sessions = wctx.getScriptSessionsByPage(wctx .getCurrentPage()); for (ScriptSession session : sessions) { String xuserid = (String) session.getAttribute("userid"); if (xuserid != null && xuserid.equals(userid)) { scriptSessions = session; } } return scriptSessions; } /** * 发送消息 * * @param sender * 发送者 * @param msg * 消息内容 */ @SuppressWarnings("unchecked") public void send(String sender, String msg) { newMessage = new Message(sender, toHtml(msg)); messages.add(newMessage); updateMessage(); } private String toHtml(String msg) { int index = -1; while ((index = msg.indexOf("\r\n")) >= 0) { msg = msg.substring(0, index) + "<br>" + msg.substring(index + 2); } while ((index = msg.indexOf("\n")) >= 0) { msg = msg.substring(0, index) + "<br>" + msg.substring(index + 1); } return msg; } /** * 获得消息 * @return */ public String getMessages() { StringBuffer content = new StringBuffer(""); for (Message msg: messages) { content.append(msg + "<br>"); } return content.toString(); } /** * 更新聊天记录 */ @SuppressWarnings("unchecked") public void updateMessage() { WebContext wctx = WebContextFactory.get(); Collection sessions = wctx.getScriptSessionsByPage(wctx .getCurrentPage()); Util utilAll = new Util(sessions); utilAll.addFunctionCall("appendMessage", newMessage == null ? "" : newMessage.toString() + "<br>"); } }
接着是前端JS:
var content = ""; /** * 页面初始化 */ function init() { dwr.engine.setActiveReverseAjax(true); // 激活反转 重要 ChatManager.updateUsersList(null); // 当你打开界面的时候,先获得在线用户列表. ChatManager.updateMessage(null); // 获得聊天记录 ChatManager.getMessages(function(data) { content = data; }); } function appendMessage(msg) { var bd = Ext.getCmp("chatlog").body; content = content + msg; bd.update(content); bd.dom.scrollTop = bd.dom.scrollHeight; } /** * 注册帐号 */ function register(button) { if ($("username").value === "" || $("username").value.length <= 0) { alert("\u8bf7\u8f93\u5165\u6635\u79f0"); return; } /* 下面是对一些按钮的禁用和激活操作 */ $("username").disabled = true; button.disabled = true; $("message").disabled = false; /* 把我输入的用户名注册到服务器,并获得用户id(这里用session id 代替) */ ChatManager.updateUsersList($("username").value, function (data) { if (data !== null && data.length > 0) { $("userid").value = data; // 注册成功,把userid放到当前页面 } }); } /** * 发送消息 */ function send() { var sender = dwr.util.getValue("username"); // 获得发送者名字 var msg = dwr.util.getValue("message"); // 获得消息内容 if (msg !== "") { ChatManager.send(sender, msg); // 发送消息 $("message").value = ""; } } window.onload = init;//页面加载完毕后执行初始化方法init
最后是Ext搞的界面:
<%@ page language="java" pageEncoding="UTF-8"%> <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"> <link rel="stylesheet" type="text/css" href="lib/ext/resources/css/ext-all.css" /> <link rel="stylesheet" type="text/css" href="lib/ext/resources/css/ext-patch.css" /> <script type="text/javascript" src="lib/ext/adapter/ext/ext-base.js"></script> <script type="text/javascript" src="lib/ext/ext-all.js"></script> <script type='text/javascript' src='dwr/interface/ChatManager.js'></script> <script type='text/javascript' src='dwr/engine.js'></script> <script type='text/javascript' src='dwr/util.js'></script> <script type="text/javascript" src="chat.js" charset="utf-8"></script> </head> <script> var chatlog = new Ext.Panel({ region:"center", id: "chatlog", autoScroll: true, height: 450, xtype: 'textarea', readOnly: true }); Ext.onReady(function(){ new Ext.Viewport({ layout:"border", items:[ { region:"center", title: "指导记录", layout:"border", items: [chatlog] }, { html: '<ul id="users"></ul>', region:"east", width:120, title:"参与者" }, { region:"south", height: 150, layout:"border", title: "发送信息", buttonAlign: "center", buttons: [{ id: 'send', xtype: 'button', text: '发送', handler:function(){ send(); } }, { id: 'exit', xtype: 'button', text: '结束指导' } ], items: [ { region:"center", id: "message", xtype: 'textarea', emptyText: '请输入内容', enableKeyListener: true, listeners:{ specialkey:function(f,e){ if(e.getKey() == e.ENTER){ send(); } } } }] } ] }); }); </script> <body> </body> </html>
貌似register被整合到我登陆的页面去了,因此米有在这里体现,需要的话可自己加个输入框输入用户名、再来个按钮调用该方法、、