这篇文章主要介绍用JavaScript和jQuery、HTML、CSS以及用第三方聊天JavaScript(jsjac)框架构建一个BS Web的聊天应用程序。此程序可以和所有连接到Openfire服务器的应用进行通信、发送消息。如果要运行本程序还需要一个聊天服务器Openfire,

以及需要用到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

注:我不会保证在第一时间给你代码,但我会在空闲的时间给你发送源码

导读

如果你对openfire还不是很了解或是不知道安装,建议你看看这2篇文章

http://www.cnblogs.com/hoojo/archive/2012/05/17/2506769.html

http://www.cnblogs.com/hoojo/archive/2012/05/13/2498151.html

因为这里还用到了JabberHTTPBind 以及在使用它或是运行示例的时候会遇到些问题,那么你可以看看这篇文章

http://www.cnblogs.com/hoojo/archive/2012/05/17/2506845.html

开发环境

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

  1. <%@ page language="java" pageEncoding="UTF-8" %>
  2. <%
  3. String path = request.getContextPath();
  4. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  5. %>
  6. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  7. <html>
  8. <head>
  9. <base href="<%=basePath%>">
  10. <title>WebIM Chat</title>
  11. <meta http-equiv="pragma" content="no-cache">
  12. <meta http-equiv="cache-control" content="no-cache">
  13. <meta http-equiv="expires" content="0">
  14. <meta http-equiv="author" content="hoojo">
  15. <meta http-equiv="email" content="hoojo_@126.com">
  16. <meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo">
  17. <meta http-equiv="blog" content="http://hoojo.cnblogs.com">
  18. <link rel="stylesheet" type="text/css" href="css/chat-2.0.css" />
  19. <script type="text/javascript">
  20. window.contextPath = "<%=path%>";
  21. window["serverDomin"] = "192.168.8.22";
  22. </script>
  23. <script type="text/javascript" src="jslib/jquery-1.7.1.min.js"></script>
  24. <script type="text/javascript" src="jslib/jsjac.js"></script>
  25. <!-- script type="text/javascript" src="debugger/Debugger.js"></script-->
  26. <script type="text/javascript" src="jslib/send.message.editor-1.0.js"></script>
  27. <script type="text/javascript" src="jslib/jquery.easydrag.js"></script>
  28. <script type="text/javascript" src="jslib/remote.jsjac.chat-2.0.js"></script>
  29. <script type="text/javascript" src="jslib/local.chat-2.0.js"></script>
  30. <script type="text/javascript">
  31. $(function () {
  32. $("#login").click(function () {
  33. var userName = $(":text[name='userName']").val();
  34. var receiver = $("*[name='to']").val();
  35. // 建立一个聊天窗口应用,并设置发送者和消息接收者
  36. $.WebIM({
  37. sender: userName,
  38. receiver: receiver
  39. });
  40. // 登陆到openfire服务器
  41. remote.jsjac.chat.login(document.userForm);
  42. $("label").text(userName);
  43. $("form").hide();
  44. $("#newConn").show();
  45. });
  46. $("#logout").click(function () {
  47. // 退出openfire登陆,断开链接
  48. remote.jsjac.chat.logout();
  49. $("form").show();
  50. $("#newConn").hide();
  51. $("#chat").hide(800);
  52. });
  53. $("#newSession").click(function () {
  54. var receiver = $("#sendTo").val();
  55. // 建立一个新聊天窗口,并设置消息接收者(发送给谁?)
  56. $.WebIM.newWebIM({
  57. receiver: receiver
  58. });
  59. });
  60. });
  61. </script>
  62. </head>
  63. <body>
  64. <!-- 登陆表单 -->
  65. <form name="userForm" style="background-color: #fcfcfc; width: 100%;">
  66. userName:<input type="text" name="userName" value="boy"/>
  67. password:<input type="password" name="password" value="boy"/>
  68. register: <input type="checkbox" name="register"/>
  69. sendTo: <input type="text" id="to" name="to" value="hoojo" width="10"/>
  70. <input type="button" value="Login" id="login"/>
  71. </form>
  72. <!-- 新窗口聊天 -->
  73. <div id="newConn" style="display: none; background-color: #fcfcfc; width: 100%;">
  74. User:<label></label>
  75. sendTo: <input type="text" id="sendTo" value="hoojo" width="10"/>
  76. <input type="button" value="new Chat" id="newSession"/>
  77. <input type="button" value="Logout" id="logout"/>
  78. </div>
  79. <!-- 日志信息 -->
  80. <div id="error" style="display: ; background-color: red;"></div>
  81. <div id="info" style="display: ; background-color: #999999;"></div>
  82. <!-- 聊天来消息提示 -->
  83. <div class="chat-message">
  84. <img src="images/write_icon.png" class="no-msg"/>
  85. <img src="images/write_icon.gif" class="have-msg" style="display: none;"/>
  86. </div>
  87. </body>
  88. </html>

下面这段代码尤为重要,它是设置你链接openfire的地址。这个地址一段错误你将无法进行通信!

  1. <script type="text/javascript">
  2. window.contextPath = "<%=path%>";
  3. window["serverDomin"] = "192.168.8.22";
  4. </script>

$.WebIM方法是主函数,用它可以覆盖local.chat中的基本配置,它可以完成聊天窗口的创建。$.WebIM.newWebIM方法是新创建一个窗口,只是消息的接收者是一个新用户。

  1. $.WebIM({
  2. sender: userName,
  3. receiver: receiver
  4. });
  5. $.WebIM.newWebIM({
  6. receiver: receiver
  7. });

remote.jsjac.chat.login(document.userForm);方法是用户登录到Openfire服务器

参数如下:

  1. httpbase: window.contextPath + "/JHB/", //请求后台http-bind服务器url
  2. domain: window["serverDomin"], //"192.168.5.231", // 192.168.5.231 当前有效域名
  3. username: "", // 登录用户名
  4. pass: "", // 密码
  5. timerval: 2000, // 设置请求超时
  6. resource: "WebIM", // 链接资源标识
  7. register: true // 是否注册

remote.jsjac.chat.logout();是退出、断开openfire的链接

