Java實(shí)現(xiàn)使用Websocket發(fā)送消息詳細(xì)代碼舉例
前言
- 需求背景:之前做了個樓棟房間數(shù)量出租了多少,需要在數(shù)據(jù)大屏上實(shí)時展示
- 解決方案:以切面攔截出租接口,當(dāng)有房間出租時重新查詢相關(guān)數(shù)據(jù),封裝好用websocket實(shí)時傳送前端展示
一、websocket 簡介
WebSocket 是一種在單個TCP連接上進(jìn)行全雙工通信的協(xié)議。WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。在WebSocket API中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。
二、websocket 如何使用
1.引入依賴包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.創(chuàng)建 WebSocketConfig
package com.alpari.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @author wangrui
* @date 2023/11/8
**/
@Configuration
@EnableWebSocket
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpoint() {
return new ServerEndpointExporter();
}
/**
* 注意事項(xiàng):
* WebSocket啟動的時候優(yōu)先于spring容器,從而導(dǎo)致在WebSocketServer中調(diào)用業(yè)務(wù)Service會報(bào)空指針異常
* 所以需要在WebSocketServer中將所需要用到的service給靜態(tài)初始化一下
* 此處提前注入
*/
// @Autowired
// private void setXxx(XxxService xxxService) {
// WebSocketServer.xxxService = xxxService;
// }
}3.創(chuàng)建 WebSocketServer
package com.alpari.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @author wangrui
* @date 2023/11/8
* @description: 若在此類中直接調(diào)用service方法失敗,需要加上:public static XxxService xxxService; 另外在config中注入實(shí)例
**/
@Slf4j
@Component
@ServerEndpoint(value = "/websocket/{userId}")
public class WebSocketServer {
/**
* 當(dāng)前連接數(shù)
*/
private static int onlineCount = 0;
/**
* concurrent包的線程安全Set,用來存放每個客戶端對應(yīng)的MyWebSocket對象
*/
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
/**
* 與某個客戶端的連接會話,需要通過它來給客戶端發(fā)送數(shù)據(jù)
*/
private Session session;
/**
* 接收的用戶id
*/
private String userId;
/**
* 連接建立成功調(diào)用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
webSocketSet.add(this);
addOnlineCount(); //在線數(shù)加1
log.info("有新連接加入!當(dāng)前在線人數(shù)為" + getOnlineCount());
this.userId = userId;
try {
sendMessage("連接成功");
} catch (IOException e) {
log.error("websocket IO異常", e);
}
}
/**
* 連接關(guān)閉調(diào)用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this);
subOnlineCount(); //在線數(shù)減1
log.info("有一連接關(guān)閉!當(dāng)前在線人數(shù)為" + getOnlineCount());
}
/**
* 收到客戶端消息后調(diào)用的方法
*
* @param message 客戶端發(fā)送過來的消息
*/
@OnMessage
public void onMessage(String message) {
log.info("來自客戶端的消息:" + message);
//群發(fā)消息
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
log.error("發(fā)送消息失敗", e);
}
}
}
/**
* @param error 錯誤
*/
@OnError
public void onError( Throwable error) {
log.error("發(fā)生錯誤", error);
}
/**
* 發(fā)送消息
* @param message 消息
* @throws IOException 異常
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群發(fā)自定義消息
*/
public static void sendInfo(String message, @PathParam("userId") String userId) {
log.info("消息內(nèi)容:" + message);
for (WebSocketServer item : webSocketSet) {
try {
//這里可以設(shè)定只推送給這個sid的,為null則全部推送
if (userId == null) {
item.sendMessage(message);
} else if (item.userId.equals(userId)) {
item.sendMessage(message);
}
} catch (IOException e) {
log.error("消息發(fā)送失敗", e);
}
}
}
/**
* 獲取在線人數(shù)
* @return 在線人數(shù)
*/
public static synchronized int getOnlineCount() {
return onlineCount;
}
/**
* 在線人數(shù)加一
*/
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
/**
* 在線人數(shù)減一
*/
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}
4.在線測試
在線ws測試地址:http://www.jsons.cn/websocket/
- 輸入測試

- 后端返回的結(jié)果

