小言_互联网的博客

springboot+websocket+sockjs进行消息推送【基于STOMP协议】

442人阅读  评论(0)

1.浅谈WebSocket

WebSocket是在HTML5基础上单个TCP连接上进行全双工通讯的协议,只要浏览器和服务器进行一次握手,就可以建立一条快速通道,两者就可以实现数据互传了。说白了,就是打破了传统的http协议的无状态传输(只能浏览器请求,服务端响应),websocket全双工通讯,就是浏览器和服务器进行一次握手,浏览器可以随时给服务器发送信息,服务器也可以随时主动发送信息给浏览器了。对webSocket原理有兴趣的客官,可以自行百度。

2.环境搭建

因为是根据项目的需求来的,所以这里我只介绍在SpringBoot下使用WebSocket的其中一种实现【STOMP协议】。因此整个工程涉及websocket使用的大致框架为SpringBoot+Maven+websocket,其他框架的基础搭建,我这里就不说了,相信各位也都很熟悉,我就直接集成websocket了。

在pox.xml加上对springBoot对WebSocket的支持:


  
  1. <!-- webSocket -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-websocket</artifactId>
  5. </dependency>

这样SpringBoot就和WebSocket集成好了,我们就可以直接使用SpringBoot提供对WebSocket操作的API了

3.编码实现

①在Spring上下文中添加对WebSocket的配置


  
  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.messaging.simp.config.MessageBrokerRegistry;
  3. import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
  4. import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
  5. import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
  6. /**
  7. * 配置WebSocket
  8. */
  9. @Configuration
  10. //注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
  11. @EnableWebSocketMessageBroker
  12. public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
  13. @Override
  14. //注册STOMP协议的节点(endpoint),并映射指定的url
  15. public void registerStompEndpoints(StompEndpointRegistry registry) {
  16. //注册一个STOMP的endpoint,并指定使用SockJS协议
  17. registry.addEndpoint( "/endpointOyzc").setAllowedOrigins( "*").withSockJS();
  18. }
  19. @Override
  20. //配置消息代理(Message Broker)
  21. public void configureMessageBroker(MessageBrokerRegistry registry) {
  22. //点对点应配置一个/user消息代理,广播式应配置一个/topic消息代理
  23. registry.enableSimpleBroker( "/topic", "/user");
  24. //点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/
  25. registry.setUserDestinationPrefix( "/user");
  26. }
  27. }

介绍以上几个相关的注解和方法:

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的代码


  
  1. package com.cheng.sbjm.boot;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.messaging.simp.SimpMessagingTemplate;
  4. import org.springframework.scheduling.annotation.Scheduled;
  5. import org.springframework.stereotype.Controller;
  6. import com.cheng.sbjm.domain.User;
  7. @Controller
  8. public class WebSocketController {
  9. @Autowired
  10. private SimpMessagingTemplate template;
  11. //广播推送消息
  12. @Scheduled(fixedRate = 10000)
  13. public void sendTopicMessage() {
  14. System.out.println( "后台广播推送!");
  15. User user= new User();
  16. user.setUserName( "oyzc");
  17. user.setAge( 10);
  18. this.template.convertAndSend( "/topic/getResponse",user);
  19. }
  20. }

简单介绍一下

1.SimpMessagingTemplate:SpringBoot提供操作WebSocket的对象

2.@Scheduled(fixedRate = 10000):为了测试,定时10S执行这个方法,向客户端推送

3.template.convertAndSend("/topic/getResponse",new AricResponse("后台实时推送:,Oyzc!")); :直接向前端推送消息。

3.1参数一:客户端监听指定通道时,设定的访问服务器的URL

3.2参数二:发送的消息(可以是对象、字符串等等)

 

在上客户端的代码(PC现代浏览器)

html页面:


  
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>websocket.html </title>
  5. <meta name="keywords" content="keyword1,keyword2,keyword3">
  6. <meta name="description" content="this is my page">
  7. <meta name="content-type" content="text/html" charset="UTF-8">
  8. <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
  9. </head>
  10. <body>
  11. <div>
  12. <p id="response"> </p>
  13. </div>
  14. <!-- 独立JS -->
  15. <script type="text/javascript" src="jquery.min.js" charset="utf-8"> </script>
  16. <script type="text/javascript" src="webSocket.js" charset="utf-8"> </script>
  17. <script type="text/javascript" src="sockjs.min.js" charset="utf-8"> </script>
  18. <script type="text/javascript" src="stomp.js" charset="utf-8"> </script>
  19. </body>
  20. </html>

