前言

如题,今天介绍的是 SpringBoot 整合 WebSocket 实现广播消息。

什么是 WebSocket ?

WebSocket 为浏览器和服务器提供了双工异步通信的功能,即浏览器可以向服务器发送信息,反之也成立。

WebSocket 是通过一个 socket 来实现双工异步通信能力的,但直接使用 WebSocket ( 或者 SockJS:WebSocket 协议的模拟,增加了当前浏览器不支持使用 WebSocket 的兼容支持) 协议开发程序显得十分繁琐,所以使用它的子协议 STOMP。

STOMP 协议简介

它是高级的流文本定向消息协议,是一种为 MOM (Message Oriented Middleware,面向消息的中间件) 设计的简单文本协议。

它提供了一个可互操作的连接格式,允许 STOMP 客户端与任意 STOMP 消息代理 (Broker) 进行交互,类似于 OpenWire (一种二进制协议)。

由于其设计简单,很容易开发客户端,因此在多种语言和多种平台上得到广泛应用。其中最流行的 STOMP 消息代理是 Apache ActiveMQ。

STOMP 协议使用一个基于 (frame) 的格式来定义消息,与 Http 的 request 和 response 类似 。

广播

接下来,实现一个广播消息的 demo。即服务端有消息时,将消息发送给所有连接了当前 endpoint 的浏览器。

准备工作

  • SpringBoot 2.1.3
  • IDEA
  • JDK8

Pom 依赖配置

<dependencies>
<!-- thymeleaf 模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- web 启动类 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- WebSocket 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- test 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

代码注释很详细,不多说。

配置 WebSocket

实现 WebSocketMessageBrokerConfigurer 接口,注册一个 STOMP 节点,配置一个广播消息代理

@Configuration
// @EnableWebSocketMessageBroker注解用于开启使用STOMP协议来传输基于代理(MessageBroker)的消息,这时候控制器(controller)
// 开始支持@MessageMapping,就像是使用@requestMapping一样。
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//注册一个 Stomp 的节点(endpoint),并指定使用 SockJS 协议。
registry.addEndpoint("/endpointNasus").withSockJS();
} @Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 广播式配置名为 /nasus 消息代理 , 这个消息代理必须和 controller 中的 @SendTo 配置的地址前缀一样或者全匹配
registry.enableSimpleBroker("/nasus");
}
}

消息类

客户端发送给服务器:

public class Client2ServerMessage {

    private String name;

    public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

服务器发送给客户端:

public class Server2ClientMessage {

    private String responseMessage;

