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>>();
@Inject
private BayeuxServer _bayeux;
@Session
private 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 list
ClientSessionChannel 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 {
@Override
protected 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
cometd