JS代码[webSocket.js]


  
  1. var stompClient = null;
  2. //加载完浏览器后 调用connect(),打开双通道
  3. $( function(){
  4. //打开双通道
  5. connect()
  6. })
  7. //强制关闭浏览器 调用websocket.close(),进行正常关闭
  8. window.onunload = function() {
  9. disconnect()
  10. }
  11. function connect(){
  12. var socket = new SockJS( 'http://127.0.0.1:9091/sbjm-cheng/endpointOyzc'); //连接SockJS的endpoint名称为"endpointOyzc"
  13. stompClient = Stomp.over(socket); //使用STMOP子协议的WebSocket客户端
  14. stompClient.connect({}, function(frame){ //连接WebSocket服务端
  15. console.log( 'Connected:' + frame);
  16. //通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息
  17. stompClient.subscribe( '/topic/getResponse', function(response){
  18. showResponse( JSON.parse(response.body));
  19. });
  20. });
  21. }
  22. //关闭双通道
  23. function disconnect(){
  24. if(stompClient != null) {
  25. stompClient.disconnect();
  26. }
  27. console.log( "Disconnected");
  28. }
  29. function showResponse(message){
  30. var response = $( "#response");
  31. response.append( "<p>"+message.userName+ "</p>");
  32. }

值得注意的是,只需要在连接服务器注册端点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的代码


  
  1. package com.cheng.sbjm.boot;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.messaging.simp.SimpMessagingTemplate;
  4. import org.springframework.scheduling.annotation.Scheduled;
  5. import org.springframework.stereotype.Controller;
  6. import com.cheng.sbjm.domain.User;
  7. @Controller
  8. public class WebSocketController {
  9. @Autowired
  10. private SimpMessagingTemplate template;
  11. //一对一推送消息
  12. @Scheduled(fixedRate = 10000)
  13. public void sendQueueMessage() {
  14. System.out.println( "后台一对一推送!");
  15. User user= new User();
  16. user.setUserId( 1);
  17. user.setUserName( "oyzc");
  18. user.setAge( 10);
  19. this.template.convertAndSendToUser(user.getUserId()+ "", "/queue/getResponse",user);
  20. }
  21. }

简单介绍一下:

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页面:


  
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>websocket.html </title>
  5. <meta name="keywords" content="keyword1,keyword2,keyword3">
  6. <meta name="description" content="this is my page">
  7. <meta name="content-type" content="text/html" charset="UTF-8">
  8. <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
  9. <!-- 独立css -->
  10. </head>
  11. <body>
  12. <div>
  13. <p id="response"> </p>
  14. </div>
  15. <!-- 独立JS -->
  16. <script type="text/javascript" src="jquery.min.js" charset="utf-8"> </script>
  17. <script type="text/javascript" src="webSocket.js" charset="utf-8"> </script>
  18. <script type="text/javascript" src="sockjs.min.js" charset="utf-8"> </script>
  19. <script type="text/javascript" src="stomp.js" charset="utf-8"> </script>
  20. </body>
  21. </html>

JS代码[webSocket.js]


  
  1. var stompClient = null;
  2. //加载完浏览器后 调用connect(),打开双通道
  3. $( function(){
  4. //打开双通道
  5. connect()
  6. })
  7. //强制关闭浏览器 调用websocket.close(),进行正常关闭
  8. window.onunload = function() {
  9. disconnect()
  10. }
  11. function connect(){
  12. var userId= 1;
  13. var socket = new SockJS( 'http://127.0.0.1:9091/sbjm-cheng/endpointOyzc'); //连接SockJS的endpoint名称为"endpointOyzc"
  14. stompClient = Stomp.over(socket); //使用STMOP子协议的WebSocket客户端
  15. stompClient.connect({}, function(frame){ //连接WebSocket服务端
  16. console.log( 'Connected:' + frame);
  17. //通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息
  18. stompClient.subscribe( '/user/' + userId + '/queue/getResponse', function(response){
  19. var code= JSON.parse(response.body);
  20. showResponse(code)
  21. });
  22. });
  23. }
  24. //关闭双通道
  25. function disconnect(){
  26. if(stompClient != null) {
  27. stompClient.disconnect();
  28. }
  29. console.log( "Disconnected");
  30. }
  31. function showResponse(message){
  32. var response = $( "#response");
  33. response.append( "<p>只有userID为"+message.userId+ "的人才能收到</p>");
  34. }

