前一篇 自己实现了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
本文介绍如何使用ExtJS和Pushlet实现实时聊天应用,包括单点登录、用户状态通知等功能。通过Post方式提交数据并解决中文编码问题。
7347

被折叠的 条评论
为什么被折叠?



