以及需要用到http方式和openfire通信的第三方库(jabberhttpbind)。
jabberhttpbind是jabber提供的xmpp协议通信的http bind发送的形式,它可以完成webbrowser和openfire建立长连接通信。
主要通信流程如下图所示:
用户a通过javascript jsjac.js库发送一条消息到jabberhttpbind这个servlet容器,然后jabberhttpbind的servlet容器会向openfire发送xmpp协议的xml报文。openfire server接收到报文后解析,然后发送给指定的用户b。jabberhttpbind获取到openfire server发送的数据后,解析报文向当前servlet容器中的链接的session中找到指定的用户再发送数据给用户b。
webbrowser端用的是jsjac和jabberhttpbind建立的连接,所有数据都要经过jabberhttpbind解析/转换发送给openfire。
先上张图看看效果,呵呵~这里是用户hoojo和girl的聊天画面,双方在进行互聊……
可以发送表情、改变字体样式(对方界面也可以看到你的字体样式),同时右侧是显示/收缩详情的信息
收缩详情
聊天界面部分截图
用户登录、注册,sendto表示你登录后向谁发送聊天消息、并且建立一个聊天窗口
登录成功后,你可以在日志控制台看到你的登陆状态、或是在firebug控制台中看到你的连接请求状态
登陆失败
只有connecting,就没有下文了
登陆成功后,你就可以给指定用户发送消息,且设置你想发送消息的新用户点击new chat按钮创建新会话
如果你来了新消息,在浏览器的标题栏会有新消息提示
如果你当前聊天界面的窗口都是关闭状态,那么在右下角会有消息提示的闪动图标
这里已经贴出了所有的源代码了,如果你非常的需要源代码(但我希望你能自己创建一个工程去复制源代码,这是我希望看到的),那么你可以通过以下方式联系我
email:hoojo_@126.com
blog:http://blog.csdn.net/ibm_hoojo
http://hoojo.cnblogs.com/
http://hoojo.blogjava.net
注:我不会保证在第一时间给你代码,但我会在空闲的时间给你发送源码
开发环境
system:windows
javaee server:tomcat 5.0.28+/tomcat 6
webbrowser:ie6+、firefox3.5+、chrome 已经兼容浏览器
javasdk:jdk 1.6+
openfire 3.7.1
ide:eclipse 3.2、myeclipse 6.5
开发依赖库
jdk1.4+
serializer.jar
xalan.jar
jhb-1.0.jar
log4j-1.2.16.jar
jhb-1.0.jar 这个就是jabberhttpbind,我把编译的class打成jar包了
javascript lib
jquery.easydrag.js 窗口拖拽javascript lib
jquery-1.7.1.min.js jquery lib
jsjac.js 通信核心库
local.chat-2.0.js 本地会话窗口发送消息javascript库
remote.jsjac.chat-2.0.js 远程会话消息javascript库
send.message.editor-1.0.js 窗口编辑器javascript库
一、准备工作
jsjac javascript lib下载:https://github.com/sstrigler/jsjac/
如果你不喜欢用jsjac javascript lib和openfire通信,那么有一款jquery的plugin可以供你使用,下载地址
jquery-xmpp-plugin https://github.com/maxpowel/jquery-xmpp-plugin
这里有所以能支持openfire通信的第三方库,有兴趣的可以研究下 http://xmpp.org/xmpp-software/libraries/
jquery.easydrag 下载:http://fromvega.com/code/easydrag/jquery.easydrag.js
jquery 下载:http://code.jquery.com/jquery-1.7.1.min.js
jabberhttpbind jhb.jar 下载:http://download.csdn.net/detail/ibm_hoojo/4489188
images 图片素材:http://download.csdn.net/detail/ibm_hoojo/4489439
工程目录结构
二、核心代码演示
1、主界面(登陆、消息提示、日志、建立新聊天窗口)代码 index.jsp
复制代码 代码如下:
string path = request.getcontextpath();
string basepath = request.getscheme()+://+request.getservername()+:+request.getserverport()+path+/;
%>
webim chat
username:
password:
register:
sendto:
user:
sendto:
下面这段代码尤为重要,它是设置你链接openfire的地址。这个地址一段错误你将无法进行通信!
复制代码 代码如下:
$.webim方法是主函数,用它可以覆盖local.chat中的基本配置,它可以完成聊天窗口的创建。$.webim.newwebim方法是新创建一个窗口,只是消息的接收者是一个新用户。
复制代码 代码如下:
$.webim({
sender: username,
receiver: receiver
});
$.webim.newwebim({
receiver: receiver
});
remote.jsjac.chat.login(document.userform);方法是用户登录到openfire服务器
参数如下:
httpbase: window.contextpath + /jhb/, //请求后台http-bind服务器url
domain: window[serverdomin], //192.168.5.231, // 192.168.5.231 当前有效域名
username: , // 登录用户名
pass: , // 密码
timerval: 2000, // 设置请求超时
resource: webim, // 链接资源标识
register: true // 是否注册
remote.jsjac.chat.logout();是退出、断开openfire的链接
2、本地聊天应用核心代码 local.chat-2.0.js
复制代码 代码如下:
/***
* jquery local chat
* @version v2.0
* @createdate -- 2012-5-28
* @author hoojo
* @email hoojo_@126.com
* @blog http://hoojo.cnblogs.com & http://blog.csdn.net/ibm_hoojo
* @requires jquery v1.2.3 or later, send.message.editor-1.0.js
* copyright (c) 2012 m. hoo
**/
;(function ($) {
if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
alert('webim requires jquery v1.2.3 or later! you are using v' + $.fn.jquery);
return;
}
var facetimed, count = 0;
var _opts = defaultoptions = {
version: 2.0,
chat: #chat,
chatel: function () {
var $chat = _opts.chat;
if ((typeof _opts.chat) == string) {
$chat = $(_opts.chat);
} else if ((typeof _opts.chat) == object) {
if (!$chat.get(0)) {
$chat = $($chat);
}
}
return $chat;
},
sendmessageiframe: function (receiverid) {
return $(iframe[name='sendmessage + receiverid + ']).get(0).contentwindow;
},
receivemessagedoc: function (receiverid) {
receiverid = receiverid || ;
var docs = [];
$.each($(iframe[name^='receivemessage + receiverid + ']), function () {
docs.push($(this.contentwindow.document));
});
return docs;
//return $($(iframe[name^='receivemessage + receiverid + ']).get(0).contentwindow.document);
},
sender: , // 发送者
receiver: , // 接收者
settitle: function (chatel) {
var receiver = this.getreceiver(chatel);
chatel.find(.title).html(和 + receiver + 聊天对话中);
},
getreceiver: function (chatel) {
var receiver = chatel.attr(receiver);
if (~receiver.indexof(@)) {
receiver = receiver.split(@)[0];
}
return receiver;
},
// 接收消息iframe样式
receivestyle: [
'',
'',
'',
''
].join(),
writereceivestyle: function (receiverid) {
this.receivemessagedoc(receiverid)[0].get(0).write(this.receivestyle);
},
datetimeformat: function (v) {
if (~~v return 0 + v;
}
return v;
},
getdatetime: function () {
// 设置当前发送日前
var date = new date();
var datetime = date.getfullyear() + - + date.getmonth() + - + date.getdate();
datetime = + _opts.datetimeformat(date.gethours())
+ : + _opts.datetimeformat(date.getminutes())
+ : + _opts.datetimeformat(date.getseconds());
return datetime;
},
/***
* 发送消息的格式模板
* flag = true 表示当前user是自己,否则就是对方
**/
receivemessagetpl: function (username, styletpl, content, flag) {
var usercls = flag ? me : you;
if (styletpl && flag) {
content = [ , content, ].join();
}
return [
'', _opts.getdatetime(), ' ', username, ':
',
'', content, '
'
].join();
},
// 工具类按钮触发事件返回html模板
sendmessagestyle: {
cssstyle: {
bold: font-weight: bold;,
underline: text-decoration: underline;,
italic: font-style: oblique;
},
setstyle: function (style, val) {
if (val) {
_opts.sendmessagestyle[style] = val;
} else {
var styleval = _opts.sendmessagestyle[style];
if (styleval === undefined || !styleval) {
_opts.sendmessagestyle[style] = true;
} else {
_opts.sendmessagestyle[style] = false;
}
}
},
getstyletpl: function () {
var tpl = ;
$.each(_opts.sendmessagestyle, function (style, item) {
//alert(style + # + item + # + (typeof item));
if (item === true) {
tpl += _opts.sendmessagestyle.cssstyle[style];
} else if ((typeof item) === string) {
//alert(style + ------------- + sendmessagestyle[style]);
tpl += style + : + item + ;;
}
});
return tpl;
}
},
// 向接收消息iframe区域写消息
writereceivemessage: function (receiverid, username, content, flag) {
if (content) {
// 发送消息的样式
var styletpl = _opts.sendmessagestyle.getstyletpl();
var receivemessagedoc = _opts.receivemessagedoc(receiverid);
$.each(receivemessagedoc, function () {
var $body = this.find(body);
// 向接收信息区域写入发送的数据
$body.append(_opts.receivemessagetpl(username, styletpl, content, flag));
// 滚动条滚到底部
this.scrolltop(this.height());
});
}
},
// 发送消息
sendhandler: function ($chatmain) {
var doc = $chatmain.find(iframe[name^='sendmessage']).get(0).contentwindow.document;
var content = doc.body.innerhtml;
content = $.trim(content);
content = content.replace(new regexp(
, gm), );
// 获取即将发送的内容
if (content) {
var sender = $chatmain.attr(sender);
var receiverid = $chatmain.attr(id);
// 接收区域写消息
_opts.writereceivemessage(receiverid, sender, content, true);
//############# xxx
var receiver = $chatmain.find(#to).val();
//var receiver = $chatmain.attr(receiver);
// 判断是否是手机端会话,如果是就发送纯text,否则就发送html代码
var flag = _opts.ismobileclient(receiver);
if (flag) {
var text = $(doc.body).text();
text = $.trim(text);
if (text) {
// 远程发送消息
remote.jsjac.chat.sendmessage(text, receiver);
}
} else { // 非手机端通信 可以发送html代码
var styletpl = _opts.sendmessagestyle.getstyletpl();
content = [ , content, ].join();
remote.jsjac.chat.sendmessage(content, receiver);
}
// 清空发送区域
$(doc).find(body).html();
}
},
faceimagepath: images/emotions/,
faceeltpl: function (i) {
return [
this.faceimagepath,%20
(i%20-%201),%20
%22fixed.bmp gif=',
this.faceimagepath,
(i - 1),
.gif'>
].join();
},
// 创建表情html elements
createfaceelement: function ($chat) {
var faces = [];
for (var i = 1; i faces.push(this.faceeltpl(i));
if (i % 11 == 0) {
faces.push(
);
}
}
$chat.find(#face).html(faces.join());
this.facehandler($chat);
},
// 插入表情
facehandler: function ($chat) {
$chat.find(#face img).click(function () {
$chat.find(#face).hide(150);
var imgel = ;
var $chatmain = $(this).parents(.chat-main);
var win = $chatmain.find(iframe[name^='sendmessage']).get(0).contentwindow;
var doc = win.document;
sendmessageeditor.insertatcursor(imgel, doc, win);
});
// 表情隐藏
$chat.find(#face, #face img).mouseover(function () {
window.cleartimeout(facetimed);
}).mouseout(function () {
window.cleartimeout(facetimed);
facetimed = window.settimeout(function () {
$chat.find(#face).hide(150);
}, 700);
});
},
/***
* 发送消息工具栏按钮事件方法
**/
toolbarhandler: function () {
var $chat = $(this).parents(.chat-main);
var targetcls = $(this).attr(class);
if (targetcls == face) {
$chat.find(#face).show(150);
window.cleartimeout(facetimed);
facetimed = window.settimeout(function () {
$chat.find(#face).hide(150);
}, 1000);
} else if (this.tagname == div) {
_opts.sendmessagestyle.setstyle(targetcls);
} else if (this.tagname == select) {
_opts.sendmessagestyle.setstyle($(this).attr(name), $(this).val());
if ($(this).attr(name) == color) {
$(this).css(background-color, $(this).val());
}
}
// 设置sendmessage iframe的style css
_opts.writesendstyle();
},
// 设置sendmessage iframe的style css
writesendstyle: function () {
var styletpl = _opts.sendmessagestyle.getstyletpl();
var styleel = [''].join();
$(body).find(iframe[name^='sendmessage']).each(function () {
var $head = $(this.contentwindow.document).find(head);
if ($head.find(style).size() > 1) {
$head.find(style:gt(0)).remove();
}
if (styletpl) {
$head.append(styleel);
}
});
},
ismobileclient: function (receiver) {
var moblieclients = [iphone, ipad, ipod, wp7, android, blackberry, spark, warning, symbian];
var flag = false;
for (var i in moblieclients) {
if (~receiver.indexof(moblieclients[i])) {
return true;
}
}
return false;
},
// 聊天界面html元素
chatlayouttemplate: function (userjid, sender, receiver, product, flag) {
var display = ;
if (flag) {
display = style=max-width:90%;
}
return [
'',
'',
'',
'',
' ',
'
',
'',
'',
'',
' ',
' ',
'',
'',
'商品详情
',
'',
'',
'', product.name, '',
'团购价:', product.price, '元',
'市场价:', product.marketprice, '元',
'快递公司:', product.deliverorgs, '',
'仓库:', product.warehouses, '',
product.skuattrs,
'',
' ',
'
',
'',
'',
'',
'宋体',
'黑体',
'幼圆',
'华文行楷',
'华文楷体',
'华文楷体',
'华文彩云',
'华文隶书',
'微软雅黑',
'fixedsys',
'',
'',
'大小',
'10',
'12',
'14',
'16',
'18',
'20',
'24',
'28',
'36',
'42',
'52',
'',
'',
'颜色',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'
',
'
',
'
',
'
',
'消息记录
',
' ',
'
',
'',
'',
'',
' ',
'
',
'',
'',
' ',
'
',
'
',
'
',
'
',
'
'
].join();
},
initwebim: function (userjid, receiver) {
var product = {
name: 小玩熊,
pic: http://avatar.csdn.net/9/7/a/2_ibm_hoojo.jpg,
price: 198.00,
marketprice: 899.90,
deliverorgs: ems,
warehouses: a库,
skuattrs:
};
var chatel = $(_opts.chatlayouttemplate(userjid, _opts.sender, receiver, product));
$(body).append(chatel);
// 拖拽
$(# + userjid).easydrag();
// 初始化sendmessageeditor相关信息
sendmessageeditor.iframe = this.sendmessageiframe(userjid);
sendmessageeditor.init(userjid);
_opts.settitle(chatel);
_opts.writereceivestyle(userjid);
_opts.writesendstyle();
_opts.createfaceelement(chatel);
// 查看更多详情
chatel.find(.more).click(function () {
var $ul = $(this).parents(ul);
$ul.find(.more).toggle();
$ul.find(.info).toggle();
$ul.find(.pic).toggle();
});
// 收缩详情
chatel.find(.split).toggle(function () {
$(.product-info).hide();
$(this).parents(.radius).css(border-right-width, 0);
}, function () {
$(.product-info).show();
$(this).parents(.radius).css(border-right-width, 8px);
});
// 工具类绑定事件 settings.toolbarhandler
chatel.find(.tool-bar td).children().click(this.toolbarhandler);
chatel.find(#send).click(function () {
var $chatmain = $(this).parents(.chat-main);
_opts.sendhandler($chatmain);
});
chatel.find(#close).click(function () {
var $chatmain = $(this).parents(.chat-main);
$chatmain.hide(500);
});
// 首先取消事件绑定,当一次性发多条消息的情况下会同时绑定多个相同事件
$(.have-msg, .no-msg, .chat-main).unbind(click);
$(.have-msg).bind(click, function () {
$(this).hide();
$(.no-msg).show();
$(.chat-main:hidden).show(150);
});
$(.no-msg).click(function () {
$(.chat-main:hidden).each(function (i, item) {
var top = i * 10 + 50;
var left = i * 20 + 50;
$(this).show(500).css({top: top, left: left});
});
});
$(.chat-main).click(function () {
$(.chat-main).css(z-index, 9999);
$(this).css({z-index: 10000});
});
$(this.sendmessageiframe(userjid).document).keyup(function (event) {
var e = event || window.event;
var keycode = e.which || e.keycode;
if (keycode == 13) {
var $chatmain = $(# + $(this).find(body).attr(jid));
_opts.sendhandler($chatmain);
}
});
},
// 建立新聊天窗口
newwebim: function (settings) {
var chatuser = remote.useraddress(settings.receiver);
var userjid = u + hex_md5(chatuser);
_opts.initwebim(userjid, chatuser);
$(# + userjid).find(remote.receiver).val(chatuser);
$(# + userjid).show(220);
},
// 远程发送消息时执行函数
messagehandler: function (user, content) {
var username = user.split(@)[0];
var tempuser = user;
if (~tempuser.indexof(/)) {
tempuser = tempuser.substr(0, tempuser.indexof(/));
}
var userjid = u + hex_md5(tempuser);
// 首次初始webim
if (!$(# + userjid).get(0)) {
// 初始im面板;
_opts.initwebim(userjid, user);
}
// 设置消息接受者的名称
$(# + userjid).find(remote.receiver).val(user);
if ($(# + userjid).get(0)) {
// 消息提示
if ($(div[id=' + userjid + ']:hidden).get(0)) {
var havemessage = $(.have-msg);
havemessage.show();
$(.no-msg).hide();
}
_opts.messagetip(闪聊有了新消息,请查收!);
// 向chat接收信息区域写消息
remote.jsjac.chat.writemessage(userjid, username, content);
}
},
// 消息提示
messagetip: function () {
if (count % 2 == 0) {
window.focus();
document.title = 你来了新消息,请查收!;
} else {
document.title = ;
}
if (count > 4) {
document.title = ;
count = 0;
} else {
window.settimeout(_opts.messagetip, 1000);
count ++;
}
}
};
// 初始化远程聊天程序相关方法
var initremoteim = function (settings) {
// 初始化远程消息
remote.jsjac.chat.init();
// 设置客户端写入信息方法
remote.jsjac.chat.writereceivemessage = settings.writereceivemessage;
// 注册事件
$(window).bind({
unload: remote.jsjac.chat.unloadhandler,
error: remote.jsjac.chat.errorhandler,
beforeunload: remote.jsjac.chat.logout
});
}
$.extend({
webim: function (opts) {
opts = opts || {};
// 覆盖默认配置
defaultoptions = $.extend(defaultoptions, defaultoptions, opts);
var settings = $.extend({}, defaultoptions, opts);
initremoteim(settings);
settings.newwebim(settings);
$.webim.settings = settings;
}
});
$.webim.settings = $.webim.settings || _opts;
$.webim.initwebim = _opts.initwebim;
$.webim.newwebim = _opts.newwebim;
$.webim.messagehandler = _opts.messagehandler;
})(jquery);
这里的方法基本上是聊天窗口上的应用,主要是本地聊天程序的js、html元素的操作。如字体、字体大小、颜色、表情、消息的发送等,不涉及到聊天消息发送的核心代码,其中有用到发送远程消息的方法。
remote.jsjac.chat.sendmessage(text, receiver); 这个是发送远程消息的方法,参数1是消息内容、参数2是消息的接收者
如果你有看到这篇文章http://www.cnblogs.com/hoojo/archive/2012/06/18/2553886.html 它是一个单纯的webim本地的聊天界面。
3、远程聊天javascript核心代码,它是和jsjac库关联的。
remote.jsjac.chat-2.0.js
复制代码 代码如下:
/**
* im chat jsjac remote message
* @author: hoojo
* @email: hoojo_@126.com
* @blog http://hoojo.cnblogs.com & http://blog.csdn.net/ibm_hoojo
* @createdate: 2012-5-24
* @version 2.0
* @requires jquery v1.2.3 or later
* copyright (c) 2012 m. hoo
**/
var remote = {
debug: info, error,
chat: body,
receiver: #to, // 接受者jquery expression
console: {
errorel: function () {
if ($(remote.chat).get(0)) {
return $(remote.chat).find(#error);
} else {
return $(body).find(#error);
}
},
infoel: function () {
if ($(remote.chat).get(0)) {
return $(remote.chat).find(#info);
} else {
return $(body).find(#info);
}
},
// debug info
info: function (html) {
if (~remote.debug.indexof(info)) {
remote.console.infoel().append(html);
remote.console.infoel().get(0).lastchild.scrollintoview();
}
},
// debug error
error: function (html) {
if (~remote.debug.indexof(error)) {
remote.console.errorel().append(html);
}
},
// clear info/debug console
clear: function (s) {
if (debug == s) {
remote.console.errorel().html();
} else {
remote.console.infoel().html();
}
}
},
useraddress: function (user) {
if (user) {
if (!~user.indexof(@)) {
user += @ + remote.jsjac.domain;// + / + remote.jsjac.resource;
} else if (~user.indexof(/)) {
user = user.substr(0, user.indexof(/));
}
}
return user;
},
jsjac: {
httpbase: window.contextpath + /jhb/, //请求后台http-bind服务器url
domain: window[serverdomin], //192.168.5.231, // 192.168.5.231 当前有效域名
username: ,
pass: ,
timerval: 2000, // 设置请求超时
resource: webim, // 链接资源标识
register: true // 是否注册
}
};
remote.jsjac.chat = {
writereceivemessage: function () {
},
setstate: function () {
var onlinestatus = new object();
onlinestatus[available] = 在线;
onlinestatus[chat] = 欢迎聊天;
onlinestatus[away] = 离开;
onlinestatus[xa] = 不可用;
onlinestatus[dnd] = 请勿打扰;
onlinestatus[invisible] = 隐身;
onlinestatus[unavailable] = 离线;
remote.jsjac.chat.state = onlinestatus;
return onlinestatus;
},
state: null,
init: function () {
// debugger plugin
if (typeof (debugger) == function) {
remote.dbger = new debugger(2, remote.jsjac.resource);
remote.dbger.start();
} else {
// if you're using firebug or safari, use this for debugging
// odbg = new jsjacconsolelogger(2);
// comment in above and remove comments below if you don't need debugging
remote.dbger = function () {
};
remote.dbger.log = function () {
};
}
try {
// try to resume a session
if (jsjaccookie.read(btype).getvalue() == binding) {
remote.connection = new jsjachttpbindingconnection({ odbg: remote.dbger});
rdbgerjac.chat.setupevent(remote.connection);
if (remote.connection.resume()) {
remote.console.clear(debug);
}
}
} catch (e) {
remote.console.errorel().html(e.name + : + e.message);
} // reading cookie failed - never mind
remote.jsjac.chat.setstate();
},
login: function (loginform) {
remote.console.clear(debug); // reset
try {
// 链接参数
var connectionconfig = remote.jsjac;
// debugger console
if (typeof (odbg) != undefined) {
connectionconfig.odbg = odbg;
}
var connection = new jsjachttpbindingconnection(connectionconfig);
remote.connection = connection;
// 安装(注册)connection事件模型
remote.jsjac.chat.setupevent(connection);
// setup args for connect method
if (loginform) {
//connectionconfig = new object();
//connectionconfig.domain = loginform.domain.value;
connectionconfig.username = loginform.username.value;
connectionconfig.pass = loginform.password.value;
connectionconfig.register = loginform.register.checked;
}
// 连接服务器
connection.connect(connectionconfig);
//remote.jsjac.chat.changestatus(available, online, 1, chat);
} catch (e) {
remote.console.errorel().html(e.tostring());
} finally {
return false;
}
},
// 改变用户状态
changestatus: function (type, status, priority, show) {
type = type || unavailable;
status = status || online;
priority = priority || 1;
show = show || chat;
var presence = new jsjacpresence();
presence.settype(type); // unavailable invisible
if (remote.connection) {
//remote.connection.send(presence);
}
//presence = new jsjacpresence();
presence.setstatus(status); // online
presence.setpriority(priority); // 1
presence.setshow(show); // chat
if (remote.connection) {
remote.connection.send(presence);
}
},
// 为connection注册事件
setupevent: function (con) {
var remotechat = remote.jsjac.chat;
con.registerhandler('message', remotechat.handlemessage);
con.registerhandler('presence', remotechat.handlepresence);
con.registerhandler('iq', remotechat.handleiq);
con.registerhandler('onconnect', remotechat.handleconnected);
con.registerhandler('onerror', remotechat.handleerror);
con.registerhandler('status_changed', remotechat.handlestatuschanged);
con.registerhandler('ondisconnect', remotechat.handledisconnected);
con.registeriqget('query', ns_version, remotechat.handleiqversion);
con.registeriqget('query', ns_time, remotechat.handleiqtime);
},
// 发送远程消息
sendmessage: function (msg, to) {
try {
if (msg == ) {
return false;
}
var user = ;
if (to) {
if (!~to.indexof(@)) {
user += @ + remote.jsjac.domain;
to += / + remote.jsjac.resource;
} else if (~to.indexof(/)) {
user = to.substr(0, to.indexof(/));
}
} else {
// 向chat接收信息区域写消息
if (remote.jsjac.chat.writereceivemessage) {
var html = 你没有指定发送者的名称;
alert(html);
//remote.jsjac.chat.writereceivemessage(receiverid, server, html, false);
}
return false;
}
var userjid = u + hex_md5(user);
$(# + userjid).find(remote.receiver).val(to);
// 构建jsjac的message对象
var message = new jsjacmessage();
message.setto(new jsjacjid(to));
message.settype(chat); // 单独聊天,默认为广播模式
message.setbody(msg);
// 发送消息
remote.connection.send(message);
return false;
} catch (e) {
var html = error: + e.message +
;
remote.console.info(html);
return false;
}
},
// 退出、断开链接
logout: function () {
var presence = new jsjacpresence();
presence.settype(unavailable);
if (remote.connection) {
remote.connection.send(presence);
remote.connection.disconnect();
}
},
errorhandler: function (event) {
var e = event || window.event;
remote.console.errorel().html(e);
if (remote.connection && remote.connection.connected()) {
remote.connection.disconnect();
}
return false;
},
unloadhandler: function () {
var con = remote.connection;
if (typeof con != undefined && con && con.connected()) {
// save backend type
if (con._hold) { // must be binding
(new jsjaccookie(btype, binding)).write();
}
if (con.suspend) {
con.suspend();
}
}
},
writemessage: function (userjid, username, content) {
// 向chat接收信息区域写消息
if (remote.jsjac.chat.writereceivemessage && !!content) {
remote.jsjac.chat.writereceivemessage(userjid, username, content, false);
}
},
// 重新连接服务器
reconnection: function () {
remote.jsjac.register = false;
if (remote.connection.connected()) {
remote.connection.disconnect();
}
remote.jsjac.chat.login();
},
/* ########################### handler event ############################# */
handleiq: function (aiq) {
var html = in (raw): + aiq.xml().htmlenc() +
;
remote.console.info(html);
remote.connection.send(aiq.errorreply(err_feature_not_implemented));
},
handlemessage: function (ajsjacpacket) {
var user = ajsjacpacket.getfromjid().tostring();
//var username = user.split(@)[0];
//var userjid = u + hex_md5(user);
var content = ajsjacpacket.getbody();
var html = ;
html += 消息来自 + user + :
;
html += content.htmlenc() +
;
remote.console.info(html);
$.webim.messagehandler(user, content);
},
handlepresence: function (ajsjacpacket) {
var user = ajsjacpacket.getfromjid();
var username = user.tostring().split(@)[0];
var html = ;
if (!ajsjacpacket.gettype() && !ajsjacpacket.getshow()) {
html += + username + 上线了.;
} else {
html += + username + 设置 presence 为: ;
if (ajsjacpacket.gettype()) {
html += ajsjacpacket.gettype() + .;
} else {
html += ajsjacpacket.getshow() + .;
}
if (ajsjacpacket.getstatus()) {
html += ( + ajsjacpacket.getstatus().htmlenc() + );
}
}
html +=
;
remote.console.info(html);
// 向chat接收信息区域写消息
remote.jsjac.chat.writemessage(, username, html);
},
handleerror: function (event) {
var e = event || window.event;
var html = an error occured:
+ (code: + e.getattribute(code)
+ \ntype: + e.getattribute(type)
+ \ncondition: + e.firstchild.nodename).htmlenc();
remote.error(html);
var content = ;
switch (e.getattribute(code)) {
case 401:
content = 登陆验证失败!;
break;
// 当注册发现重复,表明该用户已经注册,那么直接进行登陆操作
case 409:
//content = 注册失败!\n请换一个用户名!;
remote.jsjac.chat.reconnection();
break;
case 503:
content = 无法连接到im服务器,请检查相关配置!;
break;
case 500:
var contents = 服务器内部错误!\n\n连接断开!
重新连接;
remote.jsjac.chat.writemessage(, 系统, contents);
break;
default:
break;
}
if (content) {
alert(weim: + content);
}
if (remote.connection.connected()) {
remote.connection.disconnect();
}
},
// 状态变化触发事件
handlestatuschanged: function (status) {
remote.console.info(当前用户状态: + status +
);
remote.dbger.log(当前用户状态: + status);
if (status == disconnecting) {
var html = 你离线了!;
// 向chat接收信息区域写消息
remote.jsjac.chat.writemessage(, 系统, html);
}
},
// 建立链接触发事件方法
handleconnected: function () {
remote.console.clear(debug); // reset
remote.connection.send(new jsjacpresence());
},
// 断开链接触发事件方法
handledisconnected: function () {
},
handleiqversion: function (iq) {
remote.connection.send(iq.reply([
iq.buildnode(name, remote.jsjac.resource),
iq.buildnode(version, jsjac.version),
iq.buildnode(os, navigator.useragent)
]));
return true;
},
handleiqtime: function (iq) {
var now = new date();
remote.connection.send(iq.reply([
iq.buildnode(display, now.tolocalestring()),
iq.buildnode(utc, now.jabberdate()),
iq.buildnode(tz, now.tolocalestring().substring(now.tolocalestring().lastindexof( ) + 1))
]));
return true;
}
};
这个文件的代码就是用jsjac库和openfire建立通信的核心代码,代码中已经有注释,这里我就不再赘述。如果有什么不懂的可以给我留言。
4、消息区域、编辑器代码 send.message.editor-1.0.js
复制代码 代码如下:
/**
* im chat send message iframe editor
* @author: hoojo
* @email: hoojo_@126.com
* @blog: http://blog.csdn.net/ibm_hoojo
* @createdate: 2012-5-24
* @version 1.0
**/
var agent = window.navigator.useragent.tolowercase();
var sendmessageeditor = {
// 获取iframe的window对象
getwin: function () {
return /*!/firefox/.test(agent)*/false ? sendmessageeditor.iframe.contentwindow : window.frames[sendmessageeditor.iframe.name];
},
//获取iframe的document对象
getdoc: function () {
return !/firefox/.test(agent) ? sendmessageeditor.getwin().document : (sendmessageeditor.iframe.contentdocument || sendmessageeditor.getwin().document);
},
init: function (userjid) {
//打开document对象,向其写入初始化内容,以兼容firefox
var doc = sendmessageeditor.getdoc();
doc.open();
var html = [
'',
'',
'',
''].join();
doc.write(html);
//打开document对象编辑模式
doc.designmode = on;
doc.close();
},
getcontent: function () {
var doc = sendmessageeditor.getdoc();
//获取编辑器的body对象
var body = doc.body || doc.documentelement;
//获取编辑器的内容
var content = body.innerhtml;
//对内容进行处理,例如替换其中的某些特殊字符等等
//some code
//返回内容
return content;
},
//统一的执行命令方法
execcmd: function (cmd, value, d){
var doc = d || sendmessageeditor.getdoc();
//doc对象的获取参照上面的代码
//调用execcommand方法执行命令
doc.execcommand(cmd, false, value === undefined ? null : value);
},
getstylestate: function (cmd) {
var doc = sendmessageeditor.getdoc();
//doc对象的获取参考上面的对面
//光标处是否是粗体
var state = doc.querycommandstate(cmd);
if(state){
//改变按钮的样式
}
return state;
},
insertatcursor: function (text, d, w){
var doc = d || sendmessageeditor.getdoc();
var win = w || sendmessageeditor.getwin();
//win对象的获取参考上面的代码
if (/msie/.test(agent)) {
win.focus();
var r = doc.selection.createrange();
if (r) {
r.collapse(true);
r.pastehtml(text);
}
} else if (/gecko/.test(agent) || /opera/.test(agent)) {
win.focus();
sendmessageeditor.execcmd('inserthtml', text, doc);
} else if (/safari/.test(agent)) {
sendmessageeditor.execcmd('inserttext', text, doc);
}
}
};
5、css样式 chat-2.0.css
复制代码 代码如下:
/**
* function: im web chat css
* author: hoojo
* createdate: 2012-5-26 上午11:42:10
*/
@charset utf-8;
*, body {
font-family: courier,serif,monospace;
font-size: 12px;
padding: 0;
margin: 0;
}
.chat-main {
position: absolute;
/*right: 80px;*/
left: 50px;
top: 20px;
z-index: 999;
display: none;
}
.chat-main .radius {
background-color: white;
border: 8px solid #94cadf;
border-radius: 1em;
}
#chat {
position: relative;
/*left: 150px;*/
padding: 0;
margin: 0;
}
#chat table {
border-collapse: collapse;
width: 435px;
*width: 460px;
/*width: 410px;*/
/*width: 320px;*/
}
#chat table .title {
font-weight: bold;
color: green;
padding: 3px;
background-color: #94cadf;
}
/* 收缩条 */
#chat table .split {
background-color: #94cadf;
cursor: pointer;
}
/* ################## product info #################### */
#chat table .product-info {
width: 30%;
/*display: none;*/
padding: 0;
margin: 0;
vertical-align: top;
}
#chat table .product-info ul {
margin: 0;
padding: 0;
}
#chat table .product-info ul div.header {
background-color: #ebeffe;
line-height: 22px;
font-size: 12px;
color: black;
}
#chat table .product-info ul li {
list-style: none outside none;
background-color: white;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
padding-left: 5px;
line-height: 22px;
font-size: 11px;
color: #6f6f6f;
width: 140px;
}
#chat table .product-info ul li.pic {
height: 200px;
padding: 0 5px 0 5px;
border: 1px dashed #ccc;
text-align: center;
}
#chat table .product-info ul li.pic img {
}
#chat table .product-info ul li.product-name {
font-weight: bold;
color: black;
}
#chat table .product-info ul li.price span {
font-family: courier;
font-size: 16px;
font-weight: bold;
color: #ed4e08;
}
#chat table .product-info ul li.market-price s {
color: black;
}
#chat table .product-info ul li a {
float: right;
}
#chat table .product-info ul li.info {
display: none;
}
/*########### 接收消息区域 ############ */
#chat table .receive-message {
height: 250px;
}
#chat table .send-message {
width: 100%;
/*height: auto;*/
}
#chat table td {
/*border: 1px solid white;*/
}
#chat table .bottom-bar {
background-color: #94cadf;
text-align: right;
}
/* ############## 工具条 ################# start */
#chat table .tool-bar {
height: 25px;
background-color: #94cadf;
}
#chat table .tool-bar select {
float: left;
}
#chat table .tool-bar select.family {
width: 45px;
*width: 55px;
}
#chat table .tool-bar div {
width: 17px;
height: 16px;
float: left;
cursor: pointer;
margin-right: 2px;
margin-top: 1px;
*margin-top: 2px;
background: transparent url(../images/tb-sprite.gif) no-repeat scroll 0 0;
}
#chat table .tool-bar .color {
margin-left: 2px;
background-position: -159px 0;
}
#chat table .tool-bar .bold {
/*background-position: 0 0;*/
}
#chat table .tool-bar .italic {
background-position: -18px 0;
}
#chat table .tool-bar .underline {
background-position: -32px 0;
}
#chat table .tool-bar .face {
margin: 2px 0 0 3px;
background-image: url(../images/facehappy.gif);
}
#chat table .tool-bar .history {
background-image: none;
width: 60px;
float: right;
margin-top: 3px;
font-size: 12px;
display: none;
}
/* ###### 表情 ###### */
#chat #face {
border: 1px solid black;
width: 275px;
*width: 277px;
position: relative;
left: 8px;
top: -370px;
_top: -359px;
z-index: 3;
display: none;
}
#chat #face img {
border: 1px solid #ccc;
border-right: none;
border-bottom: none;
cursor: pointer;
}
#send {
width: 90px;
height: 25px;
}
#close {
width: 40px;
height: 25px;
}
.chat-message {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 25px;
background-color: #fcfcfc;
}
.no-msg, .have-msg {
cursor: pointer;
float: right;
margin: 5px 5px 0 0;
}
6、web.xml配置
复制代码 代码如下:
xmlns:xsi=http://www.w3.org/2001/xmlschema-instance
xsi:schemalocation=http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd>
jabber http binding servlet
org.jabber.jabberhttpbind.jhbservlet
jabber http binding servlet
/jhb/
index.jsp
至此,这个应用的全部代码已经贴出来,如果你按照我这边的结构形式应该是可以完成这个聊天应用的。如果你有什么问题或想法,欢迎你给我留言或评论!