与广播不同的是,在指定通道的URL加个用户标识:

 stompClient.subscribe('/user/' + userId + '/queue/getResponse',function(response){
            var code=JSON.parse(response.body);                      
            showResponse(code)              

            });

该标识userId必须与服务器推送消息时设置的用户标识一致

 

以上就是实现服务器实时向客户端推送消息,各位可以按照各自的需求进行配合使用。

 

③实现客户端与服务器之间的直接交互,聊天室demo[在②的基础上添加了一些代码]

1.在webSocket配置中,增加2个WebSocket的代理


  
  1. package com.cheng.sbjm.configure;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.messaging.simp.config.MessageBrokerRegistry;
  4. import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
  5. import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
  6. import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
  7. /**
  8. * 配置WebSocket
  9. */
  10. @Configuration
  11. //注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
  12. @EnableWebSocketMessageBroker
  13. public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
  14. @Override
  15. //注册STOMP协议的节点(endpoint),并映射指定的url
  16. public void registerStompEndpoints(StompEndpointRegistry registry) {
  17. //注册一个STOMP的endpoint,并指定使用SockJS协议
  18. registry.addEndpoint( "/endpointOyzc").setAllowedOrigins( "*").withSockJS();
  19. }
  20. @Override
  21. //配置消息代理(Message Broker)
  22. public void configureMessageBroker(MessageBrokerRegistry registry) {
  23. //点对点应配置一个/user消息代理,广播式应配置一个/topic消息代理,群发(mass),单独聊天(alone)
  24. registry.enableSimpleBroker( "/topic", "/user", "/mass", "/alone");
  25. //点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/
  26. registry.setUserDestinationPrefix( "/user");
  27. }
  28. }

"/mass"用以代理群发消息

"/alone"用以代码一对一聊天

2.java后台实现


  
  1. package com.cheng.sbjm.boot;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.messaging.handler.annotation.MessageMapping;
  4. import org.springframework.messaging.handler.annotation.SendTo;
  5. import org.springframework.messaging.simp.SimpMessagingTemplate;
  6. import org.springframework.stereotype.Controller;
  7. import com.cheng.sbjm.onput.ChatRoomRequest;
  8. import com.cheng.sbjm.onput.ChatRoomResponse;
  9. @Controller
  10. public class WebSocketController {
  11. @Autowired
  12. private SimpMessagingTemplate template;
  13. //客户端主动发送消息到服务端,服务端马上回应指定的客户端消息
  14. //类似http无状态请求,但是有质的区别
  15. //websocket可以从服务器指定发送哪个客户端,而不像http只能响应请求端
  16. //群发
  17. @MessageMapping("/massRequest")
  18. //SendTo 发送至 Broker 下的指定订阅路径
  19. @SendTo("/mass/getResponse")
  20. public ChatRoomResponse mass(ChatRoomRequest chatRoomRequest){
  21. //方法用于群发测试
  22. System.out.println( "name = " + chatRoomRequest.getName());
  23. System.out.println( "chatValue = " + chatRoomRequest.getChatValue());
  24. ChatRoomResponse response= new ChatRoomResponse();
  25. response.setName(chatRoomRequest.getName());
  26. response.setChatValue(chatRoomRequest.getChatValue());
  27. return response;
  28. }
  29. //单独聊天
  30. @MessageMapping("/aloneRequest")
  31. public ChatRoomResponse alone(ChatRoomRequest chatRoomRequest){
  32. //方法用于一对一测试
  33. System.out.println( "userId = " + chatRoomRequest.getUserId());
  34. System.out.println( "name = " + chatRoomRequest.getName());
  35. System.out.println( "chatValue = " + chatRoomRequest.getChatValue());
  36. ChatRoomResponse response= new ChatRoomResponse();
  37. response.setName(chatRoomRequest.getName());
  38. response.setChatValue(chatRoomRequest.getChatValue());
  39. this.template.convertAndSendToUser(chatRoomRequest.getUserId()+ "", "/alone/getResponse",response);
  40. return response;
  41. }
  42. }

