CometD:Java Web应用程序的Facebook类似聊天

聊天就像吃一块蛋糕或喝一杯热咖啡一样容易。 您是否曾经考虑过自己开发聊天程序? 您知道,聊天不容易。 但是,如果您是开发人员,并且阅读了本文的结尾,则可以尝试自己开发一个聊天应用程序,并允许您的用户通过您的Web应用程序进行聊天。我的网络应用程序。 就像每个人一样,我开始在互联网上搜索。 我找到了IRC。 当我阅读并搜索有关IRC的更多信息时,我了解到很难为IRC找到基于Web的客户端。 我想拥有更多可定制的Web客户端,其工作方式类似于Facebook。 最后,幸运的是,我找到了CometD。

最后,我能够使用CometD和在浏览器中打开的与Facebook完全相似的可自定义的聊天窗口来实现聊天应用程序。 这几乎适用于所有现代浏览器。 本文分步说明了如何从头开始实现聊天应用程序,以及如何将聊天应用程序集成到您现有的Java基本Web应用程序。 记住,您的Web应用程序应该是基于Java的应用程序。

您需要从他们的官方网站下载cometD 。 它具有实现聊天应用程序所需的所有依赖关系,除了两个Java脚本库。 我已经编写了两个Javascript库,一个用于创建动态聊天窗口(如Facebook),另一个用于以通用方式处理CometD聊天功能。 如果您可以自己管理这些内容,则无需使用这些Javascript库。 实际上,CometD文档提供了很多详细信息。 但是,我将通过使用这些拖曳库继续进行本教程。 无论如何,我建议您先使用这些拖曳库,然后根据需要对其进行自定义。 我希望与您共享该示例应用程序,您可以将其部署在本地主机中并测试其工作方式。

1.添加所需的jar文件。

如果您使用maven来构建项目,则将以下依赖项添加到pom.xml文件中

<dependencies><dependency><groupId>org.cometd.java</groupId><artifactId>bayeux-api</artifactId><version>2.5.0</version></dependency><dependency><groupId>org.cometd.java</groupId><artifactId>cometd-java-server</artifactId><version>2.5.0</version></dependency><dependency><groupId>org.cometd.java</groupId><artifactId>cometd-websocket-jetty</artifactId><version>2.5.0</version><exclusions><exclusion><groupId>org.cometd.java</groupId><artifactId>cometd-java-client</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.6.6</version></dependency><dependency><groupId>org.cometd.java</groupId><artifactId>cometd-java-annotations</artifactId><version>2.5.0</version></dependency>
</dependencies>

如果您不使用maven来构建项目,则只需将以下.jar文件从CometD下载包中复制到/ WEB-INF / lib文件夹中即可。 您可以从/cometd-demo/target/cometd-demo-2.5.0.war文件中找到这些.jar文件。

  • bayeux-api-2.5.0.jar
  • cometd-java-annotations-2.5.0.jar
  • cometd-java-common-2.5.0.jar
  • cometd-java-server-2.5.0.jar
  • cometd-websocket-jetty-2.5.0.jar
  • javax.inject-1.jar
  • jetty-continuation-7.6.7.v20120910.jar
  • jetty-http-7.6.7.v20120910.jar
  • jetty-io-7.6.7.v20120910.jar
  • jetty-jmx-7.6.7.v20120910.jar
  • jetty-util-7.6.7.v20120910.jar
  • jetty-websocket-7.6.7.v20120910.jar
  • jsr250-api-1.0.jar
  • slf4j-api-1.6.6.jar
  • slf4j-simple-1.6.6.jar

2.添加所需的Javascript文件。

您需要链接以下Javascript文件。

  • cometd.js
  • AckExtension.js
  • ReloadExtension.js
  • jQuery的1.8.2.js
  • jquery.cookie.js
  • jquery.cometd.js
  • jquery.cometd-reload.js
  • chat.window.js
  • comet.chat.js

chat.window.js ”和“ comet.chat.js ”是我自己的两个Javascript库,但不包含CometD发行版。 如果您完全遵循本教程,则还必须链接这些拖车库。 提供的示例应用程序具有以下两个Javascript库。

3.编写聊天服务类。

