`
yiminghe
  • 浏览: 1460482 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Extjs 聊天窗口 -续3 用pushlet来实现

阅读更多

       前一篇 自己实现了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

 

 

分享到:
评论
11 楼 xiaoyu966 2009-03-29  
楼主,我怎么弄不不能让他跑起来。。。主要刚学没多久,毕业设计就要做带数据库的即时聊天。难度太大了。可以给我一份完整的代码吗?
我想参考一下,跪谢!!主要时间实在是不够了,我得新学struts2,spring,ibatis,还有ext。。还有comet。公司给定的题目。每天只有2小时可以学习。有种想跳楼的感觉了。。。
10 楼 yiminghe 2009-03-01  
xuxy03 写道

补充说明:我用了你的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");
9 楼 xuxy03 2009-02-25  
补充说明:我用了你的Pushlet.java和ajax-pushlet-client.js;
WebRoot下新建了一个chat.jsp文件,导入的是ext-base.js、ext-all.js、ajax-pushlet-client.js,可是dataUrl: 'chat/getUserFirst.jsp' 这个文件在哪里呢?
8 楼 xuxy03 2009-02-25  
你好,我运行阁下的程序,遇到的问题是:
1.不需要配置sources.properties文件吗?
2.页面总是显示“网络出问题了,正在连接中”,不知何故。

初学pushlet,恳请赐教!
7 楼 yiminghe 2009-02-07  
chris45 写道

我明白了,十分感谢,已经解决了,现在 我有个问题,我把pushlet放到了另外一台服务器,也就必须跨域调用pushlet.srv,这在ajax里面是会报错的,不知道你是否有试验过

ajax 不能跨域访问的 ,基础常识 。。。。。这个不关pushlet啥事了

6 楼 chris45 2009-01-14  
我明白了,十分感谢,已经解决了,现在 我有个问题,我把pushlet放到了另外一台服务器,也就必须跨域调用pushlet.srv,这在ajax里面是会报错的,不知道你是否有试验过
5 楼 yiminghe 2009-01-13  
yiminghe 写道

chris45 写道我照着你的代码设置了怎么不行呢?发送消息后对方并没有能接收到?请指教要把原来pushlet包里的servlet/pushlet.java 里换成我给的 ,他是处理post xml的我改成post和get一样处理了还要配置 web.xml&lt;servlet&gt; &lt;servlet-name&gt;pushlet&lt;/servlet-name&gt; &lt;servlet-class&gt;nl.justobjects.pushlet.servlet.Pushlet&lt;/servlet-class&gt; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt; &lt;/servlet&gt; &lt;servlet-mapping&gt; &lt;servlet-name&gt;pushlet&lt;/servlet-name&gt; &lt;url-pattern&gt;/pushlet.srv&lt;/url-pattern&gt; &lt;/servlet-mapping&gt;



ajax-client.js 也要用我给的 ,pushlet.java 替换掉 原来包里的源代码 ,ant server
后 用 pushlet.jar 放在web-inf/lib 下面
4 楼 yiminghe 2009-01-13  
chris45 写道

我照着你的代码设置了怎么不行呢?发送消息后对方并没有能接收到?请指教

要把原来pushlet包里的servlet/pushlet.java 里换成我给的 ,他是处理post xml的

我改成post和get一样处理了

还要配置 web.xml

<servlet>
<servlet-name>pushlet</servlet-name>
<servlet-class>nl.justobjects.pushlet.servlet.Pushlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>pushlet</servlet-name>
<url-pattern>/pushlet.srv</url-pattern>
</servlet-mapping>
3 楼 chris45 2009-01-12  
我照着你的代码设置了怎么不行呢?发送消息后对方并没有能接收到?请指教
2 楼 yiminghe 2009-01-08  
larry838 写道

辛苦了。我也正在学习。楼主能给一份源代码吗(可以跑起来的)?谢谢
email:larry838@gmail.com


该有的源代码我都给了啊

只要加上extjs2.2 的库,建立一个空页面导入 我发的chatwin.js
pushlet的相关js ,sevlet

就可以运行了

后台我没写任何代码 ,pushlet 我就把它当成一个 数据仓库加控制分发管理
数据塞给他,他再转发给该给的人

1 楼 larry838 2008-12-24  
辛苦了。我也正在学习。楼主能给一份源代码吗(可以跑起来的)?谢谢
email:larry838@gmail.com

相关推荐

    Extjs 聊天窗口 -续2 - http长连接的实现

    标题中的“Extjs 聊天窗口 -续2 - http长连接的实现”指的是一个关于使用Extjs构建聊天窗口,并且实现HTTP长连接的技术分享。Extjs是一个流行的JavaScript框架,常用于开发富客户端应用程序,而HTTP长连接是解决传统...

    ExtJs常用布局--layout详解实例代码

    ExtJs常用布局--layout详解实例代码: ExtJs常见的布局方式有:border、form、absolute、column、accordion、table、fit、card、anchor 另外,不常见的布局有:tab、vbox、hbox 具体使用方法可见该文件的案例代码。 ...

    extjs-620-docs.zip

    extjs-620-docs官方文档extjs-620-docs官方文档extjs-620-docs官方文档

    extjs-theme-bootstrap

    同时,如果需要自定义主题,可以通过修改 Sass 文件来实现,这样可以保持代码的可维护性和可扩展性。 总之,"extjs-theme-bootstrap" 是一个将 EXTJS4 的功能性和 Bootstrap 的美观设计结合的主题,为开发者提供了...

    语言程序设计资料:ExtJs学习笔记-2积分.doc

    语言程序设计资料:ExtJs学习笔记-2积分.doc

    extjs2----关于extjs 的使用,操作

    在标题"extjs2----关于extjs 的使用,操作"中,我们可以看出这是一份关于ExtJS 2.0版本的使用指南,主要涵盖了其基本操作和应用。描述中提到内容较为初级,适合初学者学习,这表明我们将探讨的是ExtJS的基础概念和...

    ExtJS笔记---Grid实现后台分页

    在IT行业中,ExtJS是一个广泛使用的JavaScript库,用于构建富客户端的Web应用程序。它提供了丰富的组件库,包括数据网格(Grid)等,使得开发者能够创建交互性极强的数据展示和管理界面。这篇“ExtJS笔记——Grid...

    pushlet+extjs实现聊天组

    在IT行业中,构建实时通信系统是一项常见的挑战,而"pushlet+extjs实现聊天组"这一主题正是针对这个问题提供的一种解决方案。Pushlet和ExtJS分别是两个关键的技术组件,它们共同作用于创建一个简易的聊天组应用。 ...

    ExtJS快速入门--传智播客--蔡世友

    ExtJS快速入门--传智播客--蔡世友

    extJs-5.0.1-gpl(part1)

    extJs-5.0.1-gpl附带sencha cmd安装程序、ruby编译包(分为32位和64位)和教程,一共四部分

    extjs-theme-bootstrap-master.zip

    为了在项目中使用这个主题,开发者需要按照文档指示将主题文件引入到他们的ExtJS应用中,并可能需要配置一些设置来确保所有组件都应用了正确的样式。同时,由于标签中提到了"Delphi",这可能意味着这个主题包也考虑...

    extjs-OA extjs-oa

    一个extjs的OA项目 extjs-OA extjs-oaextjs-OA extjs-oa

    pushlet+extjs实现的聊天组

    【标题】:“Pushlet+ExtJS实现的聊天组”是一个基于特定技术栈构建的在线实时通信系统,旨在提供一种简洁的多人交流环境。Pushlet是一个轻量级的服务器端组件,用于实现实时数据推送,而ExtJS则是一个强大的前端...

    Extjs4---combobox省市区三级联动+struts2

    总的来说,这个项目涵盖了ExtJS 4的ComboBox组件使用、事件监听、数据绑定,以及Struts2框架的Action处理、JSON数据交互等技术。通过这种方式,我们可以构建一个动态、交互性强的省市区选择功能,既满足了用户操作的...

    Extjs-ext-3.1.1

    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-用户列表实例"展示了如何使用ExtJS的MVC架构来构建一个功能完整的Web应用,包括定义数据模型、创建视图来展示数据、设置控制器来处理用户交互,以及利用Store进行数据管理。同时,...

    ExtJS----HelloWorld程序源码

    在"ExtJS----HelloWorld程序源码"中,我们将会看到如何使用ExtJS来创建一个简单的“你好,世界!”应用。以下是对这个示例中涉及的主要知识点的详细解释: 1. **引入ExtJS库**:首先,你需要在HTML文件中引入ExtJS...

    Extjs6.2 生成的admin-dashboard官方模板

    Extjs6.2 生成的admin-dashboard官方模板

    ExtJS-4.2.2-gpl.rar

    ExtJS 是一个强大的JavaScript 框架,专用于构建富客户端Web应用程序。它提供了一整套组件、工具和API,使开发者能够创建功能丰富的、交互性强的用户界面。本资源"ExtJS-4.2.2-gpl.rar"是ExtJS 4.2.2的开源版本,...

Global site tag (gtag.js) - Google Analytics