简单介绍新的注解一下:

一.@MessageMapping("/massRequest"):类似与@RequestMapping,客户端请求服务器的URL,前提是双方端点已经打开

二.@SendTo("/mass/getResponse"):作用跟convertAndSend类似,广播发给与该通道相连的客户端

其他已经在前面解释过了。

3.html代码


  
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>login.html </title>
  5. <meta name="keywords" content="keyword1,keyword2,keyword3">
  6. <meta name="description" content="this is my page">
  7. <meta name="content-type" content="text/html" charset="UTF-8">
  8. <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
  9. <!-- 独立css -->
  10. <link rel="stylesheet" type="text/css" href="chatroom.css">
  11. </head>
  12. <body>
  13. <div>
  14. <div style="float:left;width:40%">
  15. <p>请选择你是谁: </p>
  16. <select id="selectName" onchange="sendAloneUser();">
  17. <option value="1">请选择 </option>
  18. <option value="ALong">ALong </option>
  19. <option value="AKan">AKan </option>
  20. <option value="AYuan">AYuan </option>
  21. <option value="ALai">ALai </option>
  22. <option value="ASheng">ASheng </option>
  23. </select>
  24. <div class="chatWindow">
  25. <p style="color:darkgrey">群聊: </p>
  26. <section id="chatRecord" class="chatRecord">
  27. <p id="titleval" style="color:#CD2626;"> </p>
  28. </section>
  29. <section class="sendWindow">
  30. <textarea name="sendChatValue" id="sendChatValue" class="sendChatValue"> </textarea>
  31. <input type="button" name="sendMessage" id="sendMessage" class="sendMessage" onclick="sendMassMessage()" value="发送">
  32. </section>
  33. </div>
  34. </div>
  35. <div style="float:right; width:40%">
  36. <p>请选择你要发给谁: </p>
  37. <select id="selectName2">
  38. <option value="1">请选择 </option>
  39. <option value="ALong">ALong </option>
  40. <option value="AKan">AKan </option>
  41. <option value="AYuan">AYuan </option>
  42. <option value="ALai">ALai </option>
  43. <option value="ASheng">ASheng </option>
  44. </select>
  45. <div class="chatWindow">
  46. <p style="color:darkgrey">单独聊: </p>
  47. <section id="chatRecord2" class="chatRecord">
  48. <p id="titleval" style="color:#CD2626;"> </p>
  49. </section>
  50. <section class="sendWindow">
  51. <textarea name="sendChatValue2" id="sendChatValue2" class="sendChatValue"> </textarea>
  52. <input type="button" name="sendMessage" id="sendMessage" class="sendMessage" onclick="sendAloneMessage()" value="发送">
  53. </section>
  54. </div>
  55. </div>
  56. </div>
  57. <!-- 独立JS -->
  58. <script type="text/javascript" src="jquery.min.js" charset="utf-8"> </script>
  59. <script type="text/javascript" src="chatroom.js" charset="utf-8"> </script>
  60. <script type="text/javascript" src="sockjs.min.js" charset="utf-8"> </script>
  61. <script type="text/javascript" src="stomp.js" charset="utf-8"> </script>
  62. </body>
  63. </html>

