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.pswp.cn/news/371067.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371067.shtml
英文地址,請注明出處:http://en.pswp.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…

ActiveMQ:了解內存使用情況

正如最近的一些郵件列表電子郵件和從Google返回的許多信息所表明的那樣&#xff0c;ActiveMQ的SystemUsage尤其是MemoryUsage功能使一些人感到困惑。 我將嘗試解釋有關MemoryUsage的一些細節&#xff0c;這些細節可能有助于理解它的工作方式。 我將不介紹StoreUsage和TempUsage…

php設置排序,7種php基本排序實現方法

本文總結了一下常用的7種排序方法&#xff0c;并用php語言實現。1、直接插入排序/** 直接插入排序,插入排序的思想是&#xff1a;當前插入位置之前的元素有序&#xff0c;* 若插入當前位置的元素比有序元素最后一個元素大&#xff0c;則什么也不做&#xff0c;* 否則在有序序列…

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 權重是可…

android開發中用到的px、dp、sp

先介紹一下這幾個單位&#xff1a;px : pixels(像素),相應屏幕上的實際像素點。dip :device independent pixels&#xff0c;與密度無關的像素&#xff0c;基于屏幕密度的抽象單位。在每英寸160點的顯示器上。 1dp 1px &#xff0c;即1 &#xff1a;1關系。&#xff08;dp 就是…

Spring:設置日志依賴項

這篇文章描述了如何在Spring中設置日志依賴。 它基于Dave Syer的帖子中提供的信息 。 這里提供有關Java日志記錄框架的提醒。 該代碼示例可在GitHub的Spring-Logging-Dependencies目錄中找到。 Spring使用Jakarta Commons Logging API&#xff08;JCL&#xff09;。 不幸的是&…

【Codeforces Round #424 (Div. 2) C】Jury Marks

【Link】:http://codeforces.com/contest/831/problem/C 【Description】 有一個人參加一個比賽; 他一開始有一個初始分數x; 有k個評委要依次對這個人評分; 依照時間順序依次給出這k個人的評分(可能為負數,負數的時候,表示分數會降低,而如果為正,則分數增加); 然后有一個…

php copy 文件夾,php刪除與復制文件夾及其文件夾下所有文件的實現代碼

/*復制xCopy函數用法&#xff1a;* xCopy("feiy","feiy2",1):拷貝feiy下的文件到 feiy2,包括子目錄* xCopy("feiy","feiy2",0):拷貝feiy下的文件到 feiy2,不包括子目錄*參數說明&#xff1a;* $source:源目錄名* $destina…

安卓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應用程序開發的人員閱讀此書。 為…

java 饑餓現象,Java單例模式、饑餓模式代碼實例

class MyThreadScopeData {// 單例private MyThreadScopeData() {}// 提供獲取實例方法public static synchronized MyThreadScopeData getThreadInstance() {// 從當前線程范圍內數據集中獲取實例對象MyThreadScopeData instance map.get();if (instance null) {instance n…

12. 抽象與密封

一、抽象類與抽象方法 1、抽象類與抽象方法聲明&#xff1a; 抽象類&#xff1a;在面向對象的概念中&#xff0c;所有的類都是通過對象來描述&#xff0c;但并不是所有的類都用來描述對象。如果一個類中沒有足夠的信息來描繪一個具體的對象&#xff0c;這樣的類就是抽象類。  …