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)
});

浙公网安备 33010602011771号