JS代码[chatroom.js]:


  
  1. var stompClient = null;
  2. //加载完浏览器后 调用connect(),打开双通道
  3. $( function(){
  4. //打开双通道
  5. connect()
  6. })
  7. //强制关闭浏览器 调用websocket.close(),进行正常关闭
  8. window.onunload = function() {
  9. disconnect()
  10. }
  11. //打开双通道
  12. function connect(){
  13. var socket = new SockJS( 'http://172.16.0.56:9091/sbjm-cheng/endpointOyzc'); //连接SockJS的endpoint名称为"endpointAric"
  14. stompClient = Stomp.over(socket); //使用STMOP子协议的WebSocket客户端
  15. stompClient.connect({}, function(frame){ //连接WebSocket服务端
  16. console.log( 'Connected:' + frame);
  17. //广播接收信息
  18. stompTopic();
  19. });
  20. }
  21. //关闭双通道
  22. function disconnect(){
  23. if(stompClient != null) {
  24. stompClient.disconnect();
  25. }
  26. console.log( "Disconnected");
  27. }
  28. //广播(一对多)
  29. function stompTopic(){
  30. //通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息(广播接收信息)
  31. stompClient.subscribe( '/mass/getResponse', function(response){
  32. var message= JSON.parse(response.body);
  33. //展示广播的接收的内容接收
  34. var response = $( "#chatRecord");
  35. response.append( "<p><span>"+message.name+ ":</span><span>"+message.chatValue+ "</span></p>");
  36. });
  37. }
  38. //列队(一对一)
  39. function stompQueue(){
  40. var userId=$( "#selectName").val();
  41. alert( "监听:"+userId)
  42. //通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息(队列接收信息)
  43. stompClient.subscribe( '/user/' + userId + '/alone/getResponse', function(response){
  44. var message= JSON.parse(response.body);
  45. //展示一对一的接收的内容接收
  46. var response = $( "#chatRecord2");
  47. response.append( "<p><span>"+message.name+ ":</span><span>"+message.chatValue+ "</span></p>");
  48. });
  49. }
  50. //选择发送给谁的时候触发连接服务器
  51. function sendAloneUser(){
  52. stompQueue();
  53. }
  54. //群发
  55. function sendMassMessage(){
  56. var postValue={};
  57. var chatValue=$( "#sendChatValue");
  58. var userName=$( "#selectName").val();
  59. postValue.name=userName;
  60. postValue.chatValue=chatValue.val();
  61. if(userName== 1||userName== null){
  62. alert( "请选择你是谁!");
  63. return;
  64. }
  65. if(chatValue== ""||userName== null){
  66. alert( "不能发送空消息!");
  67. return;
  68. }
  69. stompClient.send( "/massRequest",{}, JSON.stringify(postValue));
  70. chatValue.val( "");
  71. }
  72. //单独发
  73. function sendAloneMessage(){
  74. var postValue={};
  75. var chatValue=$( "#sendChatValue2");
  76. var userName=$( "#selectName").val();
  77. var sendToId=$( "#selectName2").val();
  78. var response = $( "#chatRecord2");
  79. postValue.name=userName;
  80. postValue.chatValue=chatValue.val();
  81. postValue.userId=sendToId;
  82. if(userName== 1||userName== null){
  83. alert( "请选择你是谁!");
  84. return;
  85. }
  86. if(sendToId== 1||sendToId== null){
  87. alert( "请选择你要发给谁!");
  88. return;
  89. }
  90. if(chatValue== ""||userName== null){
  91. alert( "不能发送空消息!");
  92. return;
  93. }
  94. stompClient.send( "/aloneRequest",{}, JSON.stringify(postValue));
  95. response.append( "<p><span>"+userName+ ":</span><span>"+chatValue.val()+ "</span></p>");
  96. chatValue.val( "");
  97. }

chatroom.css


  
  1. .chatWindow{
  2. width: 100%;
  3. height: 500px;
  4. border: 1px solid blue;
  5. }
  6. .chatRecord{
  7. width: 100%;
  8. height: 400px;
  9. border-bottom: 1px solid blue;
  10. line-height: 20px;
  11. overflow:auto;
  12. overflow-x:hidden;
  13. }
  14. .sendWindow{
  15. width: 100%;
  16. height: 200px;
  17. }
  18. .sendChatValue{
  19. width: 90%;
  20. height: 40px;
  21. }

另外还需要的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类似。


  
  1. @Controller
  2. public abstract class BaseController {
  3. @MessageExceptionHandler(MyException.class)
  4. public xxx handleException(MyException exception) {
  5. // ...
  6. return Xxx;
  7. }
  8. }
  9. public class WsController extends BaseController {
  10. // ...
  11. }

如有错漏,请各位大神指教!

DEMO地址: https://gitee.com/liyongzhi_coder/websocket-demo.git


转载:https://blog.csdn.net/liyongzhi1992/article/details/81221103
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场