1.浅谈WebSocket
WebSocket是在HTML5基础上单个TCP连接上进行全双工通讯的协议,只要浏览器和服务器进行一次握手,就可以建立一条快速通道,两者就可以实现数据互传了。说白了,就是打破了传统的http协议的无状态传输(只能浏览器请求,服务端响应),websocket全双工通讯,就是浏览器和服务器进行一次握手,浏览器可以随时给服务器发送信息,服务器也可以随时主动发送信息给浏览器了。对webSocket原理有兴趣的客官,可以自行百度。
2.环境搭建
因为是根据项目的需求来的,所以这里我只介绍在SpringBoot下使用WebSocket的其中一种实现【STOMP协议】。因此整个工程涉及websocket使用的大致框架为SpringBoot+Maven+websocket,其他框架的基础搭建,我这里就不说了,相信各位也都很熟悉,我就直接集成websocket了。
在pox.xml加上对springBoot对WebSocket的支持:
-
<!-- webSocket -->
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-websocket</artifactId>
-
</dependency>
这样SpringBoot就和WebSocket集成好了,我们就可以直接使用SpringBoot提供对WebSocket操作的API了
3.编码实现
①在Spring上下文中添加对WebSocket的配置
-
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;
-
-
/**
-
* 配置WebSocket
-
*/
-
@Configuration
-
//注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
-
@EnableWebSocketMessageBroker
-
public
class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
-
@Override
-
//注册STOMP协议的节点(endpoint),并映射指定的url
-
public void registerStompEndpoints(StompEndpointRegistry registry) {
-
//注册一个STOMP的endpoint,并指定使用SockJS协议
-
registry.addEndpoint(
"/endpointOyzc").setAllowedOrigins(
"*").withSockJS();
-
}
-
@Override
-
//配置消息代理(Message Broker)
-
public void configureMessageBroker(MessageBrokerRegistry registry) {
-
//点对点应配置一个/user消息代理,广播式应配置一个/topic消息代理
-
registry.enableSimpleBroker(
"/topic",
"/user");
-
//点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/
-
registry.setUserDestinationPrefix(
"/user");
-
}
-
}
介绍以上几个相关的注解和方法:
1.@EnableWebSocketMessageBroker:开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样。
2.AbstractWebSocketMessageBrokerConfigurer:继承WebSocket消息代理的类,配置相关信息。
3.registry.addEndpoint("/endpointOyzc").setAllowedOrigins("*").withSockJS(); 添加一个访问端点“/endpointGym”,客户端打开双通道时需要的url,允许所有的域名跨域访问,指定使用SockJS协议。
4. registry.enableSimpleBroker("/topic","/user"); 配置一个/topic广播消息代理和“/user”一对一消息代理
5. registry.setUserDestinationPrefix("/user");点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/
②实现服务器主动向客户端推送消息
SpringBoot封装得太好,webSocket用起来太简单(好处:用起来方便,坏处:你不知道底层实现)
由于代码中涉及到定时任务,这里我们使用spring自带的定时任务功能@EnableScheduling,定时任务在配置类上添加@EnableScheduling开启对定时任务的支持(亦可以添加在主启动类上,作用是一样的),在相应的方法上添加@Scheduled声明需要执行的定时任务。 不添加@EnableScheduling注解定时任务是无法生效的。感谢_Devil_K同学的指正。
1.一对多的实现:
先上后台java的代码
-
package com.cheng.sbjm.boot;
-
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.messaging.simp.SimpMessagingTemplate;
-
import org.springframework.scheduling.annotation.Scheduled;
-
import org.springframework.stereotype.Controller;
-
import com.cheng.sbjm.domain.User;
-
-
@Controller
-
public
class WebSocketController {
-
-
@Autowired
-
private SimpMessagingTemplate template;
-
-
//广播推送消息
-
@Scheduled(fixedRate = 10000)
-
public void sendTopicMessage() {
-
System.out.println(
"后台广播推送!");
-
User user=
new User();
-
user.setUserName(
"oyzc");
-
user.setAge(
10);
-
this.template.convertAndSend(
"/topic/getResponse",user);
-
}
-
}
简单介绍一下
1.SimpMessagingTemplate:SpringBoot提供操作WebSocket的对象
2.@Scheduled(fixedRate = 10000):为了测试,定时10S执行这个方法,向客户端推送
3.template.convertAndSend("/topic/getResponse",new AricResponse("后台实时推送:,Oyzc!")); :直接向前端推送消息。
3.1参数一:客户端监听指定通道时,设定的访问服务器的URL
3.2参数二:发送的消息(可以是对象、字符串等等)
在上客户端的代码(PC现代浏览器)
html页面:
-
<!DOCTYPE html>
-
<html>
-
<head>
-
<title>websocket.html
</title>
-
<meta name="keywords" content="keyword1,keyword2,keyword3">
-
<meta name="description" content="this is my page">
-
<meta name="content-type" content="text/html" charset="UTF-8">
-
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
-
</head>
-
<body>
-
<div>
-
<p id="response">
</p>
-
</div>
-
-
<!-- 独立JS -->
-
<script type="text/javascript" src="jquery.min.js" charset="utf-8">
</script>
-
<script type="text/javascript" src="webSocket.js" charset="utf-8">
</script>
-
<script type="text/javascript" src="sockjs.min.js" charset="utf-8">
</script>
-
<script type="text/javascript" src="stomp.js" charset="utf-8">
</script>
-
</body>
-
</html>
JS代码[webSocket.js]
-
var stompClient =
null;
-
//加载完浏览器后 调用connect(),打开双通道
-
$(
function(){
-
//打开双通道
-
connect()
-
})
-
//强制关闭浏览器 调用websocket.close(),进行正常关闭
-
window.onunload =
function() {
-
disconnect()
-
}
-
function connect(){
-
var socket =
new SockJS(
'http://127.0.0.1:9091/sbjm-cheng/endpointOyzc');
//连接SockJS的endpoint名称为"endpointOyzc"
-
stompClient = Stomp.over(socket);
//使用STMOP子协议的WebSocket客户端
-
stompClient.connect({},
function(frame){
//连接WebSocket服务端
-
console.log(
'Connected:' + frame);
-
//通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息
-
stompClient.subscribe(
'/topic/getResponse',
function(response){
-
showResponse(
JSON.parse(response.body));
-
});
-
});
-
}
-
-
//关闭双通道
-
function disconnect(){
-
if(stompClient !=
null) {
-
stompClient.disconnect();
-
}
-
console.log(
"Disconnected");
-
}
-
function showResponse(message){
-
var response = $(
"#response");
-
response.append(
"<p>"+message.userName+
"</p>");
-
}
值得注意的是,只需要在连接服务器注册端点endPoint时,写访问服务器的全路径URL:
new SockJS('http://127.0.0.1:9091/sbjm-cheng/endpointOyzc');
其他监听指定服务器广播的URL不需要写全路径
stompClient.subscribe('/topic/getResponse',function(response){
showResponse(JSON.parse(response.body));
});
2.一对一的实现
先上后台java的代码
-
package com.cheng.sbjm.boot;
-
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.messaging.simp.SimpMessagingTemplate;
-
import org.springframework.scheduling.annotation.Scheduled;
-
import org.springframework.stereotype.Controller;
-
import com.cheng.sbjm.domain.User;
-
-
-
@Controller
-
public
class WebSocketController {
-
-
@Autowired
-
private SimpMessagingTemplate template;
-
-
//一对一推送消息
-
@Scheduled(fixedRate = 10000)
-
public void sendQueueMessage() {
-
System.out.println(
"后台一对一推送!");
-
User user=
new User();
-
user.setUserId(
1);
-
user.setUserName(
"oyzc");
-
user.setAge(
10);
-
this.template.convertAndSendToUser(user.getUserId()+
"",
"/queue/getResponse",user);
-
}
-
}
简单介绍一下:
1.SimpMessagingTemplate:SpringBoot提供操作WebSocket的对象
2.@Scheduled(fixedRate = 10000):为了测试,定时10S执行这个方法,向客户端推送
3.template.convertAndSendToUser(user.getUserId()+"","/queue/getResponse",user); :直接向前端推送消息。
3.1参数一:指定客户端接收的用户标识(一般用用户ID)
3.2参数二:客户端监听指定通道时,设定的访问服务器的URL(客户端访问URL跟广播有些许不同)
3.3参数三:向目标发送消息体(实体、字符串等等)
在上客户端的代码(PC现代浏览器)
html页面:
-
<!DOCTYPE html>
-
<html>
-
<head>
-
<title>websocket.html
</title>
-
-
<meta name="keywords" content="keyword1,keyword2,keyword3">
-
<meta name="description" content="this is my page">
-
<meta name="content-type" content="text/html" charset="UTF-8">
-
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
-
<!-- 独立css -->
-
</head>
-
<body>
-
<div>
-
<p id="response">
</p>
-
</div>
-
<!-- 独立JS -->
-
<script type="text/javascript" src="jquery.min.js" charset="utf-8">
</script>
-
<script type="text/javascript" src="webSocket.js" charset="utf-8">
</script>
-
<script type="text/javascript" src="sockjs.min.js" charset="utf-8">
</script>
-
<script type="text/javascript" src="stomp.js" charset="utf-8">
</script>
-
</body>
-
</html>
JS代码[webSocket.js]
-
var stompClient =
null;
-
//加载完浏览器后 调用connect(),打开双通道
-
$(
function(){
-
//打开双通道
-
connect()
-
})
-
//强制关闭浏览器 调用websocket.close(),进行正常关闭
-
window.onunload =
function() {
-
disconnect()
-
}
-
function connect(){
-
var userId=
1;
-
var socket =
new SockJS(
'http://127.0.0.1:9091/sbjm-cheng/endpointOyzc');
//连接SockJS的endpoint名称为"endpointOyzc"
-
stompClient = Stomp.over(socket);
//使用STMOP子协议的WebSocket客户端
-
stompClient.connect({},
function(frame){
//连接WebSocket服务端
-
console.log(
'Connected:' + frame);
-
//通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息
-
stompClient.subscribe(
'/user/' + userId +
'/queue/getResponse',
function(response){
-
var code=
JSON.parse(response.body);
-
showResponse(code)
-
});
-
});
-
}
-
//关闭双通道
-
function disconnect(){
-
if(stompClient !=
null) {
-
stompClient.disconnect();
-
}
-
console.log(
"Disconnected");
-
}
-
function showResponse(message){
-
var response = $(
"#response");
-
response.append(
"<p>只有userID为"+message.userId+
"的人才能收到</p>");
-
}
与广播不同的是,在指定通道的URL加个用户标识:
stompClient.subscribe('/user/' + userId + '/queue/getResponse',function(response){
var code=JSON.parse(response.body);
showResponse(code)
});
该标识userId必须与服务器推送消息时设置的用户标识一致
以上就是实现服务器实时向客户端推送消息,各位可以按照各自的需求进行配合使用。
③实现客户端与服务器之间的直接交互,聊天室demo[在②的基础上添加了一些代码]
1.在webSocket配置中,增加2个WebSocket的代理
-
-
package com.cheng.sbjm.configure;
-
-
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;
-
-
/**
-
* 配置WebSocket
-
*/
-
@Configuration
-
//注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
-
@EnableWebSocketMessageBroker
-
public
class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
-
-
@Override
-
//注册STOMP协议的节点(endpoint),并映射指定的url
-
public void registerStompEndpoints(StompEndpointRegistry registry) {
-
//注册一个STOMP的endpoint,并指定使用SockJS协议
-
registry.addEndpoint(
"/endpointOyzc").setAllowedOrigins(
"*").withSockJS();
-
}
-
-
@Override
-
//配置消息代理(Message Broker)
-
public void configureMessageBroker(MessageBrokerRegistry registry) {
-
//点对点应配置一个/user消息代理,广播式应配置一个/topic消息代理,群发(mass),单独聊天(alone)
-
registry.enableSimpleBroker(
"/topic",
"/user",
"/mass",
"/alone");
-
//点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/
-
registry.setUserDestinationPrefix(
"/user");
-
-
}
-
-
}
"/mass"用以代理群发消息
"/alone"用以代码一对一聊天
2.java后台实现
-
package com.cheng.sbjm.boot;
-
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.messaging.handler.annotation.MessageMapping;
-
import org.springframework.messaging.handler.annotation.SendTo;
-
import org.springframework.messaging.simp.SimpMessagingTemplate;
-
import org.springframework.stereotype.Controller;
-
import com.cheng.sbjm.onput.ChatRoomRequest;
-
import com.cheng.sbjm.onput.ChatRoomResponse;
-
-
-
@Controller
-
public
class WebSocketController {
-
-
@Autowired
-
private SimpMessagingTemplate template;
-
//客户端主动发送消息到服务端,服务端马上回应指定的客户端消息
-
//类似http无状态请求,但是有质的区别
-
//websocket可以从服务器指定发送哪个客户端,而不像http只能响应请求端
-
-
//群发
-
@MessageMapping("/massRequest")
-
//SendTo 发送至 Broker 下的指定订阅路径
-
@SendTo("/mass/getResponse")
-
public ChatRoomResponse mass(ChatRoomRequest chatRoomRequest){
-
//方法用于群发测试
-
System.out.println(
"name = " + chatRoomRequest.getName());
-
System.out.println(
"chatValue = " + chatRoomRequest.getChatValue());
-
ChatRoomResponse response=
new ChatRoomResponse();
-
response.setName(chatRoomRequest.getName());
-
response.setChatValue(chatRoomRequest.getChatValue());
-
return response;
-
}
-
-
//单独聊天
-
@MessageMapping("/aloneRequest")
-
public ChatRoomResponse alone(ChatRoomRequest chatRoomRequest){
-
//方法用于一对一测试
-
System.out.println(
"userId = " + chatRoomRequest.getUserId());
-
System.out.println(
"name = " + chatRoomRequest.getName());
-
System.out.println(
"chatValue = " + chatRoomRequest.getChatValue());
-
ChatRoomResponse response=
new ChatRoomResponse();
-
response.setName(chatRoomRequest.getName());
-
response.setChatValue(chatRoomRequest.getChatValue());
-
this.template.convertAndSendToUser(chatRoomRequest.getUserId()+
"",
"/alone/getResponse",response);
-
return response;
-
}
-
}
简单介绍新的注解一下:
一.@MessageMapping("/massRequest"):类似与@RequestMapping,客户端请求服务器的URL,前提是双方端点已经打开
二.@SendTo("/mass/getResponse"):作用跟convertAndSend类似,广播发给与该通道相连的客户端
其他已经在前面解释过了。
3.html代码
-
<!DOCTYPE html>
-
<html>
-
<head>
-
<title>login.html
</title>
-
-
<meta name="keywords" content="keyword1,keyword2,keyword3">
-
<meta name="description" content="this is my page">
-
<meta name="content-type" content="text/html" charset="UTF-8">
-
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
-
<!-- 独立css -->
-
<link rel="stylesheet" type="text/css" href="chatroom.css">
-
</head>
-
-
<body>
-
<div>
-
<div style="float:left;width:40%">
-
<p>请选择你是谁:
</p>
-
<select id="selectName" onchange="sendAloneUser();">
-
<option value="1">请选择
</option>
-
<option value="ALong">ALong
</option>
-
<option value="AKan">AKan
</option>
-
<option value="AYuan">AYuan
</option>
-
<option value="ALai">ALai
</option>
-
<option value="ASheng">ASheng
</option>
-
</select>
-
<div class="chatWindow">
-
<p style="color:darkgrey">群聊:
</p>
-
<section id="chatRecord" class="chatRecord">
-
<p id="titleval" style="color:#CD2626;">
</p>
-
</section>
-
<section class="sendWindow">
-
<textarea name="sendChatValue" id="sendChatValue" class="sendChatValue">
</textarea>
-
<input type="button" name="sendMessage" id="sendMessage" class="sendMessage" onclick="sendMassMessage()" value="发送">
-
</section>
-
</div>
-
</div>
-
-
-
<div style="float:right; width:40%">
-
<p>请选择你要发给谁:
</p>
-
<select id="selectName2">
-
<option value="1">请选择
</option>
-
<option value="ALong">ALong
</option>
-
<option value="AKan">AKan
</option>
-
<option value="AYuan">AYuan
</option>
-
<option value="ALai">ALai
</option>
-
<option value="ASheng">ASheng
</option>
-
</select>
-
<div class="chatWindow">
-
<p style="color:darkgrey">单独聊:
</p>
-
<section id="chatRecord2" class="chatRecord">
-
<p id="titleval" style="color:#CD2626;">
</p>
-
</section>
-
<section class="sendWindow">
-
<textarea name="sendChatValue2" id="sendChatValue2" class="sendChatValue">
</textarea>
-
<input type="button" name="sendMessage" id="sendMessage" class="sendMessage" onclick="sendAloneMessage()" value="发送">
-
</section>
-
</div>
-
</div>
-
</div>
-
<!-- 独立JS -->
-
<script type="text/javascript" src="jquery.min.js" charset="utf-8">
</script>
-
<script type="text/javascript" src="chatroom.js" charset="utf-8">
</script>
-
<script type="text/javascript" src="sockjs.min.js" charset="utf-8">
</script>
-
<script type="text/javascript" src="stomp.js" charset="utf-8">
</script>
-
</body>
-
</html>
JS代码[chatroom.js]:
-
var stompClient =
null;
-
-
//加载完浏览器后 调用connect(),打开双通道
-
$(
function(){
-
//打开双通道
-
connect()
-
})
-
-
//强制关闭浏览器 调用websocket.close(),进行正常关闭
-
window.onunload =
function() {
-
disconnect()
-
}
-
-
//打开双通道
-
function connect(){
-
var socket =
new SockJS(
'http://172.16.0.56:9091/sbjm-cheng/endpointOyzc');
//连接SockJS的endpoint名称为"endpointAric"
-
stompClient = Stomp.over(socket);
//使用STMOP子协议的WebSocket客户端
-
stompClient.connect({},
function(frame){
//连接WebSocket服务端
-
-
console.log(
'Connected:' + frame);
-
//广播接收信息
-
stompTopic();
-
-
});
-
}
-
-
//关闭双通道
-
function disconnect(){
-
if(stompClient !=
null) {
-
stompClient.disconnect();
-
}
-
console.log(
"Disconnected");
-
}
-
-
//广播(一对多)
-
function stompTopic(){
-
//通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息(广播接收信息)
-
stompClient.subscribe(
'/mass/getResponse',
function(response){
-
var message=
JSON.parse(response.body);
-
//展示广播的接收的内容接收
-
var response = $(
"#chatRecord");
-
response.append(
"<p><span>"+message.name+
":</span><span>"+message.chatValue+
"</span></p>");
-
});
-
}
-
-
//列队(一对一)
-
function stompQueue(){
-
-
var userId=$(
"#selectName").val();
-
alert(
"监听:"+userId)
-
//通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息(队列接收信息)
-
stompClient.subscribe(
'/user/' + userId +
'/alone/getResponse',
function(response){
-
var message=
JSON.parse(response.body);
-
//展示一对一的接收的内容接收
-
var response = $(
"#chatRecord2");
-
response.append(
"<p><span>"+message.name+
":</span><span>"+message.chatValue+
"</span></p>");
-
});
-
}
-
-
//选择发送给谁的时候触发连接服务器
-
function sendAloneUser(){
-
stompQueue();
-
}
-
-
//群发
-
function sendMassMessage(){
-
var postValue={};
-
var chatValue=$(
"#sendChatValue");
-
var userName=$(
"#selectName").val();
-
postValue.name=userName;
-
postValue.chatValue=chatValue.val();
-
if(userName==
1||userName==
null){
-
alert(
"请选择你是谁!");
-
return;
-
}
-
if(chatValue==
""||userName==
null){
-
alert(
"不能发送空消息!");
-
return;
-
}
-
stompClient.send(
"/massRequest",{},
JSON.stringify(postValue));
-
chatValue.val(
"");
-
}
-
//单独发
-
function sendAloneMessage(){
-
var postValue={};
-
var chatValue=$(
"#sendChatValue2");
-
var userName=$(
"#selectName").val();
-
var sendToId=$(
"#selectName2").val();
-
var response = $(
"#chatRecord2");
-
postValue.name=userName;
-
postValue.chatValue=chatValue.val();
-
postValue.userId=sendToId;
-
if(userName==
1||userName==
null){
-
alert(
"请选择你是谁!");
-
return;
-
}
-
if(sendToId==
1||sendToId==
null){
-
alert(
"请选择你要发给谁!");
-
return;
-
}
-
if(chatValue==
""||userName==
null){
-
alert(
"不能发送空消息!");
-
return;
-
}
-
stompClient.send(
"/aloneRequest",{},
JSON.stringify(postValue));
-
response.append(
"<p><span>"+userName+
":</span><span>"+chatValue.val()+
"</span></p>");
-
chatValue.val(
"");
-
}
chatroom.css
-
.chatWindow{
-
-
width:
100%;
-
height:
500px;
-
border:
1px solid blue;
-
}
-
.chatRecord{
-
width:
100%;
-
height:
400px;
-
border-bottom:
1px solid blue;
-
line-height:
20px;
-
overflow:auto;
-
overflow-x:hidden;
-
}
-
.sendWindow{
-
width:
100%;
-
height:
200px;
-
}
-
.sendChatValue{
-
-
width:
90%;
-
height:
40px;
-
-
}
另外还需要的3个JS包,jquery.min.js、sockjs.min.js、stomp.js。
针对 执丶笔同学提出的问题作如下补充
websocket 注解介绍
1. @MessageMapping
@MessageMapping,用户处理client发送过来的消息,被注解的方法可以具有以下参数。
- Message:用于接收完整的消息
- MessageHeaders:用于接收消息中的头信息
- MessageHeaderAccessor/SimpMessageHeaderAccessor/StompHeaderAccessor:用于接收消息中的头信息,并且构建绑定Spring中的一些附加信息
- @Headers:用于接收消息中的所有header。这个参数必须用java.util.Map
- @Header:用于接收特定的头值
- @Payload:接受STOMP协议中的Body,可以用@javax.validation进行注释, Spring的@Validated自动验证 (类似@RequestBody)
- DestinationVariable: 用于提取header中destination模板变量 (类似@PathVariable)
- java.security.Principal:接收在WebSocket HTTP握手时登录的用户
当@MessageMapping方法返回一个值时,默认情况下,该值在被序列化为Payload后,作为消息发送到向订阅者广播的“brokerChannel”,且消息destination与接收destination相同,但前缀为变为配置的值。
可以使用@SendTo指定发送的destination,将Payload消息,进行广播发送到订阅的客户端。@SendToUser是会向与当条消息关联的用户发送回执消息,还可以使用SimpMessagingTemplate发送代替SendTo/@SendToUserji进行消息的发送
2. @SubscribeMapping
@SubscribeMapping注释与@MessageMapping结合使用,以缩小到订阅消息的映射。在这种情况下,@MessageMapping注释指定目标,而@SubscribeMapping仅表示对订阅消息的兴趣。
@SubscribeMapping通常与@MessageMapping没有区别。关键区别在于,@SubscribeMapping的方法的返回值被序列化后,会发送到“clientOutboundChannel”,而不是“brokerChannel”,直接回复到客户端,而不是通过代理进行广播。这对于实现一次性的、请求-应答消息交换非常有用,并且从不占用订阅。这种模式的常见场景是当数据必须加载和呈现时应用程序初始化。
@SendTo注释@SubscribeMapping方法,在这种情况下,返回值被发送到带有显式指定目标目的地的“brokerChannel”。
3. @MessageExceptionHandler
应用程序可以使用@MessageExceptionHandler方法来处理@MessageMapping方法中的异常。 @MessageExceptionHandler方法支持灵活的方法签名,并支持与@MessageMapping方法相同的方法参数类型和返回值。与Spring MVC中的@ExceptionHandler类似。
-
@Controller
-
public
abstract
class BaseController {
-
@MessageExceptionHandler(MyException.class)
-
public xxx handleException(MyException exception) {
-
// ...
-
return Xxx;
-
}
-
}
-
public
class WsController extends BaseController {
-
// ...
-
}
如有错漏,请各位大神指教!
DEMO地址: https://gitee.com/liyongzhi_coder/websocket-demo.git
转载:https://blog.csdn.net/liyongzhi1992/article/details/81221103