一 WebScoketS 简介

RFC 6455 即 webSockets 协议提供了一种标准化的方式去建立全双工,双方面交流的通道在客户端和服务端甚至单一的TCP连接中进行通信; webSockets 协议其跟HTTP的tcp协议不同,但是其设计目的是通过HTTP协议进行工作,可以使用40或者443端口和重新使用现有的防火墙规则;

  1. GET /spring-websocket-portfolio/portfolio HTTP/1.1
  2. Host: localhost:8080
  3. Upgrade: websocket
  4. Connection: Upgrade
  5. Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
  6. Sec-WebSocket-Protocol: v10.stomp, v11.stomp
  7. Sec-WebSocket-Version: 13
  8. Origin: http://localhost:8080

webSockets 的交互是以HTTP协议开始的,使用Upgrade header 转向使用Upgrade连接;如果非200状态成功响应就类似于下面的信息;如果WebSocket server 是运行在nginx是需要配置WebSocket upgrade requests ;如果是运行在云上,需要查阅相关的云是否支持WebSocket ;

  1. HTTP/1.1 101 Switching Protocols
  2. Upgrade: websocket
  3. Connection: Upgrade
  4. Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
  5. Sec-WebSocket-Protocol: v10.stomp

二 HTTP 和 WebSocket 对比

  1. 在HTTP和REST中一个应用需要很多的URLs;应用和客户端是通过 请求和响应的风格使用这些URLs进行交互;服务端会路由这些请求给基于HTTP 的URL或者方法或者头进行处理;
  2. WebSockets 通常在初始化的时候就只有一个链接,所有应用的消息都是通过相同的TCP连接进行流动;这指向一个完全不同的异步、事件驱动的消息传递体系结构。
  3. WebSocket 是一种低端的协议,不像HTTP,其不规定消息中内容中任何的语义信息;这意味着其没有任何方式去路由或者处理这些信息,除非客户端和服务端在语义上达成一致;
  4. WebSocket 客户端和服务端其交流是通过使用更加高级的消息协议(比如STOMP)和基于HTTP握手请求的Sec-WebSocket-Protocol header ;

三 注意事项

WebSockets可以使web页面具有动态性和交互性。然而,在许多情况下,Ajax和HTTP流或 long polling(轮询)可以提供一个简单有效的解决方案。HTTP流和polling适用于消息不频繁的交互,WebSockets适用于消息较频繁的交互;在 因特网上由于没有Upgrade header 或者 关闭了空闲的长链接,受限于在你有限的代理可能会将WebSockets的交互排除;

四 websocket配置和依赖

4.1 依赖

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.1.1.RELEASE</version>
  5. <relativePath/>
  6. </parent>
  7. <dependencies>
  8. <!-- websocket依赖-->
  9. <dependency>
  10. <groupId>org.springframework.boot</groupId>
  11. <artifactId>spring-boot-starter-websocket</artifactId>
  12. </dependency>
  13. <!-- 模板引擎-->
  14. <dependency>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  17. </dependency>
  18. </dependencies>

4.2 配置

  1. /**
  2. * @Author lsc
  3. * @Description <p>websocket配置类 </p>
  4. * @Date 2019/11/12 22:27
  5. */
  6. //使用STOMP协议来传输基于消息代理的消息,控制器支持在@Controller类中使用@MessageMapping
  7. @EnableWebSocketMessageBroker
  8. @Configurable
  9. @EnableWebSocket
  10. @Component
  11. public class WebConfig implements WebSocketMessageBrokerConfigurer {
  12. @Override
  13. public void registerStompEndpoints(StompEndpointRegistry registry) {
  14. // 注册 Stomp的端点(Endpoint),并且映射指定的url
  15. registry.addEndpoint("/websocket")
  16. .setAllowedOrigins("*") // 添加允许跨域访问
  17. .withSockJS();// 指定SockJS协议
  18. }
  19. @Override
  20. public void configureMessageBroker(MessageBrokerRegistry registry) {
  21. // 启动广播模式代理,只有符合的的路径才发送消息
  22. registry.enableSimpleBroker("/topic");
  23. }
  24. }

五 实体类

5.1 接受消息实体

  1. /**
  2. * @Author lsc
  3. * @Description <p> 接受客户端消息</p>
  4. * @Date 2019/11/12 22:42
  5. */
  6. public class AcceptMessages {
  7. private String name;
  8. public String getName() {
  9. return name;
  10. }
  11. }

5.2 发送消息实体

  1. /**
  2. * @Author lsc
  3. * @Description <p>发送消息给客户端 </p>
  4. * @Date 2019/11/12 22:42
  5. */
  6. public class SendMessages {
  7. private String responseMessage;
  8. public String getResponseMessage() {
  9. return responseMessage;
  10. }
  11. public void setResponseMessage(String responseMessage) {
  12. this.responseMessage = responseMessage;
  13. }
  14. }

