(一)概念
1.什么是websocket
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex),客户端连接服务端连起来以后建立一个channel,客户端可以发消息给服务器,服务器可以主动推送消息到服务端,不用一直建立连接,只要维护这个链接就可以了.
2.使用场景
如弹幕,网页聊天系统,实时监控(监控系统内存情况等等),股票行情推送等.
3.socketjs
一开始的时候我们在浏览器做WebSocket的类,一开始是用原生的
是什么:
1、是一个浏览器JavaScript库,提供了一个类似WebSocket的对象。
2、提供了一个连贯的跨浏览器的JavaScriptAPI,在浏览器和Web服务器之间创建了一个低延迟,全双工,跨域的通信通道
3、在底层SockJS首先尝试使用本地WebSocket。如果失败了,它可以使用各种浏览器特定的传输协议,并通过类似WebSocket的抽象方式呈现它们
可能老的浏览器是不支持WebSocket的,如果我们用原生的WebSocket的话,可能会出现无法使用的情况,如果我们使用SockJS包装WebSocket的话,就能很好的展现出来.
4、SockJS旨在适用于所有现代浏览器和不支持WebSocket协议的环境。
4.stompjs
是什么:
1、STOMP Simple (or Streaming) Text Orientated Messaging Protocol
它定义了可互操作的连线格式,以便任何可用的STOMP客户端都可以与任何STOMP消息代理进行通信,以在语言和平台之间提供简单而广泛的消息互操作性(归纳一句话:是一个简单的面向文本的消息传递协议。)
5.广播、单播、组播介绍和使用场景说明
单播(Unicast):
点对点,私信私聊
广播(Broadcast)(所有人):
游戏公告,发布订阅
多播,也叫组播(Multicast)(特定人群):
多人聊天,发布订阅
6.StompCommand
STOMP(SimpMessageType.CONNECT),
CONNECT(SimpMessageType.CONNECT), 连接DISCONNECT(SimpMessageType.DISCONNECT), 断开连接SUBSCRIBE(SimpMessageType.SUBSCRIBE, true, true, false), 订阅UNSUBSCRIBE(SimpMessageType.UNSUBSCRIBE, false, true, false), 取消订阅SEND(SimpMessageType.MESSAGE, true, false, true), 发送ACK(SimpMessageType.OTHER), 三次握手NACK(SimpMessageType.OTHER),
BEGIN(SimpMessageType.OTHER),
COMMIT(SimpMessageType.OTHER),
ABORT(SimpMessageType.OTHER),
// server
CONNECTED(SimpMessageType.OTHER),
RECEIPT(SimpMessageType.OTHER),
MESSAGE(SimpMessageType.MESSAGE, true, true, true),
ERROR(SimpMessageType.OTHER, false, false, true);
(二)拦截器的使用
1.HandshakeInterceptor
在里面可以获取request和response对象,也可以在里面写一些业务逻辑,比如查数据库等等.
通过拦截器可以拿到sessionId
需要实现 HandshakeInterceptor接口,然后重写两个方法:
beforeHandshake()和afterHandshake()
public class HttpHandShakeIntecepter implements HandshakeInterceptor {
然后需要在WebSocket的配置类里面里面给端点配置一下才行
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
public void registerStompEndpoints(StompEndpointRegistry registry) {
/*.addInterceptors(new HttpHandShakeIntecepter() 添加拦截器<br /> HttpHandShakeIntecepter()是自己实现的拦截器<br /> */
registry.addEndpoint(**"/endpoint-websocket"**).addInterceptors(new HttpHandShakeIntecepter())
.setAllowedOrigins(**"*"**).withSockJS();
}
演示在WebSocket的Listener里面如何获取attributes里面put的信息
@Component
public class SubscribeEventListener implements ApplicationListener
/**
* 在事件触发的时候调用这个方法
*
* StompHeaderAccessor 简单消息传递协议中处理消息头的基类,
* 通过这个类,可以获取消息类型(例如:发布订阅,建立连接断开连接),会话id等
*
*/<br /> **public void **onApplicationEvent(SessionSubscribeEvent event) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor._wrap_(event.getMessage());
System.**_out_**.println(**"【SubscribeEventListener监听器事件 sessionId"**+headerAccessor.getSessionAttributes().get(**"sessionId"**));<br /> //获取的sessionId是在拦截器里面attributes的Map集合那里put进去的值<br /> <br /> }<br />}<br /> <br />
beforeHandshake
在处理握手之前调用
参数里面:
Map
返回值
返回true就是继续握手(就是接下来的逻辑),返回false就是终止握手,
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,<br /> Map<String, Object> attributes) **throws **Exception {<br />
System.out.println(“【握手拦截器】beforeHandshake”);
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession();
String sessionId = session.getId();//sessionId是会话的唯一标识<br />
System.**_out_**.println(**"【握手拦截器】beforeHandshake sessionId=" **+ sessionId);<br />
attributes.put(**"sessionId"**, sessionId);
}
return true;
afterHandshake
握手完成后调用。响应状态和头指示握手的结果,即握手是否成功。
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,<br /> Exception exception) {<br /> System.**_out_**.println(**"【握手拦截器】afterHandshake"**);<br />
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;<br /> HttpSession session = servletRequest.getServletRequest().getSession();<br /> String sessionId = session.getId();<br /> System.**_out_**.println(**"【握手拦截器】afterHandshake sessionId=" **+ sessionId);
}
执行顺序
HttpHandShakeIntecepter.beforeHandshake
HttpHandShakeIntecepter.afterHandshake
ConnectEventListener.onApplicationEvent —WebSocket的Listener
SubscribeEventListener.onApplicationEvent —WebSocket的Listener
2.ChannelInterceptorAdapter
频道拦截器 ,类似管道,可以获取消息的一些meta数据
使用方法,继承ChannelInterceptorAdapter然后根据业务逻辑重写里面的方法
然后在WebSocket配置类里面配置拦截器,
配置拦截器
//用于为来自WebSocket客户机的入站消息定制消息通道
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors( new SocketChannelIntecepter()); //SocketChannelIntecepter 是用户自己实现的拦截器
}
//用于为从应用程序或message broker到WebSocket客户机的消息定制消息通道。
@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.interceptors( new SocketChannelIntecepter()); //SocketChannelIntecepter 是用户自己实现的拦截器
}
可以根据业务需求重写下面几个方法
afterSendCompletion 在完成发送之后进行调用,不管是否有异常发生,一般用于资源清理 preSend 在消息被实际发送到频道之前调用,可以在这个方法里面修改消息头等等信息 postSend 发送消息调用后立即调用 preReceive 在调用receive和实际检索消息之前立即调用。如果返回值为“false”,则不会检索任何消息。这只适用于PollableChannels。 postReceive 在检索到消息后立即调用,但在消息返回给调用者之前调用。必要时,可以修改电文;null中止进一步的拦截器调用。这只适用于PollableChannels。 afterReceiveCompletion 在接收完成后调用,而不考虑已引发的任何异常,从而允许进行适当的资源清理。 请注意,只有在preReceive(org.springframework. message . messagechannel)成功完成并返回true时才会调用该函数。 |
---|
触发顺序:
1.preSend
2.postSend
3.afterSendCompletion
afterSendCompletion
在完成发送之后进行调用,不管是否有异常发生,一般用于资源清理
preSend
在消息被实际发送到频道之前调用,可以在这个方法里面修改消息头等等信息
postSend
发送消息调用后立即调用,可以从这里拿到sessionId等等信息进行业务逻辑, 用户上线下线的时候也会经过这里.<br />
| /**
发送消息调用后立即调用
/
@Override
*public void postSend(Message<?> message, MessageChannel channel,**boolean **sent) {<br />
System.out.println(“SocketChannelIntecepter->postSend”);
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);//消息头访问器
if (headerAccessor.getCommand() == null) return;// 避免非stomp消息类型,例如心跳检测
String sessionId = headerAccessor.getSessionAttributes().get(“sessionId”).toString();
System.out.println(“SocketChannelIntecepter -> sessionId = “ + sessionId);
switch (headerAccessor.getCommand()) {
case CONNECT:connect(sessionId);<br />
**break**;<br />
case DISCONNECT:
disconnect(sessionId);<br />
**break**;<br />
case SUBSCRIBE:
**break**;<br />
case UNSUBSCRIBE:
**break**;<br />
default:
**break**;<br />
}
}
//连接成功
private void connect(String sessionId) {
System.out.println(“connect sessionId=” + sessionId);
}
//断开连接
private void disconnect(String sessionId) {
System.out.println(“disconnect sessionId=” + sessionId);
//用户下线操作
UserChatController.onlineUser.remove(sessionId);
} | | —- |preReceive
在调用receive和实际检索消息之前立即调用。如果返回值为“false”,则不会检索任何消息。这只适用于PollableChannels。
postReceive
在检索到消息后立即调用,但在消息返回给调用者之前调用。必要时,可以修改电文;null中止进一步的拦截器调用。这只适用于PollableChannels。
afterReceiveCompletion
在接收完成后调用,而不考虑已引发的任何异常,从而允许进行适当的资源清理。
请注意,只有在preReceive(org.springframework. message . messagechannel)成功完成并返回true时才会调用该函数。
(三)api说明
1.AbstractWebSocketMessageBrokerConfigurer
@EnableWebSocketMessageBroker注解用于开启使用STOMP协议来传输基于代理(MessageBroker)的消息,这时候控制器(controller)开始支持@MessageMapping,就像是使用@requestMapping一样。
还需要extends AbstractWebSocketMessageBrokerConfigurer重写两个方法
|
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableWebSocketMessageBroker//表示这个类是WebSocket的经纪人类
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
/**
* 注册端点,来接收客户端的连接* addEndpoint: 表示添加了一个端点,客户端就可以通过这个端点来进行连接<br />
* setAllowedOrigins 非必须,*表示允许其他域进行连接(允许任何人访问,也可以写域名.)<br />
* withSockJS 表示开始sockejs支持<br />
*/<br />
public void registerStompEndpoints(StompEndpointRegistry registry) {
/*前端代码:
* var socket = new SockJS('/endpoint-websocket');<br />
* 通过这段JS然后浏览器连接我们的后台应用程序
* */<br />
registry.addEndpoint(**"/endpoint-websocket"**).setAllowedOrigins(**"*"**).withSockJS();<br />
}
/**
* 配置消息代理(通俗讲就是设置消息连接请求的各种规范)<br />
* enableSimpleBroker 客户端接收服务端消息的地址的前缀信息<br />
* setApplicationDestinationPrefixes 客户端给服务端发消息的地址的前缀这两个方法定义的信息其实是相反的,一个定义了客户端接收的地址前缀,一个定义类客户端发送地址的前缀
*/<br />
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker(“/topic”, “/chat”);
/
浏览器js代码:
stompClient.send(“/app/v1/chat”, {}, JSON.stringify({‘content’: $(“#content”).val()}));/
registry.setApplicationDestinationPrefixes(“/app”);
}
}
|
| —- |
2.@MessageMapping
@MessageMapping(“/welcome”)
当浏览器向服务端发送请求时,通过@MessageMapping映射/welcome这个地址,类似于@RequestMapping
说白了就是前端通过这个路径发送消息到后台
3.STOMP
基于STOMP协议的WebSocket
使用STOMP的好处在于,它完全就是一种消息队列模式,你可以使用生产者与消费者的思想来认识它,发送消息的是生产者,接收消息的是消费者。而消费者可以通过订阅不同的destination,来获得不同的推送消息,不需要开发人员去管理这些订阅与推送目的地之前的关系,
我的理解就是:stomp定义了自己的消息传输体制。首先是通过一个后台绑定的连接点endpoint来建立socket连接,然后生产者通过send方法,绑定好发送的目的地也就是destination,而topic和app(后面还会说到)则是一种消息处理手段的分支,走app/url的消息会被你设置到的MassageMapping拦截到,进行你自己定义的具体逻辑处理,而走topic/url的消息就不会被拦截,直接到Simplebroker节点中将消息推送出去。其中simplebroker是spring的一种基于内存的消息队列,你也可以使用activeMQ,rabbitMQ代替。
4.STOMP客户端JS代码
介绍
STOMP(Simple Text-Orientated Messaging Protocol) 面向消息的简单文本协议
WebSocket是一个消息架构,不强制使用任何特定的消息协议,它依赖于应用层解释消息的含义;
与处在应用层的HTTP不同,WebSocket处在TCP上非常薄的一层,会将字节流转换为文本/二进制消息,因此,对于实际应用来说,WebSocket的通信形式层级过低,因此,可以在 WebSocket 之上使用 STOMP协议,来为浏览器 和 server间的 通信增加适当的消息语义。
如何理解 STOMP 与 WebSocket 的关系:
1) HTTP协议解决了 web 浏览器发起请求以及 web 服务器响应请求的细节,假设 HTTP 协议 并不存在,只能使用 TCP 套接字来 编写 web 应用,你可能认为这是一件疯狂的事情;
2) 直接使用 WebSocket(SockJS) 就很类似于 使用 TCP 套接字来编写 web 应用,因为没有高层协议,就需要我们定义应用间所发送消息的语义,还需要确保连接的两端都能遵循这些语义;
3) 同 HTTP 在 TCP 套接字上添加请求-响应模型层一样,STOMP 在 WebSocket 之上提供了一个基于帧的线路格式层,用来定义消息语义;
STOMP帧
STOMP帧由命令,一个或多个头信息、一个空行及负载(文本或字节)所组成;
其中可用的COMMAND 包括:
CONNECT、SEND、SUBSCRIBE、UNSUBSCRIBE、BEGIN、COMMIT、ABORT、ACK、NACK、DISCONNECT;
例:
发送消息
SEND
destination:/queue/trade
content-type:application/json
content-length:44
{“action”:”BUY”,”ticker”:”MMM”,”shares”,44}^@
订阅消息
SUBSCRIBE
id:sub-1
destination:/topic/price.stock.*
^@
服务器进行广播消息
MESSAGE
message-id:nxahklf6-1
subscription:sub-1
destination:/topic/price.stock.MMM
{“ticker”:”MMM”,”price”:129.45}^@
客户端 API
引入stomp.js
发起连接
stompClient.Connect 连接后台订阅消息的
用来接收后台发过来的消息
如果是前后端分离的话
| function connect() {
var socket = new SockJS(‘http://localhost:8888/endpoint-websocket‘); //连接上端点(基站)
stompClient = Stomp.over(socket); //用stom进行包装,规范协议
stompClient.connect({}, function (frame) {
setConnected(true);
console.log(‘Connected: ‘ + frame);
stompClient.subscribe(‘/topic/game_chat’, function (result) {
console.info(result)
showContent(JSON.parse(result.body));
});
});
} |
| —- |
如果是前后端不分离
| function connect() {
var socket = new SockJS(‘/endpoint-websocket’);
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log(‘Connected: ‘ + frame);
stompClient.subscribe(‘/topic/game_rank’, function (result) {
showContent(JSON.parse(result.body));
});
});
}function showContent(body) {
$(“#notice”).append(““ + body.content + “ “+new Date(body.time).toLocaleString()+““);
} |
| —- |
还能发送一些头信息,
发送过去之后服务器可以接收到的.
客户端可以通过使用Stomp.js和sockjs-client连接
// 建立连接对象(还未发起连接)
var socket=new SockJS(“/spring-websocket-portfolio/portfolio”);
// 获取 STOMP 子协议的客户端对象
var stompClient = Stomp.over(socket);
// 向服务器发起websocket连接并发送CONNECT帧
stompClient.connect(
{},
function connectCallback (frame) {
// 连接成功时(服务器响应 CONNECTED 帧)的回调方法
document.getElementById(“state-info”).innerHTML = “连接成功”;
console.log(‘已连接【’ + frame + ‘】’);
stompClient.subscribe(‘/topic/getResponse’, function (response) {
showResponse(response.body);
});
},
function errorCallBack (error) {
// 连接失败时(服务器响应 ERROR 帧)的回调方法
document.getElementById(“state-info”).innerHTML = “连接失败”;
console.log(‘连接失败【’ + error + ‘】’);
}
);
说明:
1) socket连接对象也可通过WebSocket(不通过SockJS)连接
var socket=new WebSocket(“/spring-websocket-portfolio/portfolio”);
2) stompClient.connect()方法签名:
client.connect(headers, connectCallback, errorCallback);
其中
headers表示客户端的认证信息,如:
var headers = {
login: ‘mylogin’,
passcode: ‘mypasscode’,
// additional header
‘client-id’: ‘my-client-id’
};
若无需认证,直接使用空对象 “{}” 即可;
connectCallback 表示连接成功时(服务器响应 CONNECTED 帧)的回调方法;
errorCallback 表示连接失败时(服务器响应 ERROR 帧)的回调方法,非必须;
断开连接
stompClient.disconnect() 关闭连接的信息
function disconnect() {
**if **(**_stompClient _**!== **null**) {
**_stompClient_**.disconnect();
}<br /> **_console_**.log(**"Disconnected"**);
}
若要从客户端主动断开连接,可调用 disconnect() 方法
client.disconnect(function () {
alert(“See you next time!”);
};
该方法为异步进行,因此包含了回调参数,操作完成时自动回调;
心跳机制
若使用STOMP 1.1 版本,默认开启了心跳检测机制,可通过client对象的heartbeat field进行配置(默认值都是10000 ms):
client.heartbeat.outgoing = 20000; // client will send heartbeats every 20000ms
client.heartbeat.incoming = 0; // client does not want to receive heartbeats from the server
// The heart-beating is using window.setInterval() to regularly send heart-beats and/or check server heart-beats
发送信息
stompClient.send发送
参数1: 路径 是服务器端的@MessageMapping 的路径
参数2: 不知道,视频教程就直接输入 {} 的
参数3: 要发送的消息
前后端分离不分离都不要写url路径,不然连不上后台,可能是因为连接的时候已经指定好了URL信息
| function sendName() {
stompClient.send(“/app/v1/chat”, {}, JSON.stringify({‘content’: $(“#content”).val()}));
} |
| —- |
连接成功后,客户端可使用 send() 方法向服务器发送信息:
client.send(destination url[, headers[, body]]);
其中
destination url 为服务器 controller中 @MessageMapping 中匹配的URL,字符串,必须参数;
headers 为发送信息的header,JavaScript 对象,可选参数;
body 为发送信息的 body,字符串,可选参数;
例:
client.send(“/queue/test”, {priority: 9}, “Hello, STOMP”);
client.send(“/queue/test”, {}, “Hello, STOMP”);
订阅、接收信息
stompClient.subscribe订阅
参数一 是订阅的url
参数二 是回调,服务器发过来的信息会在这里接收.
前后端分离不分离都不要写url路径,不然连不上后台,可能是因为连接的时候已经指定好了URL信息
| stompClient.subscribe(‘/topic/game_chat’, function (result) {
console.info(result)
showContent(JSON.parse(result.body));
}); |
| —- |
STOMP 客户端要想接收来自服务器推送的消息,必须先订阅相应的URL,即发送一个 SUBSCRIBE 帧,然后才能不断接收来自服务器的推送消息;
订阅和接收消息通过 subscribe() 方法实现:
subscribe(destination url, callback[, headers])
其中
destination url 为服务器 @SendTo 匹配的 URL,字符串;
callback 为每次收到服务器推送的消息时的回调方法,该方法包含参数 message;
headers 为附加的headers,JavaScript 对象;什么作用?
该方法返回一个包含了id属性的 JavaScript 对象,可作为 unsubscribe() 方法的参数;
例:
var headers = {ack: ‘client’, ‘selector’: “location = ‘Europe’”};
var callback = function(message) {
if (message.body) {
alert(“got message with body “ + message.body)
} else {
alert(“got empty message”);
}
});
var subscription = client.subscribe(“/queue/test”, callback, headers);
取消订阅
var subscription = client.subscribe(…);
subscription.unsubscribe();
JSON 支持
STOMP 帧的 body 必须是 string 类型,若希望接收/发送 json 对象,可通过 JSON.stringify() and JSON.parse() 实现;
例:
var quote = {symbol: ‘APPL’, value: 195.46};
client.send(“/topic/stocks”, {}, JSON.stringify(quote));
client.subcribe(“/topic/stocks”, function(message) {
var quote = JSON.parse(message.body);
alert(quote.symbol + “ is at “ + quote.value);
});
事务支持
STOMP 客户端支持在发送消息时用事务进行处理:
举例说明:
// start the transaction
// 该方法返回一个包含了事务 id、commit()、abort() 的JavaScript 对象
var tx = client.begin();
// send the message in a transaction
// 最关键的在于要在 headers 对象中加入事务 id,若没有添加,则会直接发送消息,不会以事务进行处理
client.send(“/queue/test”, {transaction: tx.id}, “message in a transaction”);
// commit the transaction to effectively send the message
tx.commit();
// tx.abort();
Debug 信息
STOMP 客户端默认将传输过程中的所有 debug 信息以 console.log() 形式输出到客户端浏览器中,也可通过以下方式输出到 DOM 中:
client.debug = function(str) {
// str 参数即为 debug 信息
// append the debug log to a #debug div somewhere in the page using JQuery:
$(“#debug”).append(str + “\n”);
};
认证
这一部分内容看的不是很理解,因此直接将原文放在这里了,待补充。
By default, STOMP messages will be automatically acknowledged by the server before the message is delivered to the client.
The client can chose instead to handle message acknowledgement by subscribing to a destination and specify a ack header set to client or client-individual.
In that case, the client must use the message.ack() method to inform the server that it has acknowledge the message.
var subscription = client.subscribe(“/queue/test”,
function(message) {
// do something with the message
…
// and acknowledge it
message.ack();
},
{ack: ‘client’}
);
The ack() method accepts a headers argument for additional headers to acknowledge the message. For example, it is possible to acknowledge a message as part of a transaction and ask for a receipt when the ACK STOMP frame has effectively be processed by the broker:
var tx = client.begin();
message.ack({ transaction: tx.id, receipt: ‘my-receipt’ });
tx.commit();
The nack() method can also be used to inform STOMP 1.1 brokers that the client did not consume the message. It takes the same arguments than the ack() method.
5.WebSocket推送方法讲解
@SendTo
定义了消息的目的地,将方法的返回值发送给指定的url
@SendTo(“/topic/game_chat”)//发送从哪里去(发布订阅模式),前端通过这个路径接收后台发过来的信息
@SendTo注解和SimpMessagingTemplate的区别
1、SendTo 不通用,固定发送给指定的订阅者
2、SimpMessagingTemplate 灵活,支持多种发送方式
SimpMessagingTemplate
SimpMessagingTemplate是 Spring-WebSocket 内置的一个消息发送工具,可以将消息发送到指定的客户端。
convertAndSend()
“将给定的对象进行序列化,使用‘MessageConverter’进行包装转化成一条消息,发送到指定的目标”,通俗点讲就是我们使用这个方法进行消息的转发发送!可以发送很多人.
参数1: 发送给客户端的url
参数2: 发送的内容
convertAndSendToUser()
指定用户发送
6.SpringBoot针对WebSocket四类监听器
监听器是监控某一个事件,当这个事件触发的时候会可以在里面做一些事情,
SpringBoot里面websocekt监听器的使用,包含订阅、取消订阅,socekt连接和断开连接4类监听器的编写和使用
注意点:
1、需要监听器类需要实现接口ApplicationListener
2、在监听器类上注解 @Component,spring会把改类纳入管理
websocket模块监听器有四种(可能还有更多)
SessionSubscribeEvent 订阅事件
SessionUnsubscribeEvent 取消订阅事件
SessionDisconnectEvent 断开连接事件
SessionDisconnectEvent 建立连接事件
StompHeaderAccessor(StompHeader访问器)
headers 是header信息
simpMessageType 消息类型
stompCommand 消息指令
nativeHeaders
destination 是谁订阅的 订阅的url
simSessionAttributes session会话
|
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionConnectEvent;
/**
建立连接的时候触发事件
/
@Component
public class ConnectEventListener implements ApplicationListener{
/*- 建立连接的时候触发事件
* - @param **event
*/
public void onApplicationEvent(SessionConnectEvent event) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
System.out.println(“【ConnectEventListener监听器事件 类型】” **+ headerAccessor.getCommand().getMessageType());
}
} | | —- |
如果StompCommand为null就检查一下类名上的泛型是不是SessionConnectEvent ,
- 建立连接的时候触发事件
|
@Component
public class SubscribeEventListener implements ApplicationListener
/**
* 在事件触发的时候调用这个方法<br />
* <br />
* StompHeaderAccessor 简单消息传递协议中处理消息头的基类,<br />
* 通过这个类,可以获取消息类型(例如:发布订阅,建立连接断开连接),会话id等<br />
* <br />
*/<br />
public void onApplicationEvent(SessionSubscribeEvent event) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
System.out.println(“【SubscribeEventListener监听器事件 类型】”+headerAccessor.getCommand().getMessageType());
}
} |
| —- |