Spring Boot + WebSocket

环境搭建

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

 

<!-- webSocket -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

 

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

 

编码实现

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

package com.youkong.visitor.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
//注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    //注册STOMP协议的节点(endpoint),并映射指定的url
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //注册一个STOMP的endpoint,并指定使用SockJS协议
        registry.addEndpoint("/visitor-register").setAllowedOrigins("*").withSockJS();
    }
    
    @Override
    //配置消息代理(Message Broker)
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //点对点应配置一个/user消息代理,广播式应配置一个/topic消息代理
        registry.enableSimpleBroker("/topic","/user");
        //点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/
        registry.setUserDestinationPrefix("/user");
    }
    
}

 

②实现服务器主动向客户端推送消息

SpringBoot封装得太好,webSocket用起来太简单(好处:用起来方便,坏处:你不知道底层实现)

1.一对多的实现:

Java代码:

package com.youkong.visitor.task;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import com.youkong.visitor.module.entity.Notification;

@Configuration
@EnableScheduling
public class WebSocketTestTask {

    @Autowired
    private SimpMessagingTemplate template;
    
    @Scheduled(cron = "0/5 * * * * ?")
    private void configureTasks() {
        Notification notification = Notification.builder().message("测试信息").build();
        /**
         * 参数1:客户端监听指定通道时,设定的访问服务器的URL
         * 参数2:发送的消息(可以是对象、字符串等等)
         */
        this.template.convertAndSend("/topic/sendNotification",notification);
    }
    
}

 

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>
    <!-- 自定义封装JS -->
    <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:8085/visitor-register'); //连接SockJS的endpoint名称为"endpointOyzc"
  stompClient = Stomp.over(socket);//使用STMOP子协议的WebSocket客户端
  stompClient.connect({},function(frame){//连接WebSocket服务端     
    console.log('Connected:' + frame);
    //通过stompClient.subscribe订阅/topic/sendNotification目标(destination)发送的消息
    stompClient.subscribe('/topic/sendnotification',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.message+"</p>");
}

值得注意的是,只需要在连接服务器注册端点endPoint时,写访问服务器的全路径URL:

new SockJS('http://127.0.0.1:8085/visitor-register');

其他监听指定服务器广播的URL不需要写全路径

 stompClient.subscribe('/topic/sendNotification',function(response){
     showResponse(JSON.parse(response.body));

 });

 

2.一对一的实现

Java代码:

package com.youkong.visitor.task;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import com.youkong.visitor.module.entity.Notification;

@Configuration
@EnableScheduling
public class WebSocketTestTask {

    @Autowired
    private SimpMessagingTemplate template;
    
    @Scheduled(cron = "0/13 * * * * ?")
    private void userToUser() {
        Notification notification = Notification.builder().message("一对一信息推送").build();
        /**
         * 参数1:唯一标识(通常是用户ID)
         * 参数2:客户端监听指定通道时,设定的访问服务器的URL
         * 参数3:发送的消息(可以是对象、字符串等等)
         */
        this.template.convertAndSendToUser("", "/toUser/sendMessage", notification);
    }
    
}

 

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>
    <!-- 自定义封装JS -->
    <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:8085/visitor-register'); //连接SockJS的endpoint名称为"endpointOyzc" stompClient = Stomp.over(socket);//使用STMOP子协议的WebSocket客户端 stompClient.connect({},function(frame){//连接WebSocket服务端 console.log('Connected:' + frame); //通过stompClient.subscribe订阅/topic/sendNotification目标(destination)发送的消息 stompClient.subscribe('user' + userId + '/toUser/sendMessage',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.message+"</p>"); }

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

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

 });

 

posted @ 2020-08-05 16:04  Yaoson  阅读(413)  评论(0)    收藏  举报