Spring Boot 为 websocket 提供了一些默认配置,简化了 websocket 使用,这里我们将使用 Spring Boot websocket,并加入 stomp 和 sockjs 的支持,快速编写一个简单的网页聊天室,实现广播消息推送以及点对点的私人消息推送。
篇幅限制下边只给出关键的代码,需要 HTML 页面代码或项目完整源代码的可到这里查看(使用 IDEA 导入后可直接运行)。
基本页面: 将服务器关闭,客户端自动重连: 超过重连次数后,不再重连:
项目的编写分为服务器端和客户端,因此下边也就分为这两个方面进行讲述
由于 spring boot 的默认配置,大大简化了开发,服务器端需要编写的只有两个地方:配置类和控制器。
当然首先需要引入依赖(这里使用 gradle 作为包管理工具)
compile('org.springframework.boot:spring-boot-starter-web') compile('org.springframework.boot:spring-boot-starter-websocket')然后是 websocket 的配置类 WebSocketConfig,配置项的解释见注释
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic", "/user");// “/topic“ 用于给客户端订阅广播信息,”/user“用于给客户端订阅点对点消息 //registry.setApplicationDestinationPrefixes("/app");// 客户端向服务器发送消息时 URL 为:【/app + controller中 @MessageMapping 的地址】,此处暂时不使用该配置 //registry.setUserDestinationPrefix("/user/");// 客户端向指定用户发送(一对一)信息时 URL 前缀是“/user/”,即使不配置默认也是“/user/“ } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/endpoint").withSockJS();//注册客户端websocket连接的端口 } }这里需要说一下其中用到的几个注解: - 方法注解 - @MessageMapping(value = “/URL”) 匹配客户端 send 消息时的URL; - @sendTo 和 @sendToUser 分别用于给客户端订阅广播消息和点对点消息; - 参数注解 - @Payload:使用客户端 STOMP 帧的 body 赋值; - @Header(“xxx”):使用客户端 STOMP 帧的 headers 中的 xxx 赋值;
在查阅资料的时候,看到也可以使用 SimpMessagingTemplate 进行消息的代理转发,可以这么理解:
@MessageMapping("/chat") public void chat(String value){ this.simpMessagingTemplate.convertAndSend("/topic/getResponse", value); }等同于
@MessageMapping("/chat") @SendTo("/topic/getResponse") public String chat(String value) { return value; }客户端的代码主要是使用 JavaScript 进行 websocket 的一系列操作,由于使用 STOMP 协议,因此需要使用 STOMP API, 关于 STOMP API 的使用,可以参考这里的 总结。
基本操作如下
var socket = new SockJS('/endpoint'); stompClient = Stomp.over(socket); stompClient.connect( {}, function connectCallback (frame) {...}, function errorCallBack (error) {...} );使用JavaScript设置自动重连机制,与服务器断开连接后自动重来,重连失败超过10后不再重连
function errorCallBack (error) { document.getElementById("state-info").innerHTML = "连接断开"; console.log('连接断开【' + error + '】'); if (curTryNum <= maxTryNum) { document.getElementById("state-info").innerHTML = "连接关闭,10秒后重新连接……"; console.log("连接关闭,10秒后重新连接……"); // 10秒后重新连接,实际效果:每10秒重连一次,直到连接成功 setTimeout(function () { connect(); }, 10000); } else { document.getElementById("state-info").innerHTML = "连接关闭,且已超过最大重连次数,不再重连"; console.log("连接关闭,且已超过最大重连次数,不再重连"); } }