    public Server2ClientMessage(String responseMessage) {
this.responseMessage = responseMessage;
} public String getResponseMessage() {
return responseMessage;
} public void setResponseMessage(String responseMessage) {
this.responseMessage = responseMessage;
}
}

演示控制器代码

@RestController
public class WebSocketController { @MessageMapping("/hello") // @MessageMapping 和 @RequestMapping 功能类似,浏览器向服务器发起消息,映射到该地址。
@SendTo("/nasus/getResponse") // 如果服务器接受到了消息,就会对订阅了 @SendTo 括号中的地址的浏览器发送消息。
public Server2ClientMessage say(Client2ServerMessage message) throws Exception {
Thread.sleep(3000);
return new Server2ClientMessage("Hello," + message.getName() + "!");
} }

引入 STOMP 脚本

将 stomp.min.js (STOMP 客户端脚本) 和 sockJS.min.js (sockJS 客户端脚本) 以及 Jquery 放在 resource 文件夹的 static 目录下。

演示页面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>Spring Boot+WebSocket+广播式</title> </head>
<body onload="disconnect()">
<noscript><h2 style="color: #ff0000">貌似你的浏览器不支持websocket</h2></noscript>
<div>
<div>
<button id="connect" onclick="connect();">连接</button>
<button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
</div>
<div id="conversationDiv">
<label>输入你的名字</label><input type="text" id="name" />
<button id="sendName" onclick="sendName();">发送</button>
<p id="response"></p>
</div>
</div>
<script th:src="@{sockjs.min.js}"></script>
<script th:src="@{stomp.min.js}"></script>
<script th:src="@{jquery.js}"></script>
<script type="text/javascript">
var stompClient = null; function setConnected(connected) {
document.getElementById('connect').disabled = connected;
document.getElementById('disconnect').disabled = !connected;
document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
$('#response').html();
} function connect() {
// 连接 SockJs 的 endpoint 名称为 "/endpointNasus"
var socket = new SockJS('/endpointNasus');
// 使用 STOMP 子协议的 WebSocket 客户端
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
// 通过 stompClient.subscribe 订阅 /nasus/getResponse 目标发送的信息,对应控制器的 SendTo 定义
stompClient.subscribe('/nasus/getResponse', function(respnose){
// 展示返回的信息,只要订阅了 /nasus/getResponse 目标,都可以接收到服务端返回的信息
showResponse(JSON.parse(respnose.body).responseMessage);
});
});
} function disconnect() {
// 断开连接
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
} function sendName() {
// 向服务端发送消息
var name = $('#name').val();
// 通过 stompClient.send 向 /hello (服务端)发送信息,对应控制器 @MessageMapping 中的定义
stompClient.send("/hello", {}, JSON.stringify({ 'name': name }));
} function showResponse(message) {
// 接收返回的消息
var response = $("#response");
response.html(message);
}
</script>
</body>
</html>

页面 Controller

注意,这里使用的是 @Controller 注解,用于匹配 html 前缀,加载页面。

@Controller
public class ViewController { @GetMapping("/nasus")
public String getView(){
return "nasus";
}
}

测试结果

打开三个窗口访问 http://localhost:8080/nasus ,初始页面长这样:

三个页面全部点连接,点击连接订阅 endpoint ,如下图:

在第一个页面,输入名字,点发送 ,如下图:

在第一个页面发送消息,等待 3 秒,结果是 3 个页面都接受到了服务端返回的信息,广播成功。

源码下载:

https://github.com/turoDog/Demo/tree/master/springboot_websocket_demo

如果觉得对你有帮助,请给个 Star 再走呗,非常感谢。

后语

如果本文对你哪怕有一丁点帮助,请帮忙点好看。你的好看是我坚持写作的动力。

另外,关注之后在发送 1024 可领取免费学习资料。

资料详情请看这篇旧文:Python、C++、Java、Linux、Go、前端、算法资料分享

Spring Boot2 系列教程 (十六) | 整合 WebSocket 实现广播的更多相关文章

  1. Spring Boot2 系列教程 (十八) | 整合 MongoDB

    微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 如题,今天介绍下 SpringBoot 是如何整合 MongoDB 的. MongoDB 简介 MongoDB 是由 C++ ...

  2. Spring Boot2 系列教程 (十二) | 整合 thymeleaf

    前言 如题,今天介绍 Thymeleaf ,并整合 Thymeleaf 开发一个简陋版的学生信息管理系统. SpringBoot 提供了大量模板引擎,包含 Freemarker.Groovy.Thym ...

  3. Spring Boot2 系列教程(十六)定时任务的两种实现方式

    在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Qua ...

  4. Spring Boot2 系列教程(十)Spring Boot 整合 Freemarker

    今天来聊聊 Spring Boot 整合 Freemarker. Freemarker 简介 这是一个相当老牌的开源的免费的模版引擎.通过 Freemarker 模版,我们可以将数据渲染成 HTML ...

  5. Spring Boot2 系列教程(十九)Spring Boot 整合 JdbcTemplate

    在 Java 领域,数据持久化有几个常见的方案,有 Spring 自带的 JdbcTemplate .有 MyBatis,还有 JPA,在这些方案中,最简单的就是 Spring 自带的 JdbcTem ...

  6. Spring Boot2 系列教程 (九) | SpringBoot 整合 Mybatis

    前言 如题,今天介绍 SpringBoot 与 Mybatis 的整合以及 Mybatis 的使用,本文通过注解的形式实现. 什么是 Mybatis MyBatis 是支持定制化 SQL.存储过程以及 ...

  7. Spring Boot2 系列教程(十七)SpringBoot 整合 Swagger2

    前后端分离后,维护接口文档基本上是必不可少的工作. 一个理想的状态是设计好后,接口文档发给前端和后端,大伙按照既定的规则各自开发,开发好了对接上了就可以上线了.当然这是一种非常理想的状态,实际开发中却 ...

  8. Spring Boot2 系列教程(二十一)整合 MyBatis

    前面两篇文章和读者聊了 Spring Boot 中最简单的数据持久化方案 JdbcTemplate,JdbcTemplate 虽然简单,但是用的并不多,因为它没有 MyBatis 方便,在 Sprin ...

  9. Spring Boot2 系列教程 (十四) | 统一异常处理

    如题,今天介绍 SpringBoot 是如何统一处理全局异常的.SpringBoot 中的全局异常处理主要起作用的两个注解是 @ControllerAdvice 和 @ExceptionHandler ...