2、本地聊天应用核心代码 local.chat-2.0.js

  1. /***
  2. * jquery local chat
  3. * @version v2.0
  4. * @createDate -- 2012-5-28
  5. * @author hoojo
  6. * @email hoojo_@126.com
  7. * @blog http://hoojo.cnblogs.com & http://blog.csdn.net/IBM_hoojo
  8. * @requires jQuery v1.2.3 or later, send.message.editor-1.0.js
  9. * Copyright (c) 2012 M. hoo
  10. **/
  11. ;(function ($) {
  12. if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
  13. alert('WebIM requires jQuery v1.2.3 or later! You are using v' + $.fn.jquery);
  14. return;
  15. }
  16. var faceTimed, count = 0;
  17. var _opts = defaultOptions = {
  18. version: 2.0,
  19. chat: "#chat",
  20. chatEl: function () {
  21. var $chat = _opts.chat;
  22. if ((typeof _opts.chat) == "string") {
  23. $chat = $(_opts.chat);
  24. } else if ((typeof _opts.chat) == "object") {
  25. if (!$chat.get(0)) {
  26. $chat = $($chat);
  27. }
  28. }
  29. return $chat;
  30. },
  31. sendMessageIFrame: function (receiverId) {
  32. return $("iframe[name='sendMessage" + receiverId + "']").get(0).contentWindow;
  33. },
  34. receiveMessageDoc: function (receiverId) {
  35. receiverId = receiverId || "";
  36. var docs = [];
  37. $.each($("iframe[name^='receiveMessage" + receiverId + "']"), function () {
  38. docs.push($(this.contentWindow.document));
  39. });
  40. return docs;
  41. //return $($("iframe[name^='receiveMessage" + receiverId + "']").get(0).contentWindow.document);
  42. },
  43. sender: "", // 发送者
  44. receiver: "", // 接收者
  45. setTitle: function (chatEl) {
  46. var receiver = this.getReceiver(chatEl);
  47. chatEl.find(".title").html("和" + receiver + "聊天对话中");
  48. },
  49. getReceiver: function (chatEl) {
  50. var receiver = chatEl.attr("receiver");
  51. if (~receiver.indexOf("@")) {
  52. receiver = receiver.split("@")[0];
  53. }
  54. return receiver;
  55. },
  56. // 接收消息iframe样式
  57. receiveStyle: [
  58. '<html>',
  59. '<head><style type="text/css">',
  60. 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;background-color:white;font-size:12px;font-family:Courier,serif,monospace;}',
  61. '.msg{margin-left: 1em;}p{margin:0;padding:0;}.me{color: blue;}.you{color:green;}',
  62. '</style></head>',
  63. '<body></body>',
  64. '</html>'
  65. ].join(""),
  66. writeReceiveStyle: function (receiverId) {
  67. this.receiveMessageDoc(receiverId)[0].get(0).write(this.receiveStyle);
  68. },
  69. datetimeFormat: function (v) {
  70. if (~~v < 10) {
  71. return "0" + v;
  72. }
  73. return v;
  74. },
  75. getDatetime: function () {
  76. // 设置当前发送日前
  77. var date = new Date();
  78. var datetime = date.getFullYear() + "-" + date.getMonth() + "-" + date.getDate();
  79. datetime = " " + _opts.datetimeFormat(date.getHours())
  80. + ":" + _opts.datetimeFormat(date.getMinutes())
  81. + ":" + _opts.datetimeFormat(date.getSeconds());
  82. return datetime;
  83. },
  84. /***
  85. * 发送消息的格式模板
  86. * flag = true 表示当前user是自己,否则就是对方
  87. **/
  88. receiveMessageTpl: function (userName, styleTpl, content, flag) {
  89. var userCls = flag ? "me" : "you";
  90. if (styleTpl && flag) {
  91. content = [ "<span style='", styleTpl, "'>", content, "</span>" ].join("");
  92. }
  93. return [
  94. '<p class="', userCls, '">', _opts.getDatetime(), ' ', userName, ':</p>',
  95. '<p class="msg">', content, '</p>'
  96. ].join("");
  97. },
  98. // 工具类按钮触发事件返回html模板
  99. sendMessageStyle: {
  100. cssStyle: {
  101. bold: "font-weight: bold;",
  102. underline: "text-decoration: underline;",
  103. italic: "font-style: oblique;"
  104. },
  105. setStyle: function (style, val) {
  106. if (val) {
  107. _opts.sendMessageStyle[style] = val;
  108. } else {
  109. var styleVal = _opts.sendMessageStyle[style];
  110. if (styleVal === undefined || !styleVal) {
  111. _opts.sendMessageStyle[style] = true;
  112. } else {
  113. _opts.sendMessageStyle[style] = false;
  114. }
  115. }
  116. },
  117. getStyleTpl: function () {
  118. var tpl = "";
  119. $.each(_opts.sendMessageStyle, function (style, item) {
  120. //alert(style + "#" + item + "#" + (typeof item));
  121. if (item === true) {
  122. tpl += _opts.sendMessageStyle.cssStyle[style];
  123. } else if ((typeof item) === "string") {
  124. //alert(style + "-------------" + sendMessageStyle[style]);
  125. tpl += style + ":" + item + ";";
  126. }
  127. });
  128. return tpl;
  129. }
  130. },
  131. // 向接收消息iframe区域写消息
  132. writeReceiveMessage: function (receiverId, userName, content, flag) {
  133. if (content) {
  134. // 发送消息的样式
  135. var styleTpl = _opts.sendMessageStyle.getStyleTpl();
  136. var receiveMessageDoc = _opts.receiveMessageDoc(receiverId);
  137. $.each(receiveMessageDoc, function () {
  138. var $body = this.find("body");
  139. // 向接收信息区域写入发送的数据
  140. $body.append(_opts.receiveMessageTpl(userName, styleTpl, content, flag));
  141. // 滚动条滚到底部
  142. this.scrollTop(this.height());
  143. });
  144. }
  145. },
  146. // 发送消息
  147. sendHandler: function ($chatMain) {
  148. var doc = $chatMain.find("iframe[name^='sendMessage']").get(0).contentWindow.document;
  149. var content = doc.body.innerHTML;
  150. content = $.trim(content);
  151. content = content.replace(new RegExp("<br>", "gm"), "");
  152. // 获取即将发送的内容
  153. if (content) {
  154. var sender = $chatMain.attr("sender");
  155. var receiverId = $chatMain.attr("id");
  156. // 接收区域写消息
  157. _opts.writeReceiveMessage(receiverId, sender, content, true);
  158. //############# XXX
  159. var receiver = $chatMain.find("#to").val();
  160. //var receiver = $chatMain.attr("receiver");
  161. // 判断是否是手机端会话,如果是就发送纯text,否则就发送html代码
  162. var flag = _opts.isMobileClient(receiver);
  163. if (flag) {
  164. var text = $(doc.body).text();
  165. text = $.trim(text);
  166. if (text) {
  167. // 远程发送消息
  168. remote.jsjac.chat.sendMessage(text, receiver);
  169. }
  170. } else { // 非手机端通信 可以发送html代码
  171. var styleTpl = _opts.sendMessageStyle.getStyleTpl();
  172. content = [ "<span style='", styleTpl, "'>", content, "</span>" ].join("");
  173. remote.jsjac.chat.sendMessage(content, receiver);
  174. }
  175. // 清空发送区域
  176. $(doc).find("body").html("");
  177. }
  178. },
  179. faceImagePath: "images/emotions/",
  180. faceElTpl: function (i) {
  181. return [
  182. "<img src='",
  183. this.faceImagePath,
  184. (i - 1),
  185. "fixed.bmp' gif='",
  186. this.faceImagePath,
  187. (i - 1),
  188. ".gif'/>"
  189. ].join("");
  190. },
  191. // 创建表情html elements
  192. createFaceElement: function ($chat) {
  193. var faces = [];
  194. for (var i = 1; i < 100; i++) {
  195. faces.push(this.faceElTpl(i));
  196. if (i % 11 == 0) {
  197. faces.push("<br/>");
  198. }
  199. }
  200. $chat.find("#face").html(faces.join(""));
  201. this.faceHandler($chat);
  202. },
  203. // 插入表情
  204. faceHandler: function ($chat) {
  205. $chat.find("#face img").click(function () {
  206. $chat.find("#face").hide(150);
  207. var imgEL = "<img src='" + $(this).attr("gif") + "'/>";
  208. var $chatMain = $(this).parents(".chat-main");
  209. var win = $chatMain.find("iframe[name^='sendMessage']").get(0).contentWindow;
  210. var doc = win.document;
  211. sendMessageEditor.insertAtCursor(imgEL, doc, win);
  212. });
  213. // 表情隐藏
  214. $chat.find("#face, #face img").mouseover(function () {
  215. window.clearTimeout(faceTimed);
  216. }).mouseout(function () {
  217. window.clearTimeout(faceTimed);
  218. faceTimed = window.setTimeout(function () {
  219. $chat.find("#face").hide(150);
  220. }, 700);
  221. });
  222. },
  223. /***
  224. * 发送消息工具栏按钮事件方法
  225. **/
  226. toolBarHandler: function () {
  227. var $chat = $(this).parents(".chat-main");
  228. var targetCls = $(this).attr("class");
  229. if (targetCls == "face") {
  230. $chat.find("#face").show(150);
  231. window.clearTimeout(faceTimed);
  232. faceTimed = window.setTimeout(function () {
  233. $chat.find("#face").hide(150);
  234. }, 1000);
  235. } else if (this.tagName == "DIV") {
  236. _opts.sendMessageStyle.setStyle(targetCls);
  237. } else if (this.tagName == "SELECT") {
  238. _opts.sendMessageStyle.setStyle($(this).attr("name"), $(this).val());
  239. if ($(this).attr("name") == "color") {
  240. $(this).css("background-color", $(this).val());
  241. }
  242. }
  243. // 设置sendMessage iframe的style css
  244. _opts.writeSendStyle();
  245. },
  246. // 设置sendMessage iframe的style css
  247. writeSendStyle: function () {
  248. var styleTpl = _opts.sendMessageStyle.getStyleTpl();
  249. var styleEL = ['<style type="text/css">body{', styleTpl,'}</style>'].join("");
  250. $("body").find("iframe[name^='sendMessage']").each(function () {
  251. var $head = $(this.contentWindow.document).find("head");
  252. if ($head.find("style").size() > 1) {
  253. $head.find("style:gt(0)").remove();
  254. }
  255. if (styleTpl) {
  256. $head.append(styleEL);
  257. }
  258. });
  259. },
  260. isMobileClient: function (receiver) {
  261. var moblieClients = ["iphone", "ipad", "ipod", "wp7", "android", "blackberry", "Spark", "warning", "symbian"];
  262. var flag = false;
  263. for (var i in moblieClients) {
  264. if (~receiver.indexOf(moblieClients[i])) {
  265. return true;
  266. }
  267. }
  268. return false;
  269. },
  270. // 聊天界面html元素
  271. chatLayoutTemplate: function (userJID, sender, receiver, product, flag) {
  272. var display = "";
  273. if (flag) {
  274. display = "style='display: none;'";
  275. }
  276. return [
  277. '<div class="chat-main" id="', userJID,
  278. '" sender="', sender, '" receiver="', receiver, '">',
  279. '<div id="chat"><div class="radius">',
  280. '<table>',
  281. '<tr>',
  282. '<td colspan="3" class="title"></td>',
  283. '</tr>',
  284. '<tr>',
  285. '<td class="receive-message">',
  286. '<iframe name="receiveMessage', userJID,'" frameborder="0" width="100%" height="100%"></iframe>',
  287. '</td>',
  288. '<td rowspan="4" class="split" ', display, '> </td>',
  289. '<td rowspan="4" class="product-info" ', display, '>',
  290. '<ul>',
  291. '<div class="header"> 商品详情</div>',
  292. '<li class="pic">',
  293. '<img src="', product.pic, '"/></li>',
  294. '<li class="product-name">', product.name, '</li>',
  295. '<li class="price">团购价:<span>', product.price, '</span>元</li>',
  296. '<li class="market-price">市场价:<s><i>', product.marketPrice, '</i></s>元</li>',
  297. '<li>快递公司:', product.deliverOrgs, '</li>',
  298. '<li>仓库:', product.wareHouses, '</li>',
  299. product.skuAttrs,
  300. '</ul>',
  301. '</td>',
  302. '</tr>',
  303. '<tr class="tool-bar">',
  304. '<td>',
  305. '<select name="font-family" class="family">',
  306. '<option>宋体</option>',
  307. '<option>黑体</option>',
  308. '<option>幼圆</option>',
  309. '<option>华文行楷</option>',
  310. '<option>华文楷体</option>',
  311. '<option>华文楷体</option>',
  312. '<option>华文彩云</option>',
  313. '<option>华文隶书</option>',
  314. '<option>微软雅黑</option>',
  315. '<option>Fixedsys</option>',
  316. '</select>',
  317. '<select name="font-size">',
  318. '<option value="12px">大小</option>',
  319. '<option value="10px">10</option>',
  320. '<option value="12px">12</option>',
  321. '<option value="14px">14</option>',
  322. '<option value="16px">16</option>',
  323. '<option value="18px">18</option>',
  324. '<option value="20px">20</option>',
  325. '<option value="24px">24</option>',
  326. '<option value="28px">28</option>',
  327. '<option value="36px">36</option>',
  328. '<option value="42px">42</option>',
  329. '<option value="52px">52</option>',
  330. '</select>',
  331. '<select name="color">',
  332. '<option value="" selected="selected">颜色</option>',
  333. '<option value="#000000" style="background-color:#000000"></option>',
  334. '<option value="#FFFFFF" style="background-color:#FFFFFF"></option>',
  335. '<option value="#008000" style="background-color:#008000"></option>',
  336. '<option value="#800000" style="background-color:#800000"></option>',
  337. '<option value="#808000" style="background-color:#808000"></option>',
  338. '<option value="#000080" style="background-color:#000080"></option>',
  339. '<option value="#800080" style="background-color:#800080"></option>',
  340. '<option value="#808080" style="background-color:#808080"></option>',
  341. '<option value="#FFFF00" style="background-color:#FFFF00"></option>',
  342. '<option value="#00FF00" style="background-color:#00FF00"></option>',
  343. '<option value="#00FFFF" style="background-color:#00FFFF"></option>',
  344. '<option value="#FF00FF" style="background-color:#FF00FF"></option>',
  345. '<option value="#FF0000" style="background-color:#FF0000"></option>',
  346. '<option value="#0000FF" style="background-color:#0000FF"></option>',
  347. '<option value="#008080" style="background-color:#008080"></option>',
  348. '</select>',
  349. '<div class="bold"></div>',
  350. '<div class="underline"></div>',
  351. '<div class="italic"></div>',
  352. '<div class="face"></div>',
  353. '<div class="history">消息记录</div>',
  354. '</td>',
  355. '</tr>',
  356. '<tr class="send-message">',
  357. '<td>',
  358. '<iframe name="sendMessage', userJID,'" width="100%" height="80px" frameborder="0"></iframe>',
  359. '</td>',
  360. '</tr>',
  361. '<tr class="bottom-bar">',
  362. '<td><input type="text" id="to" name="to" value="hoojo" style="width: 100px;"/><input type="button" value="关闭" id="close"/> ',
  363. '<input type="button" value="发送(Enter)" id="send"/> </td>',
  364. '</tr>',
  365. '</table></div>',
  366. '<div id="face"></div>',
  367. '</div>',
  368. '</div>'
  369. ].join("");
  370. },
  371. initWebIM: function (userJID, receiver) {
  372. var product = {
  373. name: "小玩熊",
  374. pic: "http://avatar.csdn.net/9/7/A/2_ibm_hoojo.jpg",
  375. price: "198.00",
  376. marketPrice: "899.90",
  377. deliverOrgs: "EMS",
  378. wareHouses: "A库",
  379. skuAttrs: ""
  380. };
  381. var chatEl = $(_opts.chatLayoutTemplate(userJID, _opts.sender, receiver, product));
  382. $("body").append(chatEl);
  383. // 拖拽
  384. $("#" + userJID).easydrag();
  385. // 初始化sendMessageEditor相关信息
  386. sendMessageEditor.iframe = this.sendMessageIFrame(userJID);
  387. sendMessageEditor.init(userJID);
  388. _opts.setTitle(chatEl);
  389. _opts.writeReceiveStyle(userJID);
  390. _opts.writeSendStyle();
  391. _opts.createFaceElement(chatEl);
  392. // 查看更多详情
  393. chatEl.find(".more").click(function () {
  394. var $ul = $(this).parents("ul");
  395. $ul.find(".more").toggle();
  396. $ul.find(".info").toggle();
  397. $ul.find(".pic").toggle();
  398. });
  399. // 收缩详情
  400. chatEl.find(".split").toggle(function () {
  401. $(".product-info").hide();
  402. $(this).parents(".radius").css("border-right-width", "0");
  403. }, function () {
  404. $(".product-info").show();
  405. $(this).parents(".radius").css("border-right-width", "8px");
  406. });
  407. // 工具类绑定事件 settings.toolBarHandler
  408. chatEl.find(".tool-bar td").children().click(this.toolBarHandler);
  409. chatEl.find("#send").click(function () {
  410. var $chatMain = $(this).parents(".chat-main");
  411. _opts.sendHandler($chatMain);
  412. });
  413. chatEl.find("#close").click(function () {
  414. var $chatMain = $(this).parents(".chat-main");
  415. $chatMain.hide(500);
  416. });
  417. // 首先取消事件绑定,当一次性发多条消息的情况下会同时绑定多个相同事件
  418. $(".have-msg, .no-msg, .chat-main").unbind("click");
  419. $(".have-msg").bind("click", function () {
  420. $(this).hide();
  421. $(".no-msg").show();
  422. $(".chat-main:hidden").show(150);
  423. });
  424. $(".no-msg").click(function () {
  425. $(".chat-main:hidden").each(function (i, item) {
  426. var top = i * 10 + 50;
  427. var left = i * 20 + 50;
  428. $(this).show(500).css({top: top, left: left});
  429. });
  430. });
  431. $(".chat-main").click(function () {
  432. $(".chat-main").css("z-index", 9999);
  433. $(this).css({"z-index": 10000});
  434. });
  435. $(this.sendMessageIFrame(userJID).document).keyup(function (event) {
  436. var e = event || window.event;
  437. var keyCode = e.which || e.keyCode;
  438. if (keyCode == 13) {
  439. var $chatMain = $("#" + $(this).find("body").attr("jid"));
  440. _opts.sendHandler($chatMain);
  441. }
  442. });
  443. },
  444. // 建立新聊天窗口
  445. newWebIM: function (settings) {
  446. var chatUser = remote.userAddress(settings.receiver);
  447. var userJID = "u" + hex_md5(chatUser);
  448. _opts.initWebIM(userJID, chatUser);
  449. $("#" + userJID).find(remote.receiver).val(chatUser);
  450. $("#" + userJID).show(220);
  451. },
  452. // 远程发送消息时执行函数
  453. messageHandler: function (user, content) {
  454. var userName = user.split("@")[0];
  455. var tempUser = user;
  456. if (~tempUser.indexOf("/")) {
  457. tempUser = tempUser.substr(0, tempUser.indexOf("/"));
  458. }
  459. var userJID = "u" + hex_md5(tempUser);
  460. // 首次初始webIM
  461. if (!$("#" + userJID).get(0)) {
  462. // 初始IM面板;
  463. _opts.initWebIM(userJID, user);
  464. }
  465. // 设置消息接受者的名称
  466. $("#" + userJID).find(remote.receiver).val(user);
  467. if ($("#" + userJID).get(0)) {
  468. // 消息提示
  469. if ($("div[id='" + userJID + "']:hidden").get(0)) {
  470. var haveMessage = $(".have-msg");
  471. haveMessage.show();
  472. $(".no-msg").hide();
  473. }
  474. _opts.messageTip("闪聊有了新消息,请查收!");
  475. // 向chat接收信息区域写消息
  476. remote.jsjac.chat.writeMessage(userJID, userName, content);
  477. }
  478. },
  479. // 消息提示
  480. messageTip: function () {
  481. if (count % 2 == 0) {
  482. window.focus();
  483. document.title = "你来了新消息,请查收!";
  484. } else {
  485. document.title = "";
  486. }
  487. if (count > 4) {
  488. document.title = "";
  489. count = 0;
  490. } else {
  491. window.setTimeout(_opts.messageTip, 1000);
  492. count ++;
  493. }
  494. }
  495. };
  496. // 初始化远程聊天程序相关方法
  497. var initRemoteIM = function (settings) {
  498. // 初始化远程消息
  499. remote.jsjac.chat.init();
  500. // 设置客户端写入信息方法
  501. remote.jsjac.chat.writeReceiveMessage = settings.writeReceiveMessage;
  502. // 注册事件
  503. $(window).bind({
  504. unload: remote.jsjac.chat.unloadHandler,
  505. error: remote.jsjac.chat.errorHandler,
  506. beforeunload: remote.jsjac.chat.logout
  507. });
  508. }
  509. $.extend({
  510. WebIM: function (opts) {
  511. opts = opts || {};
  512. // 覆盖默认配置
  513. defaultOptions = $.extend(defaultOptions, defaultOptions, opts);
  514. var settings = $.extend({}, defaultOptions, opts);
  515. initRemoteIM(settings);
  516. settings.newWebIM(settings);
  517. $.WebIM.settings = settings;
  518. }
  519. });
  520. $.WebIM.settings = $.WebIM.settings || _opts;
  521. $.WebIM.initWebIM = _opts.initWebIM;
  522. $.WebIM.newWebIM = _opts.newWebIM;
  523. $.WebIM.messageHandler = _opts.messageHandler;
  524. })(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

  1. /**
  2. * IM chat jsjac remote message
  3. * @author: hoojo
  4. * @email: hoojo_@126.com
  5. * @blog http://hoojo.cnblogs.com & http://blog.csdn.net/IBM_hoojo
  6. * @createDate: 2012-5-24
  7. * @version 2.0
  8. * @requires jQuery v1.2.3 or later
  9. * Copyright (c) 2012 M. hoo
  10. **/
  11. var remote = {
  12. debug: "info, error",
  13. chat: "body",
  14. receiver: "#to", // 接受者jquery expression
  15. console: {
  16. errorEL: function () {
  17. if ($(remote.chat).get(0)) {
  18. return $(remote.chat).find("#error");
  19. } else {
  20. return $("body").find("#error");
  21. }
  22. },
  23. infoEL: function () {
  24. if ($(remote.chat).get(0)) {
  25. return $(remote.chat).find("#info");
  26. } else {
  27. return $("body").find("#info");
  28. }
  29. },
  30. // debug info
  31. info: function (html) {
  32. if (~remote.debug.indexOf("info")) {
  33. remote.console.infoEL().append(html);
  34. remote.console.infoEL().get(0).lastChild.scrollIntoView();
  35. }
  36. },
  37. // debug error
  38. error: function (html) {
  39. if (~remote.debug.indexOf("error")) {
  40. remote.console.errorEL().append(html);
  41. }
  42. },
  43. // clear info/debug console
  44. clear: function (s) {
  45. if ("debug" == s) {
  46. remote.console.errorEL().html("");
  47. } else {
  48. remote.console.infoEL().html("");
  49. }
  50. }
  51. },
  52. userAddress: function (user) {
  53. if (user) {
  54. if (!~user.indexOf("@")) {
  55. user += "@" + remote.jsjac.domain;// + "/" + remote.jsjac.resource;
  56. } else if (~user.indexOf("/")) {
  57. user = user.substr(0, user.indexOf("/"));
  58. }
  59. }
  60. return user;
  61. },
  62. jsjac: {
  63. httpbase: window.contextPath + "/JHB/", //请求后台http-bind服务器url
  64. domain: window["serverDomin"], //"192.168.5.231", // 192.168.5.231 当前有效域名
  65. username: "",
  66. pass: "",
  67. timerval: 2000, // 设置请求超时
  68. resource: "WebIM", // 链接资源标识
  69. register: true // 是否注册
  70. }
  71. };
  72. remote.jsjac.chat = {
  73. writeReceiveMessage: function () {
  74. },
  75. setState: function () {
  76. var onlineStatus = new Object();
  77. onlineStatus["available"] = "在线";
  78. onlineStatus["chat"] = "欢迎聊天";
  79. onlineStatus["away"] = "离开";
  80. onlineStatus["xa"] = "不可用";
  81. onlineStatus["dnd"] = "请勿打扰";
  82. onlineStatus["invisible"] = "隐身";
  83. onlineStatus["unavailable"] = "离线";
  84. remote.jsjac.chat.state = onlineStatus;
  85. return onlineStatus;
  86. },
  87. state: null,
  88. init: function () {
  89. // Debugger plugin
  90. if (typeof (Debugger) == "function") {
  91. remote.dbger = new Debugger(2, remote.jsjac.resource);
  92. remote.dbger.start();
  93. } else {
  94. // if you're using firebug or safari, use this for debugging
  95. // oDbg = new JSJaCConsoleLogger(2);
  96. // comment in above and remove comments below if you don't need debugging
  97. remote.dbger = function () {
  98. };
  99. remote.dbger.log = function () {
  100. };
  101. }
  102. try {
  103. // try to resume a session
  104. if (JSJaCCookie.read("btype").getValue() == "binding") {
  105. remote.connection = new JSJaCHttpBindingConnection({ "oDbg": remote.dbger});
  106. rdbgerjac.chat.setupEvent(remote.connection);
  107. if (remote.connection.resume()) {
  108. remote.console.clear("debug");
  109. }
  110. }
  111. } catch (e) {
  112. remote.console.errorEL().html(e.name + ":" + e.message);
  113. } // reading cookie failed - never mind
  114. remote.jsjac.chat.setState();
  115. },
  116. login: function (loginForm) {
  117. remote.console.clear("debug"); // reset
  118. try {
  119. // 链接参数
  120. var connectionConfig = remote.jsjac;
  121. // Debugger console
  122. if (typeof (oDbg) != "undefined") {
  123. connectionConfig.oDbg = oDbg;
  124. }
  125. var connection = new JSJaCHttpBindingConnection(connectionConfig);
  126. remote.connection = connection;
  127. // 安装(注册)Connection事件模型
  128. remote.jsjac.chat.setupEvent(connection);
  129. // setup args for connect method
  130. if (loginForm) {
  131. //connectionConfig = new Object();
  132. //connectionConfig.domain = loginForm.domain.value;
  133. connectionConfig.username = loginForm.userName.value;
  134. connectionConfig.pass = loginForm.password.value;
  135. connectionConfig.register = loginForm.register.checked;
  136. }
  137. // 连接服务器
  138. connection.connect(connectionConfig);
  139. //remote.jsjac.chat.changeStatus("available", "online", 1, "chat");
  140. } catch (e) {
  141. remote.console.errorEL().html(e.toString());
  142. } finally {
  143. return false;
  144. }
  145. },
  146. // 改变用户状态
  147. changeStatus: function (type, status, priority, show) {
  148. type = type || "unavailable";
  149. status = status || "online";
  150. priority = priority || "1";
  151. show = show || "chat";
  152. var presence = new JSJaCPresence();
  153. presence.setType(type); // unavailable invisible
  154. if (remote.connection) {
  155. //remote.connection.send(presence);
  156. }
  157. //presence = new JSJaCPresence();
  158. presence.setStatus(status); // online
  159. presence.setPriority(priority); // 1
  160. presence.setShow(show); // chat
  161. if (remote.connection) {
  162. remote.connection.send(presence);
  163. }
  164. },
  165. // 为Connection注册事件
  166. setupEvent: function (con) {
  167. var remoteChat = remote.jsjac.chat;
  168. con.registerHandler('message', remoteChat.handleMessage);
  169. con.registerHandler('presence', remoteChat.handlePresence);
  170. con.registerHandler('iq', remoteChat.handleIQ);
  171. con.registerHandler('onconnect', remoteChat.handleConnected);
  172. con.registerHandler('onerror', remoteChat.handleError);
  173. con.registerHandler('status_changed', remoteChat.handleStatusChanged);
  174. con.registerHandler('ondisconnect', remoteChat.handleDisconnected);
  175. con.registerIQGet('query', NS_VERSION, remoteChat.handleIqVersion);
  176. con.registerIQGet('query', NS_TIME, remoteChat.handleIqTime);
  177. },
  178. // 发送远程消息
  179. sendMessage: function (msg, to) {
  180. try {
  181. if (msg == "") {
  182. return false;
  183. }
  184. var user = "";
  185. if (to) {
  186. if (!~to.indexOf("@")) {
  187. user += "@" + remote.jsjac.domain;
  188. to += "/" + remote.jsjac.resource;
  189. } else if (~to.indexOf("/")) {
  190. user = to.substr(0, to.indexOf("/"));
  191. }
  192. } else {
  193. // 向chat接收信息区域写消息
  194. if (remote.jsjac.chat.writeReceiveMessage) {
  195. var html = "你没有指定发送者的名称";
  196. alert(html);
  197. //remote.jsjac.chat.writeReceiveMessage(receiverId, "server", html, false);
  198. }
  199. return false;
  200. }
  201. var userJID = "u" + hex_md5(user);
  202. $("#" + userJID).find(remote.receiver).val(to);
  203. // 构建jsjac的message对象
  204. var message = new JSJaCMessage();
  205. message.setTo(new JSJaCJID(to));
  206. message.setType("chat"); // 单独聊天,默认为广播模式
  207. message.setBody(msg);
  208. // 发送消息
  209. remote.connection.send(message);
  210. return false;
  211. } catch (e) {
  212. var html = "<div class='msg error''>Error: " + e.message + "</div>";
  213. remote.console.info(html);
  214. return false;
  215. }
  216. },
  217. // 退出、断开链接
  218. logout: function () {
  219. var presence = new JSJaCPresence();
  220. presence.setType("unavailable");
  221. if (remote.connection) {
  222. remote.connection.send(presence);
  223. remote.connection.disconnect();
  224. }
  225. },
  226. errorHandler: function (event) {
  227. var e = event || window.event;
  228. remote.console.errorEL().html(e);
  229. if (remote.connection && remote.connection.connected()) {
  230. remote.connection.disconnect();
  231. }
  232. return false;
  233. },
  234. unloadHandler: function () {
  235. var con = remote.connection;
  236. if (typeof con != "undefined" && con && con.connected()) {
  237. // save backend type
  238. if (con._hold) { // must be binding
  239. (new JSJaCCookie("btype", "binding")).write();
  240. }
  241. if (con.suspend) {
  242. con.suspend();
  243. }
  244. }
  245. },
  246. writeMessage: function (userJID, userName, content) {
  247. // 向chat接收信息区域写消息
  248. if (remote.jsjac.chat.writeReceiveMessage && !!content) {
  249. remote.jsjac.chat.writeReceiveMessage(userJID, userName, content, false);
  250. }
  251. },
  252. // 重新连接服务器
  253. reconnection: function () {
  254. remote.jsjac.register = false;
  255. if (remote.connection.connected()) {
  256. remote.connection.disconnect();
  257. }
  258. remote.jsjac.chat.login();
  259. },
  260. /* ########################### Handler Event ############################# */
  261. handleIQ: function (aIQ) {
  262. var html = "<div class='msg'>IN (raw): " + aIQ.xml().htmlEnc() + "</div>";
  263. remote.console.info(html);
  264. remote.connection.send(aIQ.errorReply(ERR_FEATURE_NOT_IMPLEMENTED));
  265. },
  266. handleMessage: function (aJSJaCPacket) {
  267. var user = aJSJaCPacket.getFromJID().toString();
  268. //var userName = user.split("@")[0];
  269. //var userJID = "u" + hex_md5(user);
  270. var content = aJSJaCPacket.getBody();
  271. var html = "";
  272. html += "<div class=\"msg\"><b>消息来自 " + user + ":</b><br/>";
  273. html += content.htmlEnc() + "</div>";
  274. remote.console.info(html);
  275. $.WebIM.messageHandler(user, content);
  276. },
  277. handlePresence: function (aJSJaCPacket) {
  278. var user = aJSJaCPacket.getFromJID();
  279. var userName = user.toString().split("@")[0];
  280. var html = "<div class=\"msg\">";
  281. if (!aJSJaCPacket.getType() && !aJSJaCPacket.getShow()) {
  282. html += "<b>" + userName + " 上线了.</b>";
  283. } else {
  284. html += "<b>" + userName + " 设置 presence 为: ";
  285. if (aJSJaCPacket.getType()) {
  286. html += aJSJaCPacket.getType() + ".</b>";
  287. } else {
  288. html += aJSJaCPacket.getShow() + ".</b>";
  289. }
  290. if (aJSJaCPacket.getStatus()) {
  291. html += " (" + aJSJaCPacket.getStatus().htmlEnc() + ")";
  292. }
  293. }
  294. html += "</div>";
  295. remote.console.info(html);
  296. // 向chat接收信息区域写消息
  297. remote.jsjac.chat.writeMessage("", userName, html);
  298. },
  299. handleError: function (event) {
  300. var e = event || window.event;
  301. var html = "An error occured:<br />"
  302. + ("Code: " + e.getAttribute("code")
  303. + "\nType: " + e.getAttribute("type")
  304. + "\nCondition: " + e.firstChild.nodeName).htmlEnc();
  305. remote.error(html);
  306. var content = "";
  307. switch (e.getAttribute("code")) {
  308. case "401":
  309. content = "登陆验证失败!";
  310. break;
  311. // 当注册发现重复,表明该用户已经注册,那么直接进行登陆操作
  312. case "409":
  313. //content = "注册失败!\n\n请换一个用户名!";
  314. remote.jsjac.chat.reconnection();
  315. break;
  316. case "503":
  317. content = "无法连接到IM服务器,请检查相关配置!";
  318. break;
  319. case "500":
  320. var contents = "服务器内部错误!\n\n连接断开!<br/><a href='javascript: self.parent.remote.jsjac.chat.reconnection();'>重新连接</a>";
  321. remote.jsjac.chat.writeMessage("", "系统", contents);
  322. break;
  323. default:
  324. break;
  325. }
  326. if (content) {
  327. alert("WeIM: " + content);
  328. }
  329. if (remote.connection.connected()) {
  330. remote.connection.disconnect();
  331. }
  332. },
  333. // 状态变化触发事件
  334. handleStatusChanged: function (status) {
  335. remote.console.info("<div>当前用户状态: " + status + "</div>");
  336. remote.dbger.log("当前用户状态: " + status);
  337. if (status == "disconnecting") {
  338. var html = "<b style='color:red;'>你离线了!</b>";
  339. // 向chat接收信息区域写消息
  340. remote.jsjac.chat.writeMessage("", "系统", html);
  341. }
  342. },
  343. // 建立链接触发事件方法
  344. handleConnected: function () {
  345. remote.console.clear("debug"); // reset
  346. remote.connection.send(new JSJaCPresence());
  347. },
  348. // 断开链接触发事件方法
  349. handleDisconnected: function () {
  350. },
  351. handleIqVersion: function (iq) {
  352. remote.connection.send(iq.reply([
  353. iq.buildNode("name", remote.jsjac.resource),
  354. iq.buildNode("version", JSJaC.Version),
  355. iq.buildNode("os", navigator.userAgent)
  356. ]));
  357. return true;
  358. },
  359. handleIqTime: function (iq) {
  360. var now = new Date();
  361. remote.connection.send(iq.reply([
  362. iq.buildNode("display", now.toLocaleString()),
  363. iq.buildNode("utc", now.jabberDate()),
  364. iq.buildNode("tz", now.toLocaleString().substring(now.toLocaleString().lastIndexOf(" ") + 1))
  365. ]));
  366. return true;
  367. }
  368. };

这个文件的代码就是用jsjac库和openfire建立通信的核心代码,代码中已经有注释,这里我就不再赘述。如果有什么不懂的可以给我留言。

4、消息区域、编辑器代码 send.message.editor-1.0.js

  1. /**
  2. * IM chat Send Message iframe editor
  3. * @author: hoojo
  4. * @email: hoojo_@126.com
  5. * @blog: http://blog.csdn.net/IBM_hoojo
  6. * @createDate: 2012-5-24
  7. * @version 1.0
  8. **/
  9. var agent = window.navigator.userAgent.toLowerCase();
  10. var sendMessageEditor = {
  11. // 获取iframe的window对象
  12. getWin: function () {
  13. return /*!/firefox/.test(agent)*/false ? sendMessageEditor.iframe.contentWindow : window.frames[sendMessageEditor.iframe.name];
  14. },
  15. //获取iframe的document对象
  16. getDoc: function () {
  17. return !/firefox/.test(agent) ? sendMessageEditor.getWin().document : (sendMessageEditor.iframe.contentDocument || sendMessageEditor.getWin().document);
  18. },
  19. init: function (userJID) {
  20. //打开document对象,向其写入初始化内容,以兼容FireFox
  21. var doc = sendMessageEditor.getDoc();
  22. doc.open();
  23. var html = [
  24. '<html>',
  25. '<head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;background-color:white;font-size:12px;font-family:Courier,serif,monospace;}</style></head>',
  26. '<body jid="', userJID, '"></body>',
  27. '</html>'].join("");
  28. doc.write(html);
  29. //打开document对象编辑模式
  30. doc.designMode = "on";
  31. doc.close();
  32. },
  33. getContent: function () {
  34. var doc = sendMessageEditor.getDoc();
  35. //获取编辑器的body对象
  36. var body = doc.body || doc.documentElement;
  37. //获取编辑器的内容
  38. var content = body.innerHTML;
  39. //对内容进行处理,例如替换其中的某些特殊字符等等
  40. //Some code
  41. //返回内容
  42. return content;
  43. },
  44. //统一的执行命令方法
  45. execCmd: function (cmd, value, d){
  46. var doc = d || sendMessageEditor.getDoc();
  47. //doc对象的获取参照上面的代码
  48. //调用execCommand方法执行命令
  49. doc.execCommand(cmd, false, value === undefined ? null : value);
  50. },
  51. getStyleState: function (cmd) {
  52. var doc = sendMessageEditor.getDoc();
  53. //doc对象的获取参考上面的对面
  54. //光标处是否是粗体
  55. var state = doc.queryCommandState(cmd);
  56. if(state){
  57. //改变按钮的样式
  58. }
  59. return state;
  60. },
  61. insertAtCursor: function (text, d, w){
  62. var doc = d || sendMessageEditor.getDoc();
  63. var win = w || sendMessageEditor.getWin();
  64. //win对象的获取参考上面的代码
  65. if (/msie/.test(agent)) {
  66. win.focus();
  67. var r = doc.selection.createRange();
  68. if (r) {
  69. r.collapse(true);
  70. r.pasteHTML(text);
  71. }
  72. } else if (/gecko/.test(agent) || /opera/.test(agent)) {
  73. win.focus();
  74. sendMessageEditor.execCmd('InsertHTML', text, doc);
  75. } else if (/safari/.test(agent)) {
  76. sendMessageEditor.execCmd('InsertText', text, doc);
  77. }
  78. }
  79. };

5、css样式 chat-2.0.css

  1. /**
  2. * function: im web chat css
  3. * author: hoojo
  4. * createDate: 2012-5-26 上午11:42:10
  5. */
  6. @CHARSET "UTF-8";
  7. *, body {
  8. font-family: Courier,serif,monospace;
  9. font-size: 12px;
  10. padding: 0;
  11. margin: 0;
  12. }
  13. .chat-main {
  14. position: absolute;
  15. /*right: 80px;*/
  16. left: 50px;
  17. top: 20px;
  18. z-index: 999;
  19. display: none;
  20. }
  21. .chat-main .radius {
  22. background-color: white;
  23. border: 8px solid #94CADF;
  24. border-radius: 1em;
  25. }
  26. #chat {
  27. position: relative;
  28. /*left: 150px;*/
  29. padding: 0;
  30. margin: 0;
  31. }
  32. #chat table {
  33. border-collapse: collapse;
  34. width: 435px;
  35. *width: 460px;
  36. /*width: 410px;*/
  37. /*width: 320px;*/
  38. }
  39. #chat table .title {
  40. font-weight: bold;
  41. color: green;
  42. padding: 3px;
  43. background-color: #94CADF;
  44. }
  45. /* 收缩条 */
  46. #chat table .split {
  47. background-color: #94CADF;
  48. cursor: pointer;
  49. }
  50. /* ################## product info #################### */
  51. #chat table .product-info {
  52. width: 30%;
  53. /*display: none;*/
  54. padding: 0;
  55. margin: 0;
  56. vertical-align: top;
  57. }
  58. #chat table .product-info ul {
  59. margin: 0;
  60. padding: 0;
  61. }
  62. #chat table .product-info ul div.header {
  63. background-color: #EBEFFE;
  64. line-height: 22px;
  65. font-size: 12px;
  66. color: black;
  67. }
  68. #chat table .product-info ul li {
  69. list-style: none outside none;
  70. background-color: white;
  71. text-overflow: ellipsis;
  72. white-space: nowrap;
  73. overflow: hidden;
  74. padding-left: 5px;
  75. line-height: 22px;
  76. font-size: 11px;
  77. color: #6F6F6F;
  78. width: 140px;
  79. }
  80. #chat table .product-info ul li.pic {
  81. height: 200px;
  82. padding: 0 5px 0 5px;
  83. border: 1px dashed #ccc;
  84. text-align: center;
  85. }
  86. #chat table .product-info ul li.pic img {
  87. }
  88. #chat table .product-info ul li.product-name {
  89. font-weight: bold;
  90. color: black;
  91. }
  92. #chat table .product-info ul li.price span {
  93. font-family: Courier;
  94. font-size: 16px;
  95. font-weight: bold;
  96. color: #ED4E08;
  97. }
  98. #chat table .product-info ul li.market-price s {
  99. color: black;
  100. }
  101. #chat table .product-info ul li a {
  102. float: right;
  103. }
  104. #chat table .product-info ul li.info {
  105. display: none;
  106. }
  107. /*########### 接收消息区域 ############ */
  108. #chat table .receive-message {
  109. height: 250px;
  110. }
  111. #chat table .send-message {
  112. width: 100%;
  113. /*height: auto;*/
  114. }
  115. #chat table td {
  116. /*border: 1px solid white;*/
  117. }
  118. #chat table .bottom-bar {
  119. background-color: #94CADF;
  120. text-align: right;
  121. }
  122. /* ############## 工具条 ################# start */
  123. #chat table .tool-bar {
  124. height: 25px;
  125. background-color: #94CADF;
  126. }
  127. #chat table .tool-bar select {
  128. float: left;
  129. }
  130. #chat table .tool-bar select.family {
  131. width: 45px;
  132. *width: 55px;
  133. }
  134. #chat table .tool-bar div {
  135. width: 17px;
  136. height: 16px;
  137. float: left;
  138. cursor: pointer;
  139. margin-right: 2px;
  140. margin-top: 1px;
  141. *margin-top: 2px;
  142. background: transparent url("../images/tb-sprite.gif") no-repeat scroll 0 0;
  143. }
  144. #chat table .tool-bar .color {
  145. margin-left: 2px;
  146. background-position: -159px 0;
  147. }
  148. #chat table .tool-bar .bold {
  149. /*background-position: 0 0;*/
  150. }
  151. #chat table .tool-bar .italic {
  152. background-position: -18px 0;
  153. }
  154. #chat table .tool-bar .underline {
  155. background-position: -32px 0;
  156. }
  157. #chat table .tool-bar .face {
  158. margin: 2px 0 0 3px;
  159. background-image: url("../images/facehappy.gif");
  160. }
  161. #chat table .tool-bar .history {
  162. background-image: none;
  163. width: 60px;
  164. float: right;
  165. margin-top: 3px;
  166. font-size: 12px;
  167. display: none;
  168. }
  169. /* ###### 表情 ###### */
  170. #chat #face {
  171. border: 1px solid black;
  172. width: 275px;
  173. *width: 277px;
  174. position: relative;
  175. left: 8px;
  176. top: -370px;
  177. _top: -359px;
  178. z-index: 3;
  179. display: none;
  180. }
  181. #chat #face img {
  182. border: 1px solid #ccc;
  183. border-right: none;
  184. border-bottom: none;
  185. cursor: pointer;
  186. }
  187. #send {
  188. width: 90px;
  189. height: 25px;
  190. }
  191. #close {
  192. width: 40px;
  193. height: 25px;
  194. }
  195. .chat-message {
  196. position: absolute;
  197. bottom: 0;
  198. left: 0;
  199. width: 100%;
  200. height: 25px;
  201. background-color: #fcfcfc;
  202. }
  203. .no-msg, .have-msg {
  204. cursor: pointer;
  205. float: right;
  206. margin: 5px 5px 0 0;
  207. }

6、web.xml配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  5. http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  6. <servlet>
  7. <servlet-name>Jabber HTTP Binding Servlet</servlet-name>
  8. <servlet-class>org.jabber.JabberHTTPBind.JHBServlet</servlet-class>
  9. <!--
  10. <init-param>
  11. <param-name>debug</param-name>
  12. <param-value>1</param-value>
  13. </init-param>
  14. -->
  15. </servlet>
  16. <servlet-mapping>
  17. <servlet-name>Jabber HTTP Binding Servlet</servlet-name>
  18. <url-pattern>/JHB/</url-pattern>
  19. </servlet-mapping>
  20. <welcome-file-list>
  21. <welcome-file>index.jsp</welcome-file>
  22. </welcome-file-list>
  23. </web-app>

至此,这个应用的全部代码已经贴出来,如果你按照我这边的结构形式应该是可以完成这个聊天应用的。如果你有什么问题或想法,欢迎你给我留言或评论!