六控制器

  1. /**
  2. * @Author lsc
  3. * @Description <p>websockets 之 广播式</p>
  4. * @Date 2019/11/12 22:49
  5. */
  6. @Controller
  7. public class WebSocketsController {
  8. @MessageMapping("/welcome")//类似@RequestMapping,进行客户端请求地址映射
  9. @SendTo("/topic/getResponse")//订阅了@SendTo中的路径进行发送消息
  10. public SendMessages broadcast(AcceptMessages acceptMessages){
  11. System.out.println(acceptMessages.getName());
  12. SendMessages sendMessages = new SendMessages();
  13. sendMessages.setResponseMessage("知识追寻者:"+acceptMessages.getName());
  14. return sendMessages;
  15. }
  16. }

七 前端页面

在 resource目录下新建templates目录存放WebSockets.html;在resource目录下新建static目录,继续在其子目录下新建js目录存放sockjs.min.js,stomp.min.js,jquery-3.3.1.min.js;

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8"/>
  5. <title>springboot广播式WebSocket</title>
  6. </head>
  7. <body onload="disconnect()">
  8. <noscript><h2 style="color: #ffff0000;">Sorry,not support the WebSocket</h2></noscript>
  9. <div>
  10. <div>
  11. <button id="connect" onclick="connect();">连接</button>
  12. <button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
  13. </div>
  14. <div id="conversationDiv">
  15. <label>输入你的名字</label>
  16. <input type="text" id="name"/>
  17. <button id="sendName" onclick="sendName();">发送</button>
  18. <p id="response"></p>
  19. </div>
  20. </div>
  21. <script th:src="@{js/sockjs.min.js}"></script>
  22. <script th:src="@{js/stomp.min.js}"></script>
  23. <script th:src="@{js/jquery-3.3.1.min.js}"></script>
  24. <script type="text/javascript">
  25. var stompClient = null;
  26. // 设置连接
  27. function setConnected(connected) {
  28. document.getElementById("connect").disabled = connected;
  29. document.getElementById("disconnect").disabled = !connected;
  30. document.getElementById("conversationDiv").style.visibility = connected ? 'visible' : 'hidden';
  31. $("#response").html();
  32. }
  33. // 连接
  34. function connect() {
  35. // 转向 endpoint 名为websocket
  36. var socket = new SockJS('/websocket');
  37. // 使用ssocket的协议
  38. stompClient = Stomp.over(socket);
  39. // 连接
  40. stompClient.connect({}, function (frame) {
  41. setConnected(true);
  42. console.log('Connected:' + frame);
  43. // @Sendto 中定义路径 向目标订阅消息
  44. stompClient.subscribe('/topic/getResponse', function (response) {
  45. showResponse(JSON.parse(response.body).responseMessage);
  46. })
  47. });
  48. }
  49. function disconnect() {
  50. if (stompClient != null) {
  51. stompClient.disconnect();
  52. }
  53. setConnected(false);
  54. console.log('Disconnected');
  55. }
  56. function sendName() {
  57. var name = $('#name').val();
  58. // 控制器@MessageMapping中定义向目标发送消息
  59. stompClient.send("/welcome", {}, JSON.stringify({'name': name}));
  60. }
  61. function showResponse(message) {
  62. $("#response").html(message);
  63. }
  64. </script>
  65. </body>
  66. </html>

八 视图转发

当客户端请求地址是localhost:8080/ws,经过springmvc视图转发器至WebSockets.html;

  1. /**
  2. * @Author lsc
  3. * @Description <p> spingmvc视图映射转发</p>
  4. * @Date 2019/11/12 23:35
  5. */
  6. @Configurable
  7. @Component
  8. public class WebMvcConfig implements WebMvcConfigurer {
  9. @Override
  10. public void addViewControllers(ViewControllerRegistry registry) {
  11. // 配置视图转发
  12. registry.addViewController("/ws").setViewName("/WebSockets");
  13. }
  14. }

九 效果图

即一个浏览器发送消息,其它连接的浏览器也能收到消息,即广播形式;

十参考文献

参考1:《JavaEE开发的颠覆者》

参考2: spring-web

源码: youku1327