随机推荐

  1. 在Vue 中调用数据出现属性不存在的问题

    这已经是我在调用数据时趟过几次的坑了,索性记录下来防止后面再犯: 一般我们请求数据来渲染一个页面的时候,请求下来的数据基本上都是数组或是对象,再通过列表循环和插值表达式渲染的页面:在data 中提前声 ...

  2. 4-10 items设计

    1,items相当于dict,但是又比字典好 2,parse.urljoin(response.url,post_url)方法,其中image_url是一个域名的话,其中的当前域名就不用再添加. yi ...

  3. Html5 @media + css3 媒体查询

    css3 media媒体查询器用法总结   随着响应式设计模型的诞生,Web网站又要发生翻天腹地的改革浪潮,可能有些人会觉得在国内IE6用户居高不下的情况下,这些新的技术还不会广泛的蔓延下去,那你就错 ...

  4. 提前终止forEach技巧,使用try catch

    学习react优化性能的时候,在render之前,生命周期shouldComponentUpdate里判断前后两次数据是否一致,使用了forEach嵌套if语句,如果满足条件想直接break跳出for ...

  5. linux strace 命令

    有时小问题可以通过观察用户空间的应用程序的行为来追踪. 监视程序也有助于建立对驱 动正确工作的信心. 例如, 我们能够对 scull 感到有信心, 在看了它的读实现如何响应 不同数量数据的读请求之后. ...

  6. H3C配置Hybrid端口

  7. C# 通过 probing 指定 dll 寻找文件夹

    在很大的项目开发,会发现项目引用的 dll 会很多,我想要按照不同的功能,将不同的 dll 放在不同的文件夹 简单的方法是通过修改 App.config 文件指定文件夹,如将文件移动到 abc\12 ...

  8. JS(JavaScript)的进一步了解8(更新中···)

    元素节点的树状图 document>documentElement>body>tagName offsetLeft/offsetTop 结合运动 滚动轮播 1.DOM 全称:docu ...

  9. Linux 内核即插即用规范

    一些新 ISA 设备板遵循特殊的设计规范并且需要一个特别的初始化顺序, 对增加接口板 的简单安装和配置的扩展. 这些板的设计规范称为即插即用, 由一个麻烦的规则集组成, 来建立和配置无跳线的 ISA ...

  10. Codeforces Round #587 C. White Sheet(思维+计算几何)

    传送门 •题意 先给一个白矩阵,再两个黑矩阵 如果两个黑矩阵能把白矩阵包含,则输出NO 否则输出YES •思路 计算几何题还是思维题呢? 想起了上初中高中做几何求面积的题 这个就类似于那样 包含的话分 ...