?????? 前一篇 自己实现了http长连接 , 很繁琐,后来看到pushlet 好评如潮 ,就用pushlet 重写了一遍,由于? pushlet ajax api 以及 servlet 使用 get 方法来实现 ,并且对于中文有的问题 ,故 将其改为 post 方式,并对于中文两次编码 。
?
?
?
修改了 ajax api , ajax-pushlet-client.js ,改为 post 方式提交数据 ,并 在网络处状况时 通知 回调函数
?
修改 pushlet servlet , (nl\justobjects\pushlet\servlet\Pushlet.java) 使其支持 post 方式,原来只是支持post xml
首先 ext chat window 的建立: 用了 pushlet 代码就简洁多了 ,我基本上是把pushlet当作一个数据库使用的
?
使用代码 : (代码简要分析见后)
?
/* 利用pushlet 实现了 用户登录及时通知,退出及时通知,发送消息及时通知,用户单点登陆功能 */ Ext.onReady(function () { var chatWin = new Ext.Window({ width: 800, height: 500, title: 'Ext聊天窗口测试版', renderTo: document.body, border: false, hidden: true, layout: 'border', closeAction: 'hide', collapsible: true, constrain: true, iconCls: 'my-userCommentIcon', maximizable: true, items: [{ region: 'west', id: 'chat-west-panel', title: '用户面板', split: true, width: 170, minSize: 100, maxSize: 200, collapsible: true, constrain: true, //margins:'0 0 0 5', layout: 'accordion', layoutConfig: { animate: true }, items: [{ items: new Ext.tree.TreePanel({ id: 'im-tree', //rootVisible: false, lines: false, border: false, dataUrl: 'chat/getUserFirst.jsp', singleExpand: true, selModel: new Ext.tree.MultiSelectionModel(), root: new Ext.tree.AsyncTreeNode({ text: 'Sunrise', id: 'SunriseIm', //nodeType: 'async', singleClickExpand: true, expandable: true, expanded: true }) }), title: '在线人员', //layout:'form', border: false, autoScroll: true, iconCls: 'im_list', tools: [{ id: 'refresh', qtip: '刷新在线信息', // hidden:true, handler: function (event, toolEl, panel) { imRootNode.reload(); //reloadUser(); } }, { id: 'close', qtip: '清除选定', // hidden:true, handler: function (event, toolEl, panel) { Ext.getCmp('im-tree').getSelectionModel().clearSelections(); } }] }, { title: 'Settings', html: '<p>Some settings in here.</p>', border: false, iconCls: 'settings' }] }, { region: 'center', layout: 'border', items: [{ region: 'center', title: '历史记录 ', id: 'history_panel', autoScroll: true, iconCls: 'my-userCommentIcon', tools: [{ id: 'refresh', qtip: '注意:如果长时间没有收到对方回应,试一下', // hidden:true, handler: function (event, toolEl, panel) { // refresh logic } }] }, { region: 'south', title: '聊天啦', layout: 'fit', iconCls: 'user_edit', autoScroll: true, height: 200, collapsible: true, //margins:'0 0 0 0', items: { xtype: 'form', baseCls: 'x-plain', autoHeight: true, autoWidth: true, bodyStyle: 'padding:10 10px 0;', defaults: { anchor: '95%' }, items: [{ xtype: 'htmleditor', height: 130, id: 'htmleditor', hideLabel: true }] }, bbar: [{ text: '发送请输入Ctrl-Enter', handler: function () { sendmsg(); }, iconCls: 'my-sendingIcon' }, '-', { text: '清除', handler: function () { Ext.getCmp("htmleditor").reset(); } }] }] }] }); var tree = Ext.getCmp('im-tree'); var imRootNode = tree.getNodeById('SunriseIm'); tree.getLoader().on("loadexception", function (this1, node, response) { window.net_status = '_0'; if (!Ext.Msg.isVisible()) Ext.Msg.wait('网络出问题了,正在重新连接中....');; setTimeout(function () { imRootNode.reload(); }, 5000); }); tree.getLoader().on("load", function (this1, node, response) { Ext.Msg.hide(); if (window.net_status) { if (window.net_status == '_0') { window.net_status = '_1'; PL.state = 2; init_my_chat(); } } }); var query = location.search.substring(1); //获取查询串 var sessionId = SESSION; //Ext.urlDecode(query).sid; // 发送消息 function onMsg(content, sender, receivers) { var msg = '<div style="margin:20px 5px 10px 5px"> <img src="js/ext/user_comment.png"/> {0} <b>{1}</b> 对 <b>{2}</b> 说:<br></div>'; var chat_record = new Ext.Element(document.createElement('div')); chat_record.addClass('chat_record'); chat_record.update('<span style="margin:0px 5px 0px 5px">' + decodeURIComponent(content) + '</span>'); Ext.getCmp("history_panel").body.appendChild(chat_record); var canvas = new Ext.Element(document.createElement('canvas')); var size_chat = chat_record.getSize(); if (!Ext.isIE && size_chat.height < 100) { chat_record.setHeight(100); size_chat.height = 100; } canvas.setSize(size_chat.width - 30, size_chat.height); //canvas.setSize(size_chat.width-,40); chat_record.appendChild(canvas); if (window['G_vmlCanvasManager']) { G_vmlCanvasManager.initElement(canvas.dom); } google_dialog_draw_m(chat_record.dom.lastChild, '#FFB100'); var mc = String.format(((msg)), new Date().toLocaleString(), sender, receivers); Ext.getCmp("history_panel").body.insertHtml('beforeEnd', mc); Ext.getCmp("history_panel").body.scroll('b', 10000, { duration: 0.1 }); } function sendmsg() { Ext.getCmp("htmleditor").syncValue(); var content_value = Ext.getCmp("htmleditor").getValue(); if (content_value.trim() == '') { alert("您没有输入消息文本内容!"); Ext.getCmp("htmleditor").focus(true); return; } var receivers_values = []; var tree = Ext.getCmp('im-tree'); var receivers = tree.getSelectionModel().getSelectedNodes(); for (var i = 0; i < receivers.length; ++i) { receivers_values.push(receivers[i].attributes.loginId); } if (receivers_values.length == 0) { alert("您没有选择接收者!"); tree.focus(); return; } if (receivers_values.length > 1) { if (!confirm("您选择了多个接收者,是否继续?")) { return; } } for (var i = 0; i < receivers_values.length; i++) { p_publish('/CHAT/' + receivers_values[i], 'action', 'CHAT', 'msg', encodeURIComponent(encodeURIComponent(content_value)), 'sender', encodeURIComponent(CURRENTUSERID), 'receivers', encodeURIComponent(receivers_values.join(','))); } onMsg(encodeURIComponent(content_value), CURRENTUSERID, receivers_values); Ext.getCmp("htmleditor").reset(); } //event for source editing mode new Ext.KeyMap(Ext.getCmp("htmleditor").getEl(), [{ key: 13, ctrl: true, stopEvent: true, fn: sendmsg }]); //event for normal mode Ext.getCmp("htmleditor").onEditorEvent = function (e) { this.updateToolbar(); var keyCode = (document.layers) ? keyStroke.which : e.keyCode; if (keyCode == 13 && e.ctrlKey) sendmsg(); //it'a my handler } /* 对pushlet各种事件的处理 */ window.onError = function (event) { imRootNode.reload(); //PL.state = 2; //setTimeout(init_my_chat , 1000); /* var p_errortype = event.get('p_errortype'); //alert(p_errortype); if(p_errortype) { if(p_errortype == 'network') { PL.state = 2; setTimeout(p_join , 1000); //p_join(); //alert(PL.state); } } // alert(event.get('p_event') +' - error'); */ } window.onData = function (event) { var action = event.get('action'); //alert(action); if (action == 'CHAT') { var msg = event.get('msg'); var sender = event.get('sender'); var receivers = event.get('receivers').split(','); //if(sender == CURRENTUSERID) return; onMsg(msg, sender, receivers); if (!chatWin.isVisible()) { self.focus(); Ext.example.msg('叮当', '您有新的短消息 <a href="javascript:window.startChatWin()">查看</a>'); } } else if (action == 'USER') { var loginId = event.get('loginId'); var loginName = decodeURIComponent(event.get('loginName')); var c = imRootNode.childNodes; var i = 0; for (i = 0; i < c.length; i++) { if (c[i].attributes.loginId == loginId) break; } if (i == c.length) { imRootNode.appendChild({ loginId: loginId, leaf: true, iconCls: 'user', loginName: loginName, text: loginId + "(" + loginName + ")" }); } } else if (action == 'EXPIRE') { // Stop pushlet session p_leave(); // Give some time to send the leave request to server setTimeout(function () { alert('有人从其它地方登陆了,你被退出!'); window.location = 'index.jsp'; }, 1000); } else if (action == 'USERDEL') { var loginId = event.get('loginId'); var c = imRootNode.findChild('loginId', loginId); imRootNode.removeChild(c); } }; if (!Ext.isIE) { chatWin.collapse(); } function init_my_chat() { /* 监控各种事件源 */ p_join(); //监控发给自己的消息 p_listen('/CHAT/' + encodeURIComponent(CURRENTUSERID)); //监控自己是否在其他地方的登陆 p_listen('/EXPIREDSESSIONID/' + encodeURIComponent(SESSION)); //监控系统总的人数 p_listen('/USER'); //通知我来了 p_publish('/USER', 'action', 'USER', 'loginId', encodeURIComponent(CURRENTUSERID), 'loginName', encodeURIComponent((encodeURIComponent(CURRENTUSERNAME)))); } init_my_chat(); //失效的session id var expiredSessionIdStr = Ext.urlDecode(window.location.search.substring(1)); setTimeout(function () { //通知失效的sessionid窗口 if (expiredSessionIdStr.expiredSessionId) { p_publish('/EXPIREDSESSIONID/' + encodeURIComponent(expiredSessionIdStr.expiredSessionId), 'action', 'EXPIRE', 'expiredSessionId', encodeURIComponent(expiredSessionIdStr.expiredSessionId)); } }, 1000); window.startChatWin = function () { chatWin.show(); chatWin.center(); //Ext.getCmp('htmleditor').focus(); }; //心跳函数 五分钟更新一次,整体user数据,防止不按退出关闭浏览器 var chatTask = { run: function () { imRootNode.reload(); }, //scope:this, interval: 10 * 60 * 1000 //1 second }; time_pro = new Ext.util.TaskRunner(); time_pro.start(chatTask); function google_dialog_draw_m(canvas, color) { var context = canvas.getContext("2d"); var width = canvas.width; var height2 = canvas.height - 4.5; var height = canvas.height; context.beginPath(); context.strokeStyle = color; context.moveTo(0.5, 0.5 + 5); context.arc(5.5, 5.5, 5, -Math.PI, -Math.PI / 2, false); context.lineTo(width - 0.5 - 5, 0.5); context.arc(width - 0.5 - 5, 5.5, 5, -Math.PI / 2, 0, false); context.lineTo(width - 0.5, height2 - 5); context.arc(width - 0.5 - 5, height2 - 5, 5, 0, Math.PI / 2, false); context.lineTo(width / 2 + 3, height2); context.lineTo(width / 2, height); context.lineTo(width / 2 - 3, height2); context.lineTo(0.5 + 5, height2); context.arc(0.5 + 5, height2 - 5, 5, Math.PI / 2, Math.PI, false); context.lineTo(0.5, 0.5 + 5); context.stroke(); } });?
简单上述代码分析
?
还是很多人问我问题,我就简单解释一下上面代码,本来没打算做教程,只是自己记录一下的呀
报什么错啊,java那个替换好原来的java文件,在pushlet根目录要重新ant编译成一个jar,放在lib下面
ajax.js 放在头部
Ext.onReady 后进行其他处理
首先指明自己要监听的队列
init_my_chat 这个函数
发送消息就是往一个队列发送一个信号:
例如
p_publish('/CHAT/' + receivers_values[i], 'action', 'CHAT', 'msg', encodeURIComponent(encodeURIComponent(content_value)),?
?????????????? 'sender', encodeURIComponent(CURRENTUSERID), 'receivers', encodeURIComponent(receivers_values.join(',')));?
接收消息就是
对各种信号处理
:
window.onData = function(event)
代码不难的,要细致一点,出错也要告诉我具体的信息才行,用firebug 调试,java 要配置 log4j
?
?
补充说明:我用了你的Pushlet.java和ajax-pushlet-client.js;
WebRoot下新建了一个chat.jsp文件,导入的是ext-base.js、ext-all.js、ajax-pushlet-client.js,可是dataUrl: 'chat/getUserFirst.jsp' 这个文件在哪里呢?
这个是 取的用户列表的 jsp ,一般是 用 sessionlistener 保存到application
getUserFirst 取一下就行了
返回一个 json 数组
users.append(",{\n");
users.append("text:'" + loginId + "(" + loginName + ")" + "',\n");
users.append("loginId:'" + loginId + "',\n");
users.append("id:'user_" + s.getId() + "',\n");
users.append("loginName:'" + loginName + "',\n");
users.append("sessionId:'" + s.getId() + "',\n");
users.append("iconCls:'user',\n");
users.append(" singleClickExpand :true,\n");
users.append("leaf:true\n");
users.append("}\n");
我想参考一下,跪谢!!主要时间实在是不够了,我得新学struts2,spring,ibatis,还有ext。。还有comet。公司给定的题目。每天只有2小时可以学习。有种想跳楼的感觉了。。。
楼主,我怎么弄不不能让他跑起来。。。主要刚学没多久,毕业设计就要做带数据库的即时聊天。难度太大了。可以给我一份完整的代码吗?
我想参考一下,跪谢!!主要时间实在是不够了,我得新学struts2,spring,ibatis,还有ext。。还有comet。公司给定的题目。每天只有2小时可以学习。有种想跳楼的感觉了。。。
项目的一部分,后台分解太麻烦,我的建议:
关于pushlet你可以看看
http://www.matrix.org.cn/resource/article/2007-01-16/bcc2c490-a502-11db-8440-755941c7293d.html
后台请努力先看看简单的jsp即可 ,
ext 方面要多看自带的example
xiaoyu966 写道
楼主,我怎么弄不不能让他跑起来。。。主要刚学没多久,毕业设计就要做带数据库的即时聊天。难度太大了。可以给我一份完整的代码吗?我想参考一下,跪谢!!主要时间实在是不够了,我得新学struts2,spring,ibatis,还有ext。。还有comet。公司给定的题目。每天只有2小时可以学习。有种想跳楼的感觉了。。。项目的一部分,后台分解太麻烦,我的建议:关于pushlet你可以看看 http://www.matrix.org.cn/resource/article/2007-01-16/bcc2c490-a502-11db-8440-755941c7293d.html后台请努力先看看简单的jsp即可 ,ext 方面要多看自带的example
好的,谢谢你!
当时看它的源码好像写死了(编)解码方式,不依赖与服务器配置的话就是用encodeURIComponent 编码发送消息
服务器端程序再解码
这只是权且之计,效率不是很好
当时看它的源码好像写死了(编)解码方式,不依赖与服务器配置的话就是用encodeURIComponent 编码发送消息
服务器端程序再解码
这只是权且之计,效率不是很好
问题解决了,谢谢...
我都忘了,你再仔细看下,似乎代码直接用arguments引用其他参数的吧,不需要形参
我都忘了,你再仔细看下,似乎代码直接用arguments引用其他参数的吧,不需要形参
恩 是arguments引用其他参数。我现在看了好多帖子,但是好像也不知道怎么去写一个pushlet的例子,我下载了源码 在其中仔细看chat的那个示例,里面有一个ajax的js文件,还有一个js-pushlet-client的js文件,为什么会有两个。就是觉得东看看,西看看,就迷糊了,想问问你当时是如何看的,如何着手写第一个pushlet的示例,我现在不知道模仿哪个,麻烦了
我都忘了,你再仔细看下,似乎代码直接用arguments引用其他参数的吧,不需要形参
恩 是arguments引用其他参数。我现在看了好多帖子,但是好像也不知道怎么去写一个pushlet的例子,我下载了源码 在其中仔细看chat的那个示例,里面有一个ajax的js文件,还有一个js-pushlet-client的js文件,为什么会有两个。就是觉得东看看,西看看,就迷糊了,想问问你当时是如何看的,如何着手写第一个pushlet的示例,我现在不知道模仿哪个,麻烦了
给你两个链接仔细看下吧:
https://www.ibm.com/developerworks/cn/web/wa-lo-comet/
http://www.javaworld.com/jw-03-2000/jw-03-pushlet.html
我都忘了,你再仔细看下,似乎代码直接用arguments引用其他参数的吧,不需要形参
恩 是arguments引用其他参数。我现在看了好多帖子,但是好像也不知道怎么去写一个pushlet的例子,我下载了源码 在其中仔细看chat的那个示例,里面有一个ajax的js文件,还有一个js-pushlet-client的js文件,为什么会有两个。就是觉得东看看,西看看,就迷糊了,想问问你当时是如何看的,如何着手写第一个pushlet的示例,我现在不知道模仿哪个,麻烦了
给你两个链接仔细看下吧:
https://www.ibm.com/developerworks/cn/web/wa-lo-comet/
http://www.javaworld.com/jw-03-2000/jw-03-pushlet.html
谢谢。。。 再有不懂得再来请教
一般不上qq,可以直接站内信
好像没用的,一定要自己客户端encodeURIComponent进行编码
好像没用的,一定要自己客户端encodeURIComponent进行编码
pushlet传递中文有问题,页面什么都不显示!我的解决方法是后台编码,前台解码!详细见我博客!
好像没用的,一定要自己客户端encodeURIComponent进行编码
pushlet传递中文有问题,页面什么都不显示!我的解决方法是后台编码,前台解码!详细见我博客!
http://cuisuqiang.iteye.com/多指教