springboot-集成WebSockets广播消息的更多相关文章

  1. springboot集成redis实现消息发布订阅模式-双通道(跨多服务器)

    基础配置参考https://blog.csdn.net/llll234/article/details/80966952 查看了基础配置那么会遇到一下几个问题: 1.实际应用中可能会订阅多个通道,而一 ...

  2. springboot集成swagger添加消息头(header请求头信息)

    springboot集成swagger上篇文章介绍: https://blog.csdn.net/qiaorui_/article/details/80435488 添加头信息: package co ...

  3. SpringBoot 集成Apache Kafak 消息队列

    Kafka is a distributed,partitioned,replicated commit logservice.它提供了类似于JMS的特性,但是在实现上完全不同,此外它并不是JMS规范 ...

  4. SpringBoot集成rabbitmq(二)

    前言 在使用rabbitmq时,我们可以通过消息持久化来解决服务器因异常崩溃而造成的消息丢失.除此之外,我们还会遇到一个问题,当消息生产者发消息发送出去后,消息到底有没有正确到达服务器呢?如果不进行特 ...

  5. spring boot 集成 websocket 实现消息主动推送

    spring boot 集成 websocket 实现消息主动 前言 http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单 ...

  6. SpringBoot集成Kafka的实战用法大全

    本文是SpringBoot+Kafka的实战讲解,如果对kafka的架构原理还不了解的读者,建议先看一下<大白话kafka架构原理>.<秒懂kafka HA(高可用)>两篇文章 ...

  7. SpringBoot集成RabbitMQ消息队列搭建与ACK消息确认入门

    1.RabbitMQ介绍 RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面表现不俗.Rabbi ...

  8. SpringBoot集成WebSocket【基于纯H5】进行点对点[一对一]和广播[一对多]实时推送

    代码全部复制,仅供自己学习用 1.环境搭建 因为在上一篇基于STOMP协议实现的WebSocket里已经有大概介绍过Web的基本情况了,所以在这篇就不多说了,我们直接进入正题吧,在SpringBoot ...

  9. springboot集成websocket实现向前端浏览器发送一个对象,发送消息操作手动触发

    工作中有这样一个需示,我们把项目中用到代码缓存到前端浏览器IndexedDB里面,当系统管理员在后台对代码进行变动操作时我们要更新前端缓存中的代码怎么做开始用想用版本方式来处理,但这样的话每次使用代码 ...

随机推荐

  1. maven 发布到本地仓库

    1.maven打包命令 maven package命令只是将你需要打包的项目打包到项目的class文件夹下面,并没有发布到本地仓库或者私服上面,现在多模块开发的打包一般依赖私服或者 本地仓库,因此,我 ...

  2. Navicat连接MySQL8.0版本时 建议升级连接客户端这个提示怎么办

    开始->mysql 8.0 command line client ->执行下面的命令//开启mysql服务mysql.server start//进入mysqlmysql -u root ...

  3. 是时候了解React Native了

    文章首发于简书,欢迎关注 随着科技的发展,手机开发也在向好的方向不停的转变.IOS和Android两大手机操作横空出世,称霸江湖.我们每开发一个手机软件最少都需要开发这两个终端. 两大操作系统都在不断 ...

  4. 使用epoll实现简单的服务器

    1. 头文件 #ifndef __TCP_SERVER_H__ #define __TCP_SERVER_H__ #include <unistd.h> #include <stdi ...

  5. 亿级消息系统的核心存储:Tablestore发布Timeline 2.0模型

    背景 互联网快速发展的今天,社交类应用.消息类功能大行其道,占据了大量网络流量.大至钉钉.微信.微博.知乎,小至各类App的推送通知,消息类功能几乎成为所有应用的标配.根据场景特点,我们可以将消息类场 ...

  6. @NOI模拟2017.06.30 - T3@ Right

    目录 @description@ @solution@ @part - 1@ @part - 2@ @accepted code@ @details@ @description@ JOHNKRAM 和 ...

  7. 2015,2016 Open Source Yearbook

    https://opensource.com/yearbook/2015 The 2015 Open Source Yearbook is a community-contributed collec ...

  8. PHP导入导出Excel方法小结

    基本上导出的文件分为两种: 1:类Excel格式,这个其实不是传统意义上的Excel文件,只是因为Excel的兼容能力强,能够正确打开而已.修改这种文件后再保存,通常会提示你是否要转换成Excel文件 ...

  9. Android Animation动画详解(一): 补间动画

    前言 你有没有被一些APP中惊艳的动画效果震撼过,有没有去思考,甚至研究过这些动画是如何实现的呢? 啥?你没有思考,更没有研究过? 好吧,那跟着我一起来学习下如何去实现APP中那些让我们惊羡的动画特效 ...

  10. idea各种中文显示乱码解决大全

    本文链接:https://blog.csdn.net/liqimo1799/article/details/81811153中文乱码问题分类: 编码普通中文乱码properties文件中文乱码cons ...