5.模擬消息發(fā)送
/**
* 切面攔截?cái)?shù)據(jù)模擬給指定用戶或全部用戶發(fā)消息
*/
public void sendMessage(String userid) {
// 此處模擬數(shù)據(jù)大屏推送,以切面方式攔截相關(guān)接口,若數(shù)據(jù)發(fā)生變化,則將數(shù)據(jù)推送,不傳id則全部發(fā)送
String msg = "模擬數(shù)據(jù)";
WebSocketServer.sendInfo(msg, userid);
log.info("發(fā)送消息成功,消息內(nèi)容:{},接收人:{}", msg, userid);
}
總結(jié)
到此這篇關(guān)于Java實(shí)現(xiàn)使用Websocket發(fā)送消息的文章就介紹到這了,更多相關(guān)Java Websocket發(fā)送消息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中使用WebSocket的幾種方式
- 如何在Java中使用WebSocket協(xié)議
- springboot整合websocket后啟動報(bào)錯(javax.websocket.server.ServerContainer not available)
- Java WebSocket客戶端接收大量數(shù)據(jù)的三種方案
- 使用Java WebSocket獲取客戶端IP地址的示例代碼
- Java中實(shí)現(xiàn)WebSocket方法詳解
- 教你如何使用Java實(shí)現(xiàn)WebSocket
- 一步步教你如何使用Java實(shí)現(xiàn)WebSocket
- java后端+前端使用WebSocket實(shí)現(xiàn)消息推送的詳細(xì)流程
- JAVA 日常開發(fā)中Websocket示例詳解
相關(guān)文章
Java基礎(chǔ)學(xué)習(xí)之IO流應(yīng)用案例詳解
這篇文章主要為大家詳細(xì)介紹了Java?IO流的三個應(yīng)用案例:點(diǎn)名器、集合到文件和文件到集合,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-09-09
通過實(shí)例學(xué)習(xí)JAVA對象轉(zhuǎn)成XML輸出
這篇文章主要介紹了通過實(shí)例學(xué)習(xí)JAVA對象轉(zhuǎn)成XML輸出,做流程圖的項(xiàng)目時,新的流程定義為xml的,需要對xml與java對象進(jìn)行互轉(zhuǎn),下面我們來深入學(xué)習(xí),需要的朋友可以參考下2019-06-06
Java代碼實(shí)現(xiàn)循環(huán)隊(duì)列的示例代碼
隊(duì)列作為基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),是程序員的入門課。也是所有程序員必須掌握的一種數(shù)據(jù)結(jié)構(gòu),隊(duì)列在程序中廣泛應(yīng)用,因此我們應(yīng)該對隊(duì)列有深入的了解,接下來我們通過代碼來對隊(duì)列這種數(shù)據(jù)結(jié)構(gòu)進(jìn)行深度解析,感興趣的朋友一起看看吧2021-09-09
springboot基于keytool實(shí)現(xiàn)https的雙向認(rèn)證示例教程
這篇文章主要介紹了springboot基于keytool實(shí)現(xiàn)https的雙向認(rèn)證,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06
Java調(diào)用Python腳本實(shí)現(xiàn)HelloWorld的示例詳解
作為程序員,我們經(jīng)常會遇到需要在Java項(xiàng)目中調(diào)用Python腳本的場景,下面我們來看看如何從基礎(chǔ)到進(jìn)階,一步步實(shí)現(xiàn)Java與Python的"HelloWorld"交互吧2025-08-08
Java注解實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換的實(shí)例代碼
本篇文章主要介紹了Java注解實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換的實(shí)例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06
Java Collection和Collections的區(qū)別
本文主要介紹了Java Collection和Collections的區(qū)別,Collection?是表示集合的接口,而?Collections?是對集合進(jìn)行操作的工具類,下面就來介紹一下具體用法,感興趣的可以了解一下2023-12-12
Java struts2 validate用戶登錄校驗(yàn)功能實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Java struts2 validate用戶登錄校驗(yàn)功能實(shí)現(xiàn)的具體步驟,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-05-05
java?Object的hashCode方法的計(jì)算邏輯分析
這篇文章主要介紹了java?Object的hashCode方法的計(jì)算邏輯分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12

