react+springboot 結合websocket實現(xiàn)即時通信

react前端界面使用websoket:

(注意:不能在生命周期函數(shù)內調用websocket)

在用戶登錄的時候調用:

const?ws?=?new?WebSocket('ws://192.168.1.118:8080//productWebSocket/001'); ?? //切記需要用ws或者wss甩卓,不能使用http

????????ws.onopen?=?function?(e)?{

??????????console.log('連接上?ws?服務端了');

????????}

????????ws.onmessage?=?(msg)=>?{?

????????????console.log('接收服務端發(fā)過來的消息:?%o',?msg);?


????????};?

????????ws.onclose?=?function?(e)?{

????????????console.log('ws?連接關閉了');

????????????console.log(e);

????????}

前端代碼就這么簡單烤宙;onopen的回調函數(shù)钠糊,標識與服務器成功連接撵摆,onmassage回調函數(shù)為后端服務器推送過來的消息


java代碼部分:

首先引入jar包:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-websocket</artifactId>

</dependency>


其次websocket工具類? WebSocketConfig和MyEndpointConfigure


import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**

* 開啟WebSocket支持

* @author zhengkai.blog.csdn.net

*/

@Configuration

public class WebSocketConfig {

@Bean

? ? public ServerEndpointExporter serverEndpointExporter() {

return new ServerEndpointExporter();

}

@Bean

? ? public MyEndpointConfigure newConfigure() {

return new MyEndpointConfigure();

}

}

-------------------------------------------------------------------------------------------------------------------------------------------------------

import javax.websocket.server.ServerEndpointConfig;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

/**

* @Author:JCccc

* @Description:

* @Date: created in 15:56 2019/5/13

*/

public class MyEndpointConfigureextends ServerEndpointConfig.Configuratorimplements ApplicationContextAware {

private static volatile BeanFactorycontext;

@Override

? ? public T getEndpointInstance(Class clazz)throws InstantiationException {

return context.getBean(clazz);

}

@Override

? ? public void setApplicationContext(ApplicationContext applicationContext)throws BeansException {

MyEndpointConfigure.context = applicationContext;

}

}




再次邏輯層的service創(chuàng)建ProductWebSocket

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CopyOnWriteArraySet;

import java.util.concurrent.atomic.AtomicInteger;

import javax.websocket.OnClose;

import javax.websocket.OnError;

import javax.websocket.OnMessage;

import javax.websocket.OnOpen;

import javax.websocket.Session;

import javax.websocket.server.PathParam;

import javax.websocket.server.ServerEndpoint;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;

import road.system.config.MyEndpointConfigure;

/**

* @Author:JCccc

* @Description:

* @Date: created in 15:56 2019/5/13

*/

@Component

@ServerEndpoint(value ="/productWebSocket/{userId}", configurator = MyEndpointConfigure.class)

public class ProductWebSocket {

// 靜態(tài)變量剂跟,用來記錄當前在線連接數(shù)。應該把它設計成線程安全的象缀。

? ? private static final AtomicIntegerOnlineCount =new AtomicInteger(0);

// concurrent包的線程安全Set跪削,用來存放每個客戶端對應的ProductWebSocket對象。

? ? private static CopyOnWriteArraySetwebSocketSet =new CopyOnWriteArraySet();

// 與某個客戶端的連接會話陵刹,需要通過它來給客戶端發(fā)送數(shù)據(jù)

? ? private Sessionsession;

private Loggerlog = LoggerFactory.getLogger(ProductWebSocket.class);

/**

* 連接建立成功調用的方法

*/

? ? @OnOpen

? ? public void onOpen(@PathParam("userId")String userId, Session session) {

log.info("新客戶端連入默伍,用戶id:" + userId);

this.session = session;

webSocketSet.add(this);// 加入set中

? ? ? ? addOnlineCount();// 在線數(shù)加1

? ? ? ? if(userId!=null) {

List totalPushMsgs =new ArrayList();

totalPushMsgs.add(userId+"連接成功-"+"-當前在線人數(shù)為:"+getOnlineCount());

if(totalPushMsgs !=null && !totalPushMsgs.isEmpty()) {

totalPushMsgs.forEach(e -> sendMessage(e));

}

}

}

/**

* 連接關閉調用的方法

*/

? ? @OnClose

? ? public void onClose() {

log.info("一個客戶端關閉連接");

webSocketSet.remove(this);// 從set中刪除

? ? ? ? subOnlineCount();// 在線數(shù)減1

? ? }

/**

* 收到客戶端消息后調用的方法

*

? ? * @param message

? ? *? ? ? ? ? ? 客戶端發(fā)送過來的消息

*/

? ? @OnMessage

? ? public void onMessage(String message, Session session) {

log.info("用戶發(fā)送過來的消息為:"+message);

}

/**

* 發(fā)生錯誤時調用

*/

? ? @OnError

? ? public void onError(Session session, Throwable error) {

log.error("websocket出現(xiàn)錯誤");

error.printStackTrace();

}

public void sendMessage(String message) {

try {

this.session.getBasicRemote().sendText(message);

log.info("推送消息成功,消息為:" + message);

}catch (IOException e) {

e.printStackTrace();

}

}

/**

* 群發(fā)自定義消息

*/

? ? public static void sendInfo(String message)throws IOException {

for (ProductWebSocket productWebSocket :webSocketSet) {

productWebSocket.sendMessage(message);

}

}

public static synchronized int getOnlineCount() {

return OnlineCount.get();

}

public static synchronized void addOnlineCount() {

OnlineCount.incrementAndGet();// 在線數(shù)+1

? ? }

public static synchronized void subOnlineCount() {

OnlineCount.decrementAndGet();// 在線數(shù)-1

? ? }

}


最后衰琐,在controllerceng調用類的方法

我這里是后端給前端推送消息也糊,所以代碼調用了 ?sendInfo 這個方法

@RequestMapping("/push")

@ResponseBody

public JSONObject pushToWeb( String message)throws IOException {

message ="發(fā)送消息";

System.out.println("開始發(fā)送消息");

ProductWebSocket.sendInfo(message);

JSONObject json =new JSONObject();

json.put("code","200");

return json;

}


簡單的消息推送就完成了,全是干貨羡宙,粘貼即用狸剃,需要深入研究其他需求的可以看看官方的具體調用方法

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市狗热,隨后出現(xiàn)的幾起案子钞馁,更是在濱河造成了極大的恐慌,老刑警劉巖匿刮,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件僧凰,死亡現(xiàn)場離奇詭異,居然都是意外死亡熟丸,警方通過查閱死者的電腦和手機训措,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來光羞,“玉大人绩鸣,你說我怎么就攤上這事∩炊遥” “怎么了全闷?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長萍启。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么勘纯? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任局服,我火速辦了婚禮,結果婚禮上驳遵,老公的妹妹穿的比我還像新娘淫奔。我一直安慰自己,他們只是感情好堤结,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布唆迁。 她就那樣靜靜地躺著,像睡著了一般竞穷。 火紅的嫁衣襯著肌膚如雪唐责。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天瘾带,我揣著相機與錄音鼠哥,去河邊找鬼。 笑死看政,一個胖子當著我的面吹牛朴恳,可吹牛的內容都是我干的。 我是一名探鬼主播允蚣,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼于颖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嚷兔?” 一聲冷哼從身側響起森渐,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谴垫,沒想到半個月后章母,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡翩剪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年乳怎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片前弯。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚪缀,死狀恐怖,靈堂內的尸體忽然破棺而出恕出,到底是詐尸還是另有隱情询枚,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布浙巫,位于F島的核電站金蜀,受9級特大地震影響刷后,放射性物質發(fā)生泄漏。R本人自食惡果不足惜渊抄,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一尝胆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧护桦,春花似錦含衔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至催享,卻和暖如春杭隙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背睡陪。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工寺渗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人兰迫。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓信殊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親汁果。 傳聞我的和親對象是個殘疾皇子涡拘,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354