/*** @author Semika siriwardana* CometD chat service.*/
package com.semika.cometd;import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;import javax.inject.Inject;import org.cometd.annotation.Configure;
import org.cometd.annotation.Listener;
import org.cometd.annotation.Service;
import org.cometd.annotation.Session;
import org.cometd.bayeux.client.ClientSessionChannel;
import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.bayeux.server.ConfigurableServerChannel;
import org.cometd.bayeux.server.ServerMessage;
import org.cometd.bayeux.server.ServerSession;
import org.cometd.server.authorizer.GrantAuthorizer;
import org.cometd.server.filter.DataFilter;
import org.cometd.server.filter.DataFilterMessageListener;
import org.cometd.server.filter.JSONDataFilter;
import org.cometd.server.filter.NoMarkupFilter;@Service('chat')
public class ChatService {private final ConcurrentMap<String, Map<String, String>> _members = new ConcurrentHashMap<String, Map<String, String>>();@Injectprivate BayeuxServer _bayeux;@Sessionprivate ServerSession _session;@Configure ({'/chat/**','/members/**'})protected void configureChatStarStar(ConfigurableServerChannel channel) {DataFilterMessageListener noMarkup = new DataFilterMessageListener(new NoMarkupFilter(),new BadWordFilter());channel.addListener(noMarkup);channel.addAuthorizer(GrantAuthorizer.GRANT_ALL);}@Configure ('/service/members')protected void configureMembers(ConfigurableServerChannel channel) {channel.addAuthorizer(GrantAuthorizer.GRANT_PUBLISH);channel.setPersistent(true);}@Listener('/service/members')public void handleMembership(ServerSession client, ServerMessage message) {Map<String, Object> data = message.getDataAsMap();final String room = ((String)data.get('room')).substring('/chat/'.length());Map<String, String> roomMembers = _members.get(room);if (roomMembers == null) {Map<String, String> new_room = new ConcurrentHashMap<String, String>();roomMembers = _members.putIfAbsent(room, new_room);if (roomMembers == null) roomMembers = new_room;}final Map<String, String> members = roomMembers;String userName = (String)data.get('user');members.put(userName, client.getId());client.addListener(new ServerSession.RemoveListener() {public void removed(ServerSession session, boolean timeout) {members.values().remove(session.getId());broadcastMembers(room, members.keySet());}});broadcastMembers(room, members.keySet());}private void broadcastMembers(String room, Set<String> members) {// Broadcast the new members listClientSessionChannel channel = _session.getLocalSession().getChannel('/members/'+room);channel.publish(members);}@Configure ('/service/privatechat')protected void configurePrivateChat(ConfigurableServerChannel channel) {DataFilterMessageListener noMarkup = new DataFilterMessageListener(new NoMarkupFilter(),new BadWordFilter());channel.setPersistent(true);channel.addListener(noMarkup);channel.addAuthorizer(GrantAuthorizer.GRANT_PUBLISH);}@Listener('/service/privatechat')protected void privateChat(ServerSession client, ServerMessage message) {Map<String,Object> data = message.getDataAsMap();String room = ((String)data.get('room')).substring('/chat/'.length());Map<String, String> membersMap = _members.get(room);if (membersMap == null) {Map<String,String>new_room=new ConcurrentHashMap<String, String>();membersMap=_members.putIfAbsent(room,new_room);if (membersMap==null)membersMap=new_room;}String peerName = (String)data.get('peer');String peerId = membersMap.get(peerName);if (peerId != null) {ServerSession peer = _bayeux.getSession(peerId);if (peer != null) {Map<String, Object> chat = new HashMap<String, Object>();String text = (String)data.get('chat');chat.put('chat', text);chat.put('user', data.get('user'));chat.put('scope', 'private');chat.put('peer', peerName);ServerMessage.Mutable forward = _bayeux.newMessage();forward.setChannel('/chat/' + room);forward.setId(message.getId());forward.setData(chat);if (text.lastIndexOf('lazy') > 0) {forward.setLazy(true);}if (peer != client) {peer.deliver(_session, forward);}client.deliver(_session, forward);}}}class BadWordFilter extends JSONDataFilter {@Overrideprotected Object filterString(String string) {if (string.indexOf('dang') >= 0) {throw new DataFilter.Abort();}return string;}}
}

4.更改web.xml文件。

您应该将以下过滤器添加到web.xml文件中。

<filter><filter-name>continuation</filter-name><filter-class>org.eclipse.jetty.continuation.ContinuationFilter</filter-class>
</filter>
<filter-mapping><filter-name>continuation</filter-name><url-pattern>/cometd/*</url-pattern>
</filter-mapping>

还有以下servlet。

<servlet><servlet-name>cometd</servlet-name><servlet-class>org.cometd.annotation.AnnotationCometdServlet</servlet-class><init-param><param-name>timeout</param-name><param-value>20000</param-value></init-param><init-param><param-name>interval</param-name><param-value>0</param-value></init-param><init-param><param-name>maxInterval</param-name><param-value>10000</param-value></init-param><init-param><param-name>maxLazyTimeout</param-name><param-value>5000</param-value></init-param><init-param><param-name>long-polling.multiSessionInterval</param-name><param-value>2000</param-value></init-param><init-param><param-name>logLevel</param-name><param-value>0</param-value></init-param><init-param><param-name>transports</param-name><param-value>org.cometd.websocket.server.WebSocketTransport</param-value></init-param><init-param><param-name>services</param-name><param-value>com.semika.cometd.ChatService</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>cometd</servlet-name><url-pattern>/cometd/*</url-pattern>
</servlet-mapping>

5.实现客户端功能。

我认为这部分应该是描述性的。 如果允许用户与其他用户聊天,则需要在网页中显示在线用户列表,就像Facebook在右侧栏中显示在线用户一样。 为此,您可以在页面内放置一个简单的<span>或<div>标记。 我做了如下。

<div id='members'></div>

所有的在线用户将显示在上述容器中。 单击特定的用户名后,它将打开一个类似于Facebook的新聊天窗口。 对于每对用户,它将打开一个新的聊天窗口。 要获得这种行为,您应该使用我之前提到的“ chat.window.js ”。 特定用户对之间的聊天将通过专用的聊天窗口继续进行。
用户以通常的方式登录到您的Web应用程序后,我们应该为该用户订阅聊天频道。 您可以使用以下方式进行操作。

$(document).ready(function(){ $.cometChat.onLoad({memberListContainerID:'members'});
});

请注意,我已将在线用户列表容器的“ id”作为配置参数传递。 然后,用户应按以下方式加入频道。您可以使用用户名调用波纹管方法。

function join(userName){$.cometChat.join(userName);
}

由于对于每个聊天,都有一个像Facebook一样的专用聊天窗口,因此我们应该维护全局Javascript数组来存储那些创建的聊天窗口对象。 您需要在页面内放置以下Javascript代码。

function getChatWindowByUserPair(loginUserName, peerUserName) {var chatWindow;  for(var i = 0; i < chatWindowArray.length; i++) {var windowInfo = chatWindowArray[i];if (windowInfo.loginUserName == loginUserName && windowInfo.peerUserName == peerUserName) {chatWindow =  windowInfo.windowObj;}}return chatWindow;
}function createWindow(loginUserName, peerUserName) {  var chatWindow = getChatWindowByUserPair(loginUserName, peerUserName);if (chatWindow == null) { //Not chat window created before for this user pair.chatWindow = new ChatWindow(); //Create new chat window.chatWindow.initWindow({loginUserName:loginUserName, peerUserName:peerUserName,windowArray:chatWindowArray});//collect all chat windows opended so far.var chatWindowInfo = { peerUserName:peerUserName, loginUserName:loginUserName,windowObj:chatWindow };chatWindowArray.push(chatWindowInfo);}chatWindow.show();  return chatWindow;
}

如上所述,声明以下全局Javascript变量。

var chatWindowArray = [];   
var config = {contextPath: '${pageContext.request.contextPath}'
};

由于我使用的是JSP页面,因此必须通过“ pageContext ”变量获取上下文路径。 如果您使用的是HTML页面,请自行进行管理以声明“ config” Javascript全局变量。 现在,您几乎到达了教程的最后一部分。

5.示例应用程序如何工作?

您可以下载comet.war文件并将其部署在服务器中。 将浏览器指向以下URL。

http:// localhost:8080 / comet

这将带您进入一个包含文本字段和名为“ Join”的按钮的页面。 根据需要插入一些用户名,然后单击“加入”按钮。 然后,您将转到另一个包含在线用户列表的页面。 您的姓名以红色突出显示。 要在本地计算机上聊天,您可以打开另一个浏览器(IE和FF)并加入聊天频道。 对等用户在联机用户列表中以蓝色显示。 单击对等用户后,它将打开一个新的聊天窗口,以便您可以与他聊天。 此功能与Facebook聊天非常相似。

我已经在IE,FF和Crome中测试了此聊天应用程序,并且工作正常。 如果您需要将其与Java基本Web应用程序集成的任何帮助,请给我发送邮件。

参考: 适用于Java Web应用程序的Facebook类似聊天。 从我们的JCG合作伙伴 Semika loku kaluge在Code Box博客上获得。


翻译自: https://www.javacodegeeks.com/2012/10/cometd-facebook-similar-chat-for-your.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371067.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

怎么用PHP建立购物网站,如何使用PHP建设一个购物网站

本系统以PHP为主要制作工具&#xff0c;实现了用户注册、登录、验证身份及用户数据的采集、物品的预览查询、搜索/查看物品信息&#xff0c;站内最新物品信息发布&#xff0c;可进入在线下单从而实现了网络销售。网上购物&#xff0c;这个逐渐流行于二十世纪的购物方式已经为越…

团队作业2——需求分析原型设计

需求分析&#xff1a; 软件的最终目的是用来解决用户的某些问题&#xff0c;需求分析就是要理解要解决的问题&#xff0c;真正明确用户需求。请发表一篇随笔&#xff0c;完成初步的需求分析&#xff1a; 1.访问软件项目的真实用户&#xff08;至少10个&#xff09;&#xff0c;…

给div命名,使逻辑更加清晰

我们把一些标签放进<div>里&#xff0c;划分出一个独立的逻辑部分。为了使逻辑更加清晰&#xff0c;我们可以为这一个独立的逻辑部分设置一个名称&#xff0c;用id属性来为<div>提供唯一的名称&#xff0c;这个就像我们每个人都有一个身份证号&#xff0c;这个身份…

css边框颜色渐变

在实际开发中&#xff0c;我们经常遇见边框需要背景渐变的实现要求&#xff0c;那么如何去实现呢&#xff0c;今天给大家分享依稀几种情况 1.直角的背景渐变 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta…

170406、用uid分库,uname(用户名)上的查询怎么办

【缘起】 用户中心是几乎每一个公司必备的基础服务&#xff0c;用户注册、登录、信息查询与修改都离不开用户中心。 当数据量越来越大时&#xff0c;需要多用户中心进行水平切分。最常见的水平切分方式&#xff0c;按照uid取模分库&#xff1a; 通过uid取模&#xff0c;将数据分…

bzoj2144: 跳跳棋(二分/倍增)

思维好题&#xff01; 可以发现如果中间的点要跳到两边有两种情况&#xff0c;两边的点要跳到中间最多只有一种情况。 我们用一个节点表示一种状态&#xff0c;那么两边跳到中间的状态就是当前点的父亲&#xff0c;中间的点跳到两边的状态就是这个点的两个儿子&#xff0c;从而…

电脑投屏软件哪个好_目前当贝市场中投屏软件哪个好,最全面投屏技巧盘点

现在不管是在家里还是公司里&#xff0c;为了看一些是视频和资料&#xff0c;投屏到电视上是一件非常必要的事情&#xff0c;但是现在投屏的技巧各种各样&#xff0c;投屏的软件也是五花八门&#xff0c;小编平常也是经常投屏&#xff0c;也试过非常多的方法&#xff0c;这边分…

从零开始的全栈工程师——html篇1.2

起名方式与CSS 一.起名方式(起名方式也叫选择器) 起名的目的是为了给标签添加属性 常见的3种选择器有 标签选择器 id选择器(使用的时候加#) class选择器(使用的时候加.) 样式的要求是由选择器的权重来决定的 标签的权重为1 class的权重是10 id的权重是100 权重是可…

Spring:设置日志依赖项

这篇文章描述了如何在Spring中设置日志依赖。 它基于Dave Syer的帖子中提供的信息 。 这里提供有关Java日志记录框架的提醒。 该代码示例可在GitHub的Spring-Logging-Dependencies目录中找到。 Spring使用Jakarta Commons Logging API&#xff08;JCL&#xff09;。 不幸的是&…

安卓app开发工具_怎么开发app软件需要多少钱?主流app开发工具盘点

现在智能手机的快速普及让手机app在生活中越来越重要&#xff0c;很多企业及创业者也意识到了app的重要性&#xff0c;但是怎么开发app软件&#xff1f;有哪些主流app开发工具呢&#xff1f;这里就为大家分享一下如何快速开发app软件。一、编程app开发工具主要针对专业的程序员…

大话设计模式读书笔记(十一) 观察者模式

观察者模式&#xff1a; 书中通过小菜描述同事在公司看股票行情&#xff0c;并请求前台帮忙在老板回来时提醒同事&#xff0c;引出需求。将前台通知同事老板回来的事写成程序。未用模式实现&#xff1a; 1 //前台类2 public class Secretary {3 private List<StockObser…

解决高度塌陷

<!DOCTYPE html> <html lang"en" dir"ltr"><head><meta charset"utf-8"><title>高度塌陷解决</title><style media"screen">.box1{border: 10px #bfc993 solid;}.box2{width: 100px;height…

IBM AIX:Java进程大小监视

本文将为您提供有关如何计算在IBM AIX 5.3 OS上运行的Java VM进程的Java进程大小内存占用量的快速参考指南。 这是我关于该主题的原始文章的补充文章&#xff1a; 如何在AIX上监视Java本机内存 。 我强烈建议所有参与生产支持或AIX上部署Java应用程序开发的人员阅读此书。 为…

pstate0 vid数值意义_天体运动的简单数值计算

&#xff08;建议阅读全文&#xff09; 预备知识 万有引力&#xff0c; 弹簧振子受迫运动的简单数值计算    下面我们来用一种极其简单的算法对单个天体在中心天体的万有引力作用下的运动进行数值计算&#xff0e; 事实上该问题存在解析解&#xff08;见开普勒三定律&#x…

集合框架

集合框架包含的内容&#xff1a; 集合框架的接口&#xff1a; List接口实现类 ArrayList 1 package com.jredu.ch01;3 import java.util.ArrayList;5 import java.util.List;7 public class ArrayListTest {9 public static void main(String[] args) { 10 // TODO…

Java中的类型安全的空集合

我之前曾在Java Collections类的实用程序上进行过博客撰写&#xff0c;并且特别地在使用Usings Collections Methods上的博客emptyList&#xff08;&#xff09;&#xff0c;emptyMap&#xff08;&#xff09;和emptySet&#xff08;&#xff09;上进行了博客撰写。 在本文中&a…

剑指offer二十二之从上往下打印二叉树

一、题目 从上往下打印出二叉树的每个节点&#xff0c;同层节点从左至右打印。 二、思路 二叉树的层次遍历&#xff0c;可以借助队列实现。具体思路详见注释。 三、代码 import java.util.ArrayList; import java.util.LinkedList; /** public class TreeNode {int val 0;Tree…

arduino i2c 如何写16位寄存器_arduino入门

硬件&#xff1a;Arduino Uno是基于ATmega328P(数据表)的微控制器板。它具有14个数字输入/输出引脚(其中6个可用作PWM输出)&#xff0c;6个模拟输入&#xff0c;工作电压5v&#xff0c;输入电压7-12v。串行&#xff1a;0(RX)和1(TX)用于接收(RX)和发送(TX)TTL串行数据。这些引脚…

mysql序列号生成_一文看懂mycat的6种全局序列号实现方式

概述在实现分库分表的情况下&#xff0c;数据库自增主键已无法保证自增主键的全局唯一。为此&#xff0c;MyCat 提供了全局sequence&#xff0c;并且提供了包含本地配置和数据库配置等多种实现方式。下面对这几种实现方式做一下介绍。1、本地文件方式原理&#xff1a;此方式 My…

android.graphics.Paint方法setXfermode (Xfermode x...

[java] view plaincopymPaint new Paint(); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN)); 常见的Xfermode&#xff08;SRC为原图&#xff0c;DST为目标图&#xff09;&#xff0c;把代码中的SRC_IN换成下图指定的模式就会出现对应的效果图…