WebSocket的ping與pong的java實(shí)現(xiàn)…
理解幾個(gè)知識(shí)點(diǎn)
- 訂閱地址 :如stompEndpointRegistry.addEndpoint("/endpointWechat") 或使用@ServerEndpoint創(chuàng)建
- 容許跨域
- 是否開啟SockJS支持
- 推送:聲明SimpMessagingTemplate ,調(diào)用convertAndSend方法(或者使用@SendTo和@SendToUser注解)
- 一對(duì)一發(fā)送消息
- Principal:身份驗(yàn)證和授權(quán)
- stomp協(xié)議:STOMP即Simple (or Streaming) Text Orientated Messaging Protocol药版,簡單(流)文本定向消息協(xié)議劫瞳,它提供了一個(gè)可互操作的連接格式呀酸,允許STOMP客戶端與任意STOMP消息代理(Broker)進(jìn)行交互坤学。
- WebSocket(stomp服務(wù)端)
WebSocketSession 發(fā)送的消息類型(sendMessage)
前端涉及js
- jquery
- sockJs :
- stomp.min.js(stomp客戶端)
- STOMP Simple (or Streaming) Text Orientated Messaging Protocol扣唱,簡單(流)文本定向消息協(xié)議茄厘,它提供了一個(gè)可互操作的連接格式蚁阳,允許STOMP客戶端與任意STOMP消息代理(Broker)進(jìn)行交互
js 前端鏈接websocket的方式
STOMP 鏈接成功夕凝、失敗宝穗、主動(dòng)斷開等參閱
STOMP 客戶端 API 整理:https://blog.csdn.net/jqsad/article/details/77745379
html頁面,連接stomp服務(wù)端,訂閱/topic/myTop的消息(訂閱topic或myTop)
方式1:
var socket = new SockJS('/endpointWechat');
方式2
//前臺(tái) js 中 new SockJS 的時(shí)候,一起是3個(gè)參數(shù)項(xiàng)的烁挟,另外2個(gè)參數(shù)項(xiàng)可以傳遞目前是哪個(gè)用戶的標(biāo)識(shí)寇荧,這樣就可以在后臺(tái)區(qū)分出來連接是哪個(gè)用戶建立的
var socket = new SockJS(url, undefined, {protocols_whitelist: ['websocket']});
方式3:直接攜帶參數(shù)
var socket = new SockJS('/endpointWechat'+ '?token='+str_token); //'?token=token8888'
Android端的鏈接方式
SpringBoot 使用的websocket 協(xié)議,不是標(biāo)準(zhǔn)的websocket協(xié)議齐疙,使用的是名稱叫做STOMP的協(xié)議障陶。
要想與js方式調(diào)用:stompClient.send("/sendServer", {}, JSON.stringify({ 'name': message }));届榄,需要Android采用STOMP方式調(diào)用
更多細(xì)節(jié)參考
stomp協(xié)議 官方:http://stomp.github.io/
csdn 大神博客:http://blog.csdn.net/chszs/article/details/5200554
iteye 大神博客 http://diaocow.iteye.com/blog/1725186 (務(wù)必看一下莉兰,了解協(xié)議的一些使用)
SpringBoot webSocket 發(fā)送廣播挑围、點(diǎn)對(duì)點(diǎn)消息,Android接收
WebSocket可以應(yīng)用于即時(shí)通信等場景糖荒,比如現(xiàn)在直播很火熱杉辙,直播中的彈幕也可以使用WebSocket去實(shí)現(xiàn)。
WebSocket的協(xié)議內(nèi)容可以見 The WebSocket Protocol捶朵,講得最全面的官方說明蜘矢。簡單介紹可以見維基百科WebSocket
在Android客戶端,一般可以使用下面的庫完成WebSocket通信
- okhttp综看,一般人我不告訴他okhttp還可以用來進(jìn)行WebSocket通信
- Java-WebSocket品腹,純java實(shí)現(xiàn)的WebSocket客戶端和服務(wù)端實(shí)現(xiàn)
Android最佳實(shí)踐——深入淺出WebSocket協(xié)議:https://blog.csdn.net/blueangle17/article/details/80701152
springboot 的工程
pom.xml引入
<!--添加websocket依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--添加alibaba 的fastjson引用-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.46</version>
</dependency>
編寫MyHandShakeInterceptor類(主要作用用于對(duì)握手前檢查合法性)
// 初始化對(duì)象,攔截握手红碑,發(fā)生在鏈接之前
@Component
public class MyHandShakeInterceptor implements HandshakeInterceptor {
private static final Logger log = LoggerFactory.getLogger(MyHandShakeInterceptor.class);
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
//http://localhost:8080/endpointWechat/948/dtdzvrrs/websocket?token=token8888
//js調(diào)用:
// var host="http://localhost:8080";
// var socket = new SockJS(host+'/endpointWechat' + '?token=token8888');
log.info("this.getClass().getCanonicalName() = {},在這里決定是否允許鏈接,http協(xié)議轉(zhuǎn)換websoket協(xié)議進(jìn)行前, 握手前Url = {}",this.getClass().getCanonicalName(),request.getURI());
//System.out.println(this.getClass().getCanonicalName() + " 在這里決定是否允許鏈接,http協(xié)議轉(zhuǎn)換websoket協(xié)議進(jìn)行前, 握手前"+request.getURI() );
// http協(xié)議轉(zhuǎn)換websoket協(xié)議進(jìn)行前舞吭,可以在這里通過session信息判斷用戶登錄是否合法
//request.getURI().getPath(); // /endpointWechat/896/mdoqjqia/websocket
//request.getURI().getHost();//localhost
//request.getURI().string ; // http://localhost:8080/endpointWechat/896/mdoqjqia/websocket?token=token8888
//request.getURI().getQuery() ; // token=token8888
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) request;
HttpServletRequest httpRequest = servletServerHttpRequest.getServletRequest();
String myToken = httpRequest.getParameter("token");
if (null != myToken && !StringUtils.isEmpty(myToken)){
WebSocketSession webSocketSession = SocketManager.get(myToken);
if (webSocketSession != null){
log.info("token = {},已經(jīng)在建立鏈接列表,不允許重復(fù)鏈接",myToken);
}else {
return true;
}
}
}
return false; //不允許建立鏈接
//return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
//握手成功后,
System.out.println(this.getClass().getCanonicalName() + "握手成功后...");
}
}
成功連接的情況
配置類WebSocketConfig
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Autowired
private MyHandShakeInterceptor myHandShakeInterceptor;
@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
//以 /endpointWechat端點(diǎn)析珊,客戶端就可以通過這個(gè)端點(diǎn)來進(jìn)行連接
stompEndpointRegistry.addEndpoint("/endpointWechat").setAllowedOrigins("*")
.withSockJS();//開啟SockJS支持
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic","/user"); //客戶端訂閱服務(wù)的前綴
registry.setUserDestinationPrefix("/user"); //開啟一對(duì)一發(fā)送消息
}
}
控制器WebScoketController
/**
* 創(chuàng)建人:牽手生活
* 創(chuàng)建時(shí)間:2019-01-14 17:17
*/
@Controller
public class WebSocketController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate; //聲明SimpMessagingTemplate (或者使用@SendTo和@SendToUser注解)羡鸥,SimpMessagingTemplate可以在需要用到推送的地方如Controller,service忠寻,Component等地方
private static final Logger log = LoggerFactory.getLogger(WebSocketController.class);
// 收到消息記數(shù)
private AtomicInteger count = new AtomicInteger(0);
/**
* @MessageMapping 指定要接收消息的地址惧浴,類似@RequestMapping。除了注解到方法上奕剃,也可以注解到類上
* @MessageMapping("/receive") 對(duì)應(yīng)html中的 stompClient.send("/app/receive", {}, JSON.stringify({ 'name': name }));
* 多出來的“/app"是WebSocKetConfig中定義的,如不定義衷旅,則HTML中對(duì)應(yīng)改為stompClient.send("/receive")
* @SendTo默認(rèn) 消息將被發(fā)送到與傳入消息相同的目的地
* 消息的返回值是通過{@link org.springframework.messaging.converter.MessageConverter}進(jìn)行轉(zhuǎn)換
* @SendTo("/topic/getResponse") 指定訂閱路徑,對(duì)應(yīng)HTML中的stompClient.subscribe('/topic/getResponse', ……)
* 意味將信息推送給所有訂閱了"/topic/getResponse"的用戶
* @param requestMessage
* @return
*/
@MessageMapping("/receive")
@SendTo("/topic/getResponse") //topic是廣播全局通訊
public ResponseMessage receive(RequestMessage requestMessage){
log.info("receive message = {}" , JSONObject.toJSONString(requestMessage));
ResponseMessage responseMessage = new ResponseMessage();
responseMessage.setResponseMessage("響應(yīng)消息WebSocketController receive [" + count.incrementAndGet() + "] records:"+JSONObject.toJSONString(requestMessage));
return responseMessage;
}
/**
* 客戶端發(fā)消息纵朋,服務(wù)端接收
*
* @param requestMessage
*/
// 相當(dāng)于RequestMapping
@MessageMapping("/sendServer")
public void sendServer(RequestMessage requestMessage) {
log.info("sendServer 客服端發(fā)送的芜茵,不需要發(fā)回給客戶端message:{}", JSONObject.toJSONString(requestMessage));
}
@MessageMapping("/sendServer_str")
public void sendServer_str(String message) {
log.info("sendServer 客服端發(fā)送的,不需要發(fā)回給客戶端message:{}", message);
}
/**
* 客戶端發(fā)消息倡蝙,大家都接收九串,相當(dāng)于直播說話
*
* @param message
* @return
*/
@MessageMapping("/sendAllUser_str")
@SendTo("/topic/sendTopic_str")
public String sendAllUser_str(String message) {
// 也可以采用template方式
return "服務(wù)的處理后的:"+message;
}
@MessageMapping("/sendAllUser")
@SendTo("/topic/sendTopic")
public ResponseMessage sendAllUser(RequestMessage requestMessage) {
log.info("sendTopic 請(qǐng)求message = {}" , JSONObject.toJSONString(requestMessage));
ResponseMessage responseMessage = new ResponseMessage();
responseMessage.setResponseMessage(JSONObject.toJSONString(requestMessage));
return responseMessage;
}
/**
* 點(diǎn)對(duì)點(diǎn)用戶聊天,這邊需要注意寺鸥,由于前端傳過來json數(shù)據(jù)猪钮,所以使用@RequestBody
* 這邊需要前端開通var socket = new SockJS(host+'/myUrl' + '?token=token8888'); token為指定name
* @param map
*/
@MessageMapping("/sendMyUser")
public void sendMyUser(@RequestBody Map<String, String> map) {
log.info("sendMyUser 請(qǐng)求 map = {}", map);
WebSocketSession webSocketSession = SocketManager.get(map.get("name"));
if (webSocketSession != null) {
log.info("sendMyUser sessionId = {}", webSocketSession.getId());
//生成IJSONResult對(duì)象的data數(shù)據(jù)
ResponseMessage responseMessage = new ResponseMessage();
responseMessage.setResponseMessage("響應(yīng)消息WebSocketController sendMyUser records:"+map.get("message"));
simpMessagingTemplate.convertAndSendToUser(map.get("name"), "/queue/sendUser", IJSONResult.ok(responseMessage));
//simpMessagingTemplate.convertAndSendToUser(map.get("name"), "/queue/sendUser", JSONObject.toJSONString(responseMessage)); //ok
}
}
@MessageMapping("/sendMyUser_obj")
//@SendToUser("/user/queue/sendUser_obj") //添加看看
public ResponseMessage sendMyUser_obj(RequestMessage requestMessage) {
log.info("sendMyUser message = {}" , JSONObject.toJSONString(requestMessage));
ResponseMessage responseMessage = new ResponseMessage();
responseMessage.setResponseMessage("響應(yīng)消息WebSocketController sendMyUser [" + count.incrementAndGet() + "] records:"+JSONObject.toJSONString(requestMessage));
return responseMessage;
}
//http://localhost:8080//wechatTask/websocket/index 轉(zhuǎn)發(fā)到頁面
@RequestMapping(value="/wechatTask/websocket/index")
public String websocketIndex(HttpServletRequest req){
log.info("websocketIndex接口的 req.getRemoteHost(){}" , req.getRemoteHost());
return "websocket/simple/websocket-index";
}
}
添加thymeleaf的模板-websocket-index.html
說明
客戶端可以通過使用Stomp.js和sockjs-client連接
var socket = new SockJS('/endpointWechat'+ '?token='+str_token);
或
socket連接對(duì)象也可通過WebSocket(不通過SockJS)連接
var socket=new WebSocket('/endpointWechat'+ '?token='+str_token);
stompClient.connect()方法簽名:
client.connect(headers, connectCallback, errorCallback);
websocket-index.html如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spring Boot+WebSocket例子</title>
<script src="https://cdn.bootcss.com/sockjs-client/1.3.0/sockjs.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<link rel="stylesheet">
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<!--引入jqurey庫-->
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<body onload="disconnect()" >
<div>
<p> 創(chuàng)建鏈接:var socket = new SockJS(host+'/myUrl' + '?token=token8888')</p>
<p> token 是你上面輸入的token 或username</p>
<p>點(diǎn)擊鏈接,如果鏈接成功胆建,則可以與后臺(tái)通過websocket進(jìn)行通信 </p>
<p>輸入你要發(fā)送的內(nèi)容(這里是你的名字--以后改為json對(duì)象)</p>
<p>點(diǎn)擊發(fā)送烤低,會(huì)把輸入的內(nèi)容通過websocket發(fā)送到后臺(tái)</p>
<p>查看log 更多細(xì)節(jié)查看chrome的開發(fā)者選項(xiàng)中的控制臺(tái)</p>
</div>
<div >
<label >輸入你新建鏈接是的token或name(用于點(diǎn)對(duì)點(diǎn)通信)?</label>
<input type="text" id="mytoken" value="wxid_on8oksh88zo22" placeholder="Your token/name here...如:4567"></input>
</div>
<div >
<label id = "state-info" >***連接狀態(tài)-未連接***</label>
</div>
</div>
<div>
<div>
<button id="connect" onclick="connect();">連接</button>
<button id="disconnect" disabled="disabled" onclick="disconnect();">斷開連接</button>
</div>
<div id="conversationDiv">
<label>輸入你要發(fā)送的內(nèi)容</label><input type="text" id="message" value="fdsfs"/>
<button id="sendName" onclick="sendName();">發(fā)送</button>
<button id="sendServer" onclick="sendServer();">發(fā)送sendServer</button>
<button id="sendTopic" onclick="sendTopic();">發(fā)送sendTopic</button>
<button id="sendMyUser" onclick="sendMyUser();">發(fā)送點(diǎn)對(duì)點(diǎn)</button>
<!--用于顯示通過websocket的響應(yīng)數(shù)據(jù)-->
<p id="response"></p>
</div>
</div>
<script type="text/javascript">
var stompClient = null;
function setConnected(connected) {
document.getElementById('connect').disabled = connected;
document.getElementById('disconnect').disabled = !connected;
document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
$('#response').html();
}
function connect() {
//判斷是否輸入token
var val = $('#mytoken').val();
var str_token = val.replace(/(^\s*)|(\s*$)/g, '');//去除空格;
if (str_token == '' || str_token == undefined || str_token == null){
alert('建立鏈接前笆载,需要輸入token');
return
}
// websocket的連接地址扑馁,此值等于WebSocketMessageBrokerConfigurer中registry.addEndpoint("/endpointWechat").withSockJS()配置的地址
//var socket = new SockJS('/endpointWechat'); //
//建立連接對(duì)象(還未發(fā)起連接)
var socket = new SockJS('/endpointWechat'+ '?token='+str_token); //'?token=token8888'
//利用Stomp協(xié)議創(chuàng)建socket客戶端
stompClient = Stomp.over(socket);
/**
* 調(diào)用stompClient中的connect方法來連接服務(wù)端涯呻,
* 連接成功之后調(diào)用setConnected方法,該隱藏的隱藏腻要,該顯示的顯示
*/
stompClient.connect({},
function(frame) {
setConnected(true);
console.log('連接成功Connected: ' + frame);
document.getElementById("state-info").innerHTML = "***連接成功***";
// 客戶端訂閱消息的目的地址:此值WebSocketController中被@SendTo("/topic/getResponse")注解的里配置的值
stompClient.subscribe('/topic/getResponse', function(respnose){ //2
showResponse(JSON.parse(respnose.body).responseMessage);
});
//訂閱queue===接收廣播的
stompClient.subscribe('/topic/sendTopic', function(response) {
showResponse(JSON.parse(response.body).responseMessage);
//showResponse((respnose.body).responseMessage);//string返回的處理
});
//接收發(fā)個(gè)單個(gè)人的===點(diǎn)對(duì)點(diǎn)===????????為什么會(huì)收不到
var mytoken = $('#mytoken').val();
stompClient.subscribe('/user/queue/sendUser', function(response) { // '/user/queue/sendUser'===/'+mytoken+'
//showResponse(JSON.parse(response.body).responseMessage);
showResponseBody(response.body);//直接顯示response.body
});
},
function errorCallBack (error) {
// 連接失敗時(shí)(服務(wù)器響應(yīng) ERROR 幀)的回調(diào)方法
document.getElementById("state-info").innerHTML = "***連接失敗***";
console.log('連接失敗【' + error + '】');
}
);//end for connected
}
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
document.getElementById("state-info").innerHTML = "***連接未連接***";
console.log("Disconnected");
}
//后臺(tái)采用@SendTo("/topic/getResponse")注解
function sendName() {
var message = $('#message').val();
// 客戶端消息發(fā)送的目的:服務(wù)端使用WebSocketController中@MessageMapping("/receive")注解的方法來處理發(fā)送過來的消息
stompClient.send("/receive", {}, JSON.stringify({ 'name': message }));
}
//后臺(tái)采用@SendTo("/topic/getResponse")注解
function sendName() {
var message = $('#message').val();
// 客戶端消息發(fā)送的目的:服務(wù)端使用WebSocketController中@MessageMapping("/receive")注解的方法來處理發(fā)送過來的消息
stompClient.send("/receive", {}, JSON.stringify({ 'name': message }));
}
function sendTopic() { //發(fā)公告===類似發(fā)群公告
var message = $('#message').val();
// 客戶端消息發(fā)送的目的:服務(wù)端使用WebSocketController中@MessageMapping("/receive")注解的方法來處理發(fā)送過來的消息
stompClient.send("/sendAllUser", {}, JSON.stringify({ 'name': message }));
}
function sendServer() { //發(fā)送到服務(wù)端复罐,server不返回?cái)?shù)據(jù)
var message = $('#message').val();
// 客戶端消息發(fā)送的目的:服務(wù)端使用WebSocketController中@MessageMapping("/receive")注解的方法來處理發(fā)送過來的消息
stompClient.send("/sendServer", {}, JSON.stringify({ 'name': message }));
}
function sendAllUser() { //發(fā)公告===類直接發(fā)到群中,其實(shí)跟公告一樣
var message = $('#message').val();
// 客戶端消息發(fā)送的目的:服務(wù)端使用WebSocketController中@MessageMapping("/receive")注解的方法來處理發(fā)送過來的消息
stompClient.send("/sendAllUser", {}, JSON.stringify({ 'name': message }));
}
//發(fā)送點(diǎn)對(duì)點(diǎn)通信---后臺(tái)對(duì)應(yīng)的采用的是simpMessagingTemplate.convertAndSendToUser
function sendMyUser() {
var message = $('#message').val();
var mytoken = $('#mytoken').val();
// 客戶端消息發(fā)送的目的:服務(wù)端使用WebSocketController中@MessageMapping("/receive")注解的方法來處理發(fā)送過來的消息
//stompClient.send("/sendMyUser", {}, JSON.stringify({ 'name': message }));
stompClient.send("/sendMyUser", {}, JSON.stringify({name:mytoken,message:message}));
}
//顯示消息
function showResponse(message) {
var response = $("#response");
response.html("按ResponseMessage對(duì)象返回的responseMessage字段數(shù)據(jù):\""+message + "<br\>" + response.html());
}
function showResponseBody(response_body) {
var response = $("#response");
response.html("按websocket api 返回格式的response.body數(shù)據(jù):"+response_body + "<br\>" + response.html());
}
</script>
</body>
</html>
通過controller轉(zhuǎn)發(fā)到html訪問websocket
http://localhost:8080//wechatTask/websocket/index
添加Socket鏈接的管理器SocketManager
public class SocketManager {
private static final Logger log = LoggerFactory.getLogger(SocketManager.class);
private static ConcurrentHashMap<String, WebSocketSession> manager = new ConcurrentHashMap<String, WebSocketSession>();
public static void add(String key, WebSocketSession webSocketSession) {
log.info("新添加webSocket連接 {} ", key);
manager.put(key, webSocketSession);
}
public static void remove(String key) {
log.info("移除webSocket連接 {} ", key);
manager.remove(key);
}
public static WebSocketSession get(String key) {
log.info("獲取webSocket連接 {}", key);
return manager.get(key);
}
public static int connectedCount(){
return manager.size();
}
}
添加WebSocketDecoratorFactory(用于管理websocket的鏈接與斷開)
/**
* 服務(wù)端和客戶端在進(jìn)行握手時(shí)會(huì)被執(zhí)行
*/
@Component
public class WebSocketDecoratorFactory implements WebSocketHandlerDecoratorFactory {
private static final Logger log = LoggerFactory.getLogger(WebSocketDecoratorFactory.class);
@Override
public WebSocketHandler decorate(WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
log.info("有人連接啦 sessionId = {}", session.getId()+"鏈接數(shù)量"+SocketManager.connectedCount()+"****連接數(shù)一直為0則是校驗(yàn)了taken");
Principal principal = session.getPrincipal();
if (principal != null) {
log.info("key = {} 存入", principal.getName());
// 身份校驗(yàn)成功雄家,緩存socket連接
SocketManager.add(principal.getName(), session);
}
super.afterConnectionEstablished(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
log.info("有人退出連接啦 sessionId = {}", session.getId()+SocketManager.connectedCount());
Principal principal = session.getPrincipal();
if (principal != null) {
// 身份校驗(yàn)成功效诅,移除socket連接
SocketManager.remove(principal.getName());
}
super.afterConnectionClosed(session, closeStatus);
}
};
}
}
WebSocketConfig中注入WebSocketDecoratorFactory,并重寫configureWebSocketTransport方法
關(guān)于websocket的文章收錄
JMeter測試WebSocket的經(jīng)驗(yàn)總結(jié)
springboot集成websocket需要的都在這里
Spring Boot系列十六 WebSocket簡介和spring boot集成簡單消息代理
//socket = new WebSocket("ws://localhost:9094/starManager/websocket/張三");
var socket;
if(typeof(WebSocket) == "undefined") {
console.log("您的瀏覽器不支持WebSocket");
}else{
console.log("您的瀏覽器支持WebSocket");
//實(shí)現(xiàn)化WebSocket對(duì)象乱投,指定要連接的服務(wù)器地址與端口 建立連接
//socket = new WebSocket("ws://localhost:9094/starManager/websocket/張三")
socket = new WebSocket("ws://localhost:9094/starManager/websocket");
//打開事件
socket.onopen = function() {
console.log("Socket 已打開");
//socket.send("這是來自客戶端的消息" + location.href + new Date());
};
//獲得消息事件
socket.onmessage = function(msg) {
console.log(msg.data);
//發(fā)現(xiàn)消息進(jìn)入 調(diào)后臺(tái)獲取
getCallingList();
};
//關(guān)閉事件
socket.onclose = function() {
console.log("Socket已關(guān)閉");
};
//發(fā)生了錯(cuò)誤事件
socket.onerror = function() {
alert("Socket發(fā)生了錯(cuò)誤");
}
$(window).unload(function(){
socket.close();
});
// $("#btnSend").click(function() {
// socket.send("這是來自客戶端的消息" + location.href + new Date());
// });
//
// $("#btnClose").click(function() {
// socket.close();
// });
}
SpringBoot使用WebSocket--SimpMessagingTemplate
聲明SimpMessagingTemplate (或者使用@SendTo和@SendToUser注解)
在需要用到推送的地方如Controller,service顷编,Component等地方聲明SimpMessagingTemplate
當(dāng)需要向客戶端推送消息時(shí)戚炫,調(diào)用convertAndSend方法,即可推送消息媳纬,此處“/topic/send”可隨意設(shè)置双肤,所有前端訂閱該url的客戶端都可以收到推送的消息。
messagingTemplate.convertAndSend("/topic/send", result);
springboot+websocket层宫,一篇足夠了--管理Socket的類-SocketManager
springboot+websocket杨伙,一篇足夠了--管理Socket的類-SocketManager -簡書
Spring-boot2 WebFlux WebSockit實(shí)現(xiàn)-實(shí)現(xiàn)心跳
websocket消息推送實(shí)現(xiàn)
[java+websocket實(shí)現(xiàn)網(wǎng)頁聊天室-今日頭條](https://www.toutiao.com/a6700358112806699528)
spring websocket之sockjs超簡單現(xiàn)實(shí)
客戶端接收服務(wù)端消息推送sockjs-client的使用--new SockJS(url, _reserved, options)
利用Spring_Boot WebSocKet實(shí)現(xiàn)一個(gè)推送的小Demo--全局推送&點(diǎn)對(duì)點(diǎn)推動(dòng)-spring-boot-starter-security
Spring Boot通信之STOMP協(xié)議:后臺(tái)不發(fā)送心跳的問題
spring boot集成WebSocket實(shí)時(shí)輸出日志到web頁面--采用阻塞隊(duì)列
Spring消息之STOMP--留意參數(shù)Principal principal
什么是stomp其监?spring-boot websocket stomp服務(wù)構(gòu)建-@MessageMapping參數(shù)詳情