Java后端向前端推送消息完整代碼實(shí)例
1、WebSocketConfig配置類
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;
@Configuration
@EnableWebSocket
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
2、WebSocket消息發(fā)送接收
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Component
@ServerEndpoint(value = "/web/{id}")
public class WebSocketProcess {
/*
* 持有每個(gè)webSocket對(duì)象,以key-value存儲(chǔ)到線程安全ConcurrentHashMap,
*/
private static ConcurrentHashMap<Long, WebSocketProcess> concurrentHashMap = new ConcurrentHashMap<>(12);
/**
* 會(huì)話對(duì)象
**/
private Session session;
/*
* 客戶端創(chuàng)建連接時(shí)觸發(fā)
* */
@OnOpen
public void onOpen(Session session, @PathParam("id") long id) {
//每新建立一個(gè)連接,就把當(dāng)前客戶id為key,this為value存儲(chǔ)到map中
this.session = session;
concurrentHashMap.put(id, this);
log.info("Open a websocket. id={}", id);
}
/**
* 客戶端連接關(guān)閉時(shí)觸發(fā)
**/
@OnClose
public void onClose(Session session, @PathParam("id") long id) {
//客戶端連接關(guān)閉時(shí),移除map中存儲(chǔ)的鍵值對(duì)
concurrentHashMap.remove(id);
log.info("close a websocket, concurrentHashMap remove sessionId= {}", id);
}
/**
* 接收到客戶端消息時(shí)觸發(fā)
*/
@OnMessage
public void onMessage(String message, @PathParam("id") String id) {
log.info("receive a message from client id={},msg={}", id, message);
}
/**
* 連接發(fā)生異常時(shí)候觸發(fā)
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("Error while websocket. ", error);
}
/**
* 發(fā)送消息到指定客戶端
*
* @param id
* @param message
*/
public void sendMessage(long id, String message) throws Exception {
//根據(jù)id,從map中獲取存儲(chǔ)的webSocket對(duì)象
WebSocketProcess webSocketProcess = concurrentHashMap.get(id);
if (!ObjectUtils.isEmpty(webSocketProcess)) {
//當(dāng)客戶端是Open狀態(tài)時(shí),才能發(fā)送消息
if (webSocketProcess.session.isOpen()) {
webSocketProcess.session.getBasicRemote().sendText(message);
} else {
log.error("websocket session={} is closed ", id);
}
} else {
log.error("websocket session={} is not exit ", id);
}
}
/**
* 發(fā)送消息到所有客戶端
*/
public void sendAllMessage(String msg) throws Exception {
log.info("online client count={}", concurrentHashMap.size());
Set<Map.Entry<Long, WebSocketProcess>> entries = concurrentHashMap.entrySet();
for (Map.Entry<Long, WebSocketProcess> entry : entries) {
Long cid = entry.getKey();
WebSocketProcess webSocketProcess = entry.getValue();
boolean sessionOpen = webSocketProcess.session.isOpen();
if (sessionOpen) {
webSocketProcess.session.getBasicRemote().sendText(msg);
} else {
log.info("cid={} is closed,ignore send text", cid);
}
}
}
}
3、消息推送Controller
import com.xyl.web.controller.common.WebSocketProcess;
import com.xyl.web.controller.common.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/testws")
public class WebSocketController {
/**
* 注入WebSocketProcess
**/
@Autowired
private WebSocketProcess webSocketProcess;
/**
* 向指定客戶端發(fā)消息
*
* @param id
*/
@PostMapping(value = "sendMsgToClientById")
public void sendMsgToClientById(@RequestParam long id, @RequestParam String text) {
try {
webSocketProcess.sendMessage(id, text);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 發(fā)消息到所有客戶端
*
* @param text
*/
@PostMapping(value = "sendMsgToAllClient")
public void sendMsgToAllClient(@RequestParam String text) {
try {
webSocketProcess.sendAllMessage(text);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 定時(shí)向客戶端推送消息
* @throws Exception
*/
@Scheduled(cron = "0/5 * * * * ?")
private void configureTasks() throws Exception {
webSocketProcess.sendAllMessage("向前端推送消息內(nèi)容");
}
}
4、測(cè)試HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>websocket測(cè)試</title>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
</head>
<body>
<div id="content"></div>
</body>
<script type="text/javascript">
$(function(){
var ws;
//檢測(cè)瀏覽器是否支持webSocket
if("WebSocket" in window){
$("#content").html("您的瀏覽器支持webSocket!");
//模擬產(chǎn)生clientID
let clientID = Math.ceil(Math.random()*100);
//創(chuàng)建 WebSocket 對(duì)象,注意請(qǐng)求路徑?。。?!
ws = new WebSocket("ws://127.0.0.1:9095/web/"+clientID);
//與服務(wù)端建立連接時(shí)觸發(fā)
ws.onopen = function(){
$("#content").append("<p>與服務(wù)端建立連接建立成功!您的客戶端ID="+clientID+"</p>");
//模擬發(fā)送數(shù)據(jù)到服務(wù)器
ws.send("你好服務(wù)端!我是客戶端 "+clientID);
}
//接收到服務(wù)端消息時(shí)觸發(fā)
ws.onmessage = function (evt) {
let received_msg = evt.data;
$("#content").append("<p>接收到服務(wù)端消息:"+received_msg+"</p>");
};
//服務(wù)端關(guān)閉連接時(shí)觸發(fā)
ws.onclose = function() {
console.error("連接已經(jīng)關(guān)閉.....")
};
}else{
$("#content").html("您的瀏覽器不支持webSocket!");
}
})
</script>
</html>
總結(jié)
到此這篇關(guān)于Java后端向前端推送消息完整代碼的文章就介紹到這了,更多相關(guān)Java后端向前端推送消息內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java8 使用CompletableFuture 構(gòu)建異步應(yīng)用方式
這篇文章主要介紹了Java8 使用CompletableFuture 構(gòu)建異步應(yīng)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
java批量導(dǎo)入Excel數(shù)據(jù)超詳細(xì)實(shí)例
這篇文章主要給大家介紹了關(guān)于java批量導(dǎo)入Excel數(shù)據(jù)的相關(guān)資料,EXCEL導(dǎo)入就是文件導(dǎo)入,操作代碼是一樣的,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下2023-08-08
Springboot集成RabbitMQ死信隊(duì)列的實(shí)現(xiàn)
在大多數(shù)的MQ中間件中,都有死信隊(duì)列的概念。本文主要介紹了Springboot集成RabbitMQ死信隊(duì)列的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
詳解SpringMVC組件之HandlerMapping(一)
這篇文章主要介紹了詳解SpringMVC組件之HandlerMapping(一),HandlerMapping組件是Spring?MVC核心組件,用來(lái)根據(jù)請(qǐng)求的request查找對(duì)應(yīng)的Handler,在Spring?MVC中,有各式各樣的Web請(qǐng)求,每個(gè)請(qǐng)求都需要一個(gè)對(duì)應(yīng)的Handler來(lái)處理,需要的朋友可以參考下2023-08-08
一起來(lái)看看springboot集成redis的使用注解
這篇文章主要為大家詳細(xì)介紹了springboot集成redis的使用注解,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
java 如何往已經(jīng)存在的excel表格里面追加數(shù)據(jù)的方法
這篇文章主要介紹了java 如何往已經(jīng)存在的excel表格里面追加數(shù)據(jù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
Lombok @Slf4j log對(duì)象沒(méi)有info等方法不可用問(wèn)題及解決
本文主要介紹了如何解決Spring Boot項(xiàng)目中的日志依賴沖突問(wèn)題,以及如何使用Lombok和SLF4J進(jìn)行日志記錄,Lombok通過(guò)生成Logger對(duì)象簡(jiǎn)化了日志記錄,而SLF4J提供了一個(gè)統(tǒng)一的日志接口,允許開(kāi)發(fā)者在運(yùn)行時(shí)選擇不同的日志實(shí)現(xiàn)2024-12-12

