- 浏览: 1466343 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
luhouxiang:
写的很不错,学习了
Extjs 模块化动态加载js实践 -
kingkongtown:
如果想改成淘宝后台那样,可以在编辑器批量上传图片呢?
kissy editor 阶段体会 -
317966578:
兄弟我最近也在整jquery和caja 开放一些接口。在git ...
caja 原理 : 前端 -
liuweihug:
Javascript引擎单线程机制及setTimeout执行原 ...
setTimeout ,xhr,event 线程问题 -
辽主临轩:
怎么能让浏览器不进入 文档模式的quirks模式,进入标准的
浏览器模式与文本模式
前一篇 自己实现了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.zip (162 KB)
- 下载次数: 1870
评论
00:55:39,019 WARN pushlet:93 - S-0:0:0:0:0:0:0:1[1]: [Subscriber] not alive for at least: 45000ms, leaving...
00:55:39,020 INFO pushlet:79 - SessionManager: Thu Apr 04 00:55:39 CST 2013 1 at 0:0:0:0:0:0:0:1 removed
00:59:10,636 INFO pushlet:79 - SessionManager: Thu Apr 04 00:59:10 CST 2013 AgingTimerTask: Session expired: 0:0:0:0:0:0:0:1[5]
00:59:10,636 INFO pushlet:79 - SessionManager: Thu Apr 04 00:59:10 CST 2013 5 at 0:0:0:0:0:0:0:1 removed
好像没用的,一定要自己客户端encodeURIComponent进行编码
pushlet传递中文有问题,页面什么都不显示!我的解决方法是后台编码,前台解码!详细见我博客!
http://cuisuqiang.iteye.com/多指教
好像没用的,一定要自己客户端encodeURIComponent进行编码
pushlet传递中文有问题,页面什么都不显示!我的解决方法是后台编码,前台解码!详细见我博客!
好像没用的,一定要自己客户端encodeURIComponent进行编码
一般不上qq,可以直接站内信
我都忘了,你再仔细看下,似乎代码直接用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
我都忘了,你再仔细看下,似乎代码直接用arguments引用其他参数的吧,不需要形参
恩 是arguments引用其他参数。我现在看了好多帖子,但是好像也不知道怎么去写一个pushlet的例子,我下载了源码 在其中仔细看chat的那个示例,里面有一个ajax的js文件,还有一个js-pushlet-client的js文件,为什么会有两个。就是觉得东看看,西看看,就迷糊了,想问问你当时是如何看的,如何着手写第一个pushlet的示例,我现在不知道模仿哪个,麻烦了
我都忘了,你再仔细看下,似乎代码直接用arguments引用其他参数的吧,不需要形参
当时看它的源码好像写死了(编)解码方式,不依赖与服务器配置的话就是用encodeURIComponent 编码发送消息
服务器端程序再解码
这只是权且之计,效率不是很好
问题解决了,谢谢...
当时看它的源码好像写死了(编)解码方式,不依赖与服务器配置的话就是用encodeURIComponent 编码发送消息
服务器端程序再解码
这只是权且之计,效率不是很好
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
好的,谢谢你!
楼主,我怎么弄不不能让他跑起来。。。主要刚学没多久,毕业设计就要做带数据库的即时聊天。难度太大了。可以给我一份完整的代码吗?
我想参考一下,跪谢!!主要时间实在是不够了,我得新学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
发表评论
-
Extjs 实践细节备忘 -3
2009-04-12 20:26 24321. dragdrop 继承层次 dd - ... -
Extjs 实践细节备忘 -2
2009-04-12 05:43 27521. grid 列宽问题 可以指定 每列的宽度数值 ... -
Extjs 实践细节备忘 -1
2009-04-11 01:47 2713在使用 extjs 开发 OAOP 应用中 ,除了API文档外 ... -
长字串换行问题
2009-03-01 23:10 5789很久没用过 ,textarea ... -
Extjs portal 应用初探
2009-02-24 23:09 6009近期在研究拖放的实现 ,看了看 Extjs 的 portal ... -
Extjs 模块化动态加载js实践
2009-01-09 18:12 23509前一段转载了一篇 透明加载外部 javascript ... -
Extjs 聊天窗口 -续2 - http长连接的实现
2008-12-16 00:55 13336认为长连接就是有个http请求被服务器阻塞了 ,这样的话浏览 ... -
Extjs CRUD 模板
2008-12-12 00:52 7814也算是一个总结吧,备忘,总结了一个增删改查的例子,以后要达到的 ... -
Ext 聊天窗口的实现 - 续
2008-12-02 15:13 6703<filter> <fil ... -
Ext 树操作
2008-11-10 23:21 4505后台 树 节点 定义 menu_info { ... -
Ext 一个聊天窗口的设计
2008-11-10 00:26 37751.关键是要 弹性设计,自动适应浏览器 部件要: ... -
Ext.data.Store 与 GridFilters
2008-11-03 16:12 5368Store 每次 reload 会记着上次的参数,比如 pa ... -
Ext 实现 文件上传 进度显示
2008-10-24 18:15 5203利用了 ahxu-commons-fileuploadex-b ... -
Ext official doc - class-event-observer
2008-10-23 18:20 1441....ppt -
Ext 多文件上传面板扩展
2008-10-23 16:53 8383扩展了 Ext.Panel ,加入文件框列表 ,并控制删 ... -
Ext Grid 表头显示问题
2008-09-27 23:51 3346出现问题了,当 Grid div 放在 table 布局下的话 ... -
JSON marsh && unmarsh
2008-09-23 00:46 1989Ext 端用 //Encodes an Objec ... -
[extjs] formpanel 标准提交问题
2008-09-19 02:29 3339formpanel 的 标准提交 有 bug? var ta ... -
ComboBox 传值问题
2008-09-19 00:07 5301field -> textfield->trigg ... -
Ext 2 概述
2008-09-18 01:11 2301欢迎来到Ext 2.0。 在下列各章节中,你将会接触到E ...
相关推荐
标题中的“Extjs 聊天窗口 -续2 - http长连接的实现”指的是一个关于使用Extjs构建聊天窗口,并且实现HTTP长连接的技术分享。Extjs是一个流行的JavaScript框架,常用于开发富客户端应用程序,而HTTP长连接是解决传统...
ExtJs常用布局--layout详解实例代码: ExtJs常见的布局方式有:border、form、absolute、column、accordion、table、fit、card、anchor 另外,不常见的布局有:tab、vbox、hbox 具体使用方法可见该文件的案例代码。 ...
3. **UI组件**:ExtJS 提供了众多预定义的UI组件,如按钮、表格、面板、菜单等。6.2.0版本可能添加了新的组件,或者对现有组件进行了视觉和功能上的升级,以满足更广泛的设计需求。 4. **表单处理**:ExtJS 对表单...
extjs-620-docs官方文档extjs-620-docs官方文档extjs-620-docs官方文档
同时,如果需要自定义主题,可以通过修改 Sass 文件来实现,这样可以保持代码的可维护性和可扩展性。 总之,"extjs-theme-bootstrap" 是一个将 EXTJS4 的功能性和 Bootstrap 的美观设计结合的主题,为开发者提供了...
语言程序设计资料:ExtJs学习笔记-2积分.doc
在标题"extjs2----关于extjs 的使用,操作"中,我们可以看出这是一份关于ExtJS 2.0版本的使用指南,主要涵盖了其基本操作和应用。描述中提到内容较为初级,适合初学者学习,这表明我们将探讨的是ExtJS的基础概念和...
在IT行业中,ExtJS是一个广泛使用的JavaScript库,用于构建富客户端的Web应用程序。它提供了丰富的组件库,包括数据网格(Grid)等,使得开发者能够创建交互性极强的数据展示和管理界面。这篇“ExtJS笔记——Grid...
在IT行业中,构建实时通信系统是一项常见的挑战,而"pushlet+extjs实现聊天组"这一主题正是针对这个问题提供的一种解决方案。Pushlet和ExtJS分别是两个关键的技术组件,它们共同作用于创建一个简易的聊天组应用。 ...
ExtJS快速入门--传智播客--蔡世友
extJs-5.0.1-gpl附带sencha cmd安装程序、ruby编译包(分为32位和64位)和教程,一共四部分
为了在项目中使用这个主题,开发者需要按照文档指示将主题文件引入到他们的ExtJS应用中,并可能需要配置一些设置来确保所有组件都应用了正确的样式。同时,由于标签中提到了"Delphi",这可能意味着这个主题包也考虑...
一个extjs的OA项目 extjs-OA extjs-oaextjs-OA extjs-oa
【标题】:“Pushlet+ExtJS实现的聊天组”是一个基于特定技术栈构建的在线实时通信系统,旨在提供一种简洁的多人交流环境。Pushlet是一个轻量级的服务器端组件,用于实现实时数据推送,而ExtJS则是一个强大的前端...
总的来说,这个项目涵盖了ExtJS 4的ComboBox组件使用、事件监听、数据绑定,以及Struts2框架的Action处理、JSON数据交互等技术。通过这种方式,我们可以构建一个动态、交互性强的省市区选择功能,既满足了用户操作的...
licensing@extjs.com http://extjs.com/license Open Source License Ext is licensed under the terms of the Open Source GPL 3.0 license. http://www.gnu.org/licenses/gpl.html There are several FLOSS ...
总结起来,这个"ExtJS-MVC-用户列表实例"展示了如何使用ExtJS的MVC架构来构建一个功能完整的Web应用,包括定义数据模型、创建视图来展示数据、设置控制器来处理用户交互,以及利用Store进行数据管理。同时,...
在"ExtJS----HelloWorld程序源码"中,我们将会看到如何使用ExtJS来创建一个简单的“你好,世界!”应用。以下是对这个示例中涉及的主要知识点的详细解释: 1. **引入ExtJS库**:首先,你需要在HTML文件